<commit_before># -*- coding: utf-8 -*-
#
# vim: expandtab shiftwidth=4 softtabstop=4
#

import datetime
import time
import urllib
import urlparse
import requests
import xml.etree.ElementTree as ET
import os

class PublicShare():
    def __init__(self, share_id, target_file, link, token):
        self.share_id = share_id
        self.target_file = target_file
        self.link = link
        self.token = token

    def __str__(self):
        return 'PublicShare(id=%i,path=%s,link=%s,token=%s)' % (self.share_id, self.target_file, self.link, self.token)

class File():
    __DATE_FORMAT = '%a, %d %b %Y %H:%M:%S %Z'

    def __init__(self, path, file_type = 'file', attributes = {}):
        self.path = path
        self.file_type = file_type
        self.attributes = attributes

    def getSize(self):
        return int(self.attributes['{DAV:}getcontentlength'])

    def getETag(self):
        return self.attributes['{DAV:}getetag']

    def getContentType(self):
        return self.attributes['{DAV:}getcontenttype']

    def getLastModified(self):
        return datetime.datetime.strptime(self.attributes['{DAV:}getlastmodified'], self.__DATE_FORMAT)

    def __str__(self):
        return 'File(path=%s,file_type=%s,attributes=%s)' % (self.path, self.file_type, self.attributes)

    def __repr__(self):
        return self.__str__()

class Client():
    __DEBUG = True

    def __init__(self, url):
        if not url[-1] == '/':
            url = url + '/'

        self.url = url
        self.__auth = None

        url_components = urlparse.urlparse(url)
        self.__davpath = url_components.path + 'remote.php/webdav'
        self.__webdav_url = url + 'remote.php/webdav'
        self.__ocs_share_url = url + 'ocs/v1.php/apps/files_sharing/api/v1/'

    def login(self, user_id, password):
        self.__auth = (user_id, password)
        res = requests.get(self.url, auth = self.__auth)
        if res.status_code == 200:
            self.authenticated = True
            return True
        self.authenticated = False
        return False

    def logout(self):
        # TODO
        pass

    def fileinfo(self, path):
        return self.__makeDAVRequest('PROPFIND', path)

    def get(self, path):
        path = self.__normalizePath(path)
        res = requests.get(self.__webdav_url + path, auth = self.__auth)
        if res.status_code == 200:
            return res.content
        return False

    def getToFile(self, path, target_file = None):
        path = self.__normalizePath(path)
        res = requests.get(self.__webdav_url + path, auth = self.__auth, stream = True)
        if res.status_code == 200:
            if target_file == None:
                # use downloaded file name from Content-Disposition
                # targetFile = res.headers['content-disposition']
                target_file = os.path.basename(path)

            f = open(target_file, 'w', 8192)
            for chunk in res.iter_content(8192):
                f.write(chunk)
            f.close()
            return True
        return False

    def getDirectoryAsZip(self, path, target_file):
        path = self.__normalizePath(path)
        res = requests.get(self.url + 'index.php/apps/files/ajax/download.php?dir=' + urllib.quote(path), auth = self.__auth, stream = True)
        if res.status_code == 200:
            if target_file == None:
                # use downloaded file name from Content-Disposition
                # targetFile = res.headers['content-disposition']
                target_file = os.path.basename(path)

            f = open(target_file, 'w', 8192)
            for chunk in res.iter_content(8192):
                f.write(chunk)
            f.close()
            return True
        return False

    def putFromString(self, target_path, data):
        return self.__makeDAVRequest('PUT', target_path, {'data': data})

    def putFromFile(self, target_path, local_source_file, **kwargs):
        if kwargs.get('chunked', True):
            return self.__putFromFileChunked(target_path, local_source_file, **kwargs)

        stat_result = os.stat(local_source_file)

        headers = {}
        if kwargs.get('keep_mtime', True):
            headers['X-OC-MTIME'] = stat_result.st_mtime

        if target_path[-1] == '/':
            target_path += os.path.basename(local_source_file)
        f = open(local_source_file, 'r', 8192)
        res = self.__makeDAVRequest('PUT', target_path, {'data': f, 'headers': headers})
        f.close()
        return res

    def putDirectory(self, target_path, local_directory, **kwargs):
        target_path = self.__normalizePath(target_path)
        if not target_path[-1] == '/':
            target_path += '/'
        gathered_files = []
        # gather files to upload
        for path, dirs, files in os.walk(local_directory):
            gathered_files.append((path, files))

        for path, files in gathered_files:
            self.mkdir(target_path + path + '/')
            for name in files:
                self.putFromFile(target_path + path + '/', path + '/' + name, **kwargs)

    def __putFromFileChunked(self, target_path, local_source_file, **kwargs):
        chunk_size = kwargs.get('chunk_size', 10 * 1024 * 1024)
        result = True
        transfer_id = int(time.time())

        target_path = self.__normalizePath(target_path)
        if target_path[-1] == '/':
            target_path += os.path.basename(local_source_file)
        # TODO: empty file should still work
        stat_result = os.stat(local_source_file)

        f = open(local_source_file, 'r', 8192)
        f.seek(0, os.SEEK_END)
        size = f.tell()
        f.seek(0)

        headers = {}
        if kwargs.get('keep_mtime', True):
            headers['X-OC-MTIME'] = stat_result.st_mtime

        if size == 0:
            return self.__makeDAVRequest('PUT', target_path, {'data': '', 'headers': headers})

        chunk_count = size / chunk_size

        if chunk_count > 1:
            headers['OC-CHUNKED'] = 1

        if size % chunk_size > 0:
            chunk_count += 1

        for chunk_index in range(0, chunk_count):
            data = f.read(chunk_size)
            if chunk_count > 1:
                chunk_name = '%s-chunking-%s-%i-%i' % (target_path, transfer_id, chunk_count, chunk_index)
            else:
                chunk_name = target_path

            if not self.__makeDAVRequest('PUT', chunk_name, {'data': data, 'headers': headers}):
                result = False
                break

        f.close()
        return result

    def mkdir(self, path):
        if not path[-1] == '/':
            path = path + '/'
        return self.__makeDAVRequest('MKCOL', path)

    def delete(self, path):
        return self.__makeDAVRequest('DELETE', path)

    def shareFileWithLink(self, path):
        path = self.__normalizePath(path)
        post_data = {'shareType': 3, 'path': path}

        res = requests.post(self.__ocs_share_url + 'shares', auth = self.__auth, data = post_data)
        if res.status_code == 200:
            tree = ET.fromstring(res.text)
            data_el = tree.find('data')
            return PublicShare(
                int(data_el.find('id').text),
                path,
                data_el.find('url').text,
                data_el.find('token').text
            )
        return False

    @staticmethod
    def __normalizePath(path):
        if isinstance(path, File):
            path = path.path
        if len(path) == 0:
            return '/'
        if path[0] != '/':
            path = '/' + path
        return path

    def __makeDAVRequest(self, method, path, attributes = {}):
        if self.__DEBUG:
            print 'DAV request: %s %s' % (method, path)

        path = self.__normalizePath(path)
        attributes = attributes.copy()
        attributes['auth'] = self.__auth
        res = requests.request(method, self.__webdav_url + path, **attributes)
        if self.__DEBUG:
            print 'DAV status: %i' % res.status_code
        if res.status_code == 200 or res.status_code == 207:
            return self.__parseDAVResponse(res)
        if res.status_code == 204 or res.status_code == 201:
            return True
        return False

    def __parseDAVResponse(self, res):
        if res.status_code == 207:
            tree = ET.fromstring(res.text)
            items = []
            for child in tree:
                items.append(self.__parseDAVElement(child))
            return items
        return True

    def __parseDAVElement(self, el):
        href = urllib.unquote(self.__stripDAVPath(el.find('{DAV:}href').text))
        is_collection = el.find('{DAV:}collection')
        if is_collection:
            file_type = 'dir'
        else:
            file_type = 'file'

        file_attrs = {}
        attrs = el.find('{DAV:}propstat')
        attrs = attrs.find('{DAV:}prop')
        for attr in attrs:
            file_attrs[attr.tag] = attr.text

        return File(href, file_type, file_attrs)

    def __stripDAVPath(self, path):
        if (path.startswith(self.__davpath)):
            return path[len(self.__davpath):]
        return path

<commit_msg>Added privatedata API calls<commit_after># -*- coding: utf-8 -*-
#
# vim: expandtab shiftwidth=4 softtabstop=4
#

import datetime
import time
import urllib
import urlparse
import requests
import xml.etree.ElementTree as ET
import os

class PublicShare():
    def __init__(self, share_id, target_file, link, token):
        self.share_id = share_id
        self.target_file = target_file
        self.link = link
        self.token = token

    def __str__(self):
        return 'PublicShare(id=%i,path=%s,link=%s,token=%s)' % (self.share_id, self.target_file, self.link, self.token)

class File():
    __DATE_FORMAT = '%a, %d %b %Y %H:%M:%S %Z'

    def __init__(self, path, file_type = 'file', attributes = {}):
        self.path = path
        self.file_type = file_type
        self.attributes = attributes

    def getSize(self):
        return int(self.attributes['{DAV:}getcontentlength'])

    def getETag(self):
        return self.attributes['{DAV:}getetag']

    def getContentType(self):
        return self.attributes['{DAV:}getcontenttype']

    def getLastModified(self):
        return datetime.datetime.strptime(self.attributes['{DAV:}getlastmodified'], self.__DATE_FORMAT)

    def __str__(self):
        return 'File(path=%s,file_type=%s,attributes=%s)' % (self.path, self.file_type, self.attributes)

    def __repr__(self):
        return self.__str__()

class Client():
    __DEBUG = True

    def __init__(self, url):
        if not url[-1] == '/':
            url = url + '/'

        self.url = url
        self.__auth = None

        url_components = urlparse.urlparse(url)
        self.__davpath = url_components.path + 'remote.php/webdav'
        self.__webdav_url = url + 'remote.php/webdav'
        self.__ocs_share_url = url + 'ocs/v1.php/apps/files_sharing/api/v1/'

    def login(self, user_id, password):
        self.__auth = (user_id, password)
        res = requests.get(self.url, auth = self.__auth)
        if res.status_code == 200:
            self.authenticated = True
            return True
        self.authenticated = False
        return False

    def logout(self):
        # TODO
        pass

    def fileinfo(self, path):
        return self.__makeDAVRequest('PROPFIND', path)

    def get(self, path):
        path = self.__normalizePath(path)
        res = requests.get(self.__webdav_url + path, auth = self.__auth)
        if res.status_code == 200:
            return res.content
        return False

    def getToFile(self, path, target_file = None):
        path = self.__normalizePath(path)
        res = requests.get(self.__webdav_url + path, auth = self.__auth, stream = True)
        if res.status_code == 200:
            if target_file == None:
                # use downloaded file name from Content-Disposition
                # targetFile = res.headers['content-disposition']
                target_file = os.path.basename(path)

            f = open(target_file, 'w', 8192)
            for chunk in res.iter_content(8192):
                f.write(chunk)
            f.close()
            return True
        return False

    def getDirectoryAsZip(self, path, target_file):
        path = self.__normalizePath(path)
        res = requests.get(self.url + 'index.php/apps/files/ajax/download.php?dir=' + urllib.quote(path), auth = self.__auth, stream = True)
        if res.status_code == 200:
            if target_file == None:
                # use downloaded file name from Content-Disposition
                # targetFile = res.headers['content-disposition']
                target_file = os.path.basename(path)

            f = open(target_file, 'w', 8192)
            for chunk in res.iter_content(8192):
                f.write(chunk)
            f.close()
            return True
        return False

    def putFromString(self, target_path, data):
        return self.__makeDAVRequest('PUT', target_path, {'data': data})

    def putFromFile(self, target_path, local_source_file, **kwargs):
        if kwargs.get('chunked', True):
            return self.__putFromFileChunked(target_path, local_source_file, **kwargs)

        stat_result = os.stat(local_source_file)

        headers = {}
        if kwargs.get('keep_mtime', True):
            headers['X-OC-MTIME'] = stat_result.st_mtime

        if target_path[-1] == '/':
            target_path += os.path.basename(local_source_file)
        f = open(local_source_file, 'r', 8192)
        res = self.__makeDAVRequest('PUT', target_path, {'data': f, 'headers': headers})
        f.close()
        return res

    def putDirectory(self, target_path, local_directory, **kwargs):
        target_path = self.__normalizePath(target_path)
        if not target_path[-1] == '/':
            target_path += '/'
        gathered_files = []
        # gather files to upload
        for path, dirs, files in os.walk(local_directory):
            gathered_files.append((path, files))

        for path, files in gathered_files:
            self.mkdir(target_path + path + '/')
            for name in files:
                self.putFromFile(target_path + path + '/', path + '/' + name, **kwargs)

    def __putFromFileChunked(self, target_path, local_source_file, **kwargs):
        chunk_size = kwargs.get('chunk_size', 10 * 1024 * 1024)
        result = True
        transfer_id = int(time.time())

        target_path = self.__normalizePath(target_path)
        if target_path[-1] == '/':
            target_path += os.path.basename(local_source_file)
        # TODO: empty file should still work
        stat_result = os.stat(local_source_file)

        f = open(local_source_file, 'r', 8192)
        f.seek(0, os.SEEK_END)
        size = f.tell()
        f.seek(0)

        headers = {}
        if kwargs.get('keep_mtime', True):
            headers['X-OC-MTIME'] = stat_result.st_mtime

        if size == 0:
            return self.__makeDAVRequest('PUT', target_path, {'data': '', 'headers': headers})

        chunk_count = size / chunk_size

        if chunk_count > 1:
            headers['OC-CHUNKED'] = 1

        if size % chunk_size > 0:
            chunk_count += 1

        for chunk_index in range(0, chunk_count):
            data = f.read(chunk_size)
            if chunk_count > 1:
                chunk_name = '%s-chunking-%s-%i-%i' % (target_path, transfer_id, chunk_count, chunk_index)
            else:
                chunk_name = target_path

            if not self.__makeDAVRequest('PUT', chunk_name, {'data': data, 'headers': headers}):
                result = False
                break

        f.close()
        return result

    def mkdir(self, path):
        if not path[-1] == '/':
            path = path + '/'
        return self.__makeDAVRequest('MKCOL', path)

    def delete(self, path):
        return self.__makeDAVRequest('DELETE', path)

    def shareFileWithLink(self, path):
        path = self.__normalizePath(path)
        post_data = {'shareType': 3, 'path': path}

        res = requests.post(self.__ocs_share_url + 'shares', auth = self.__auth, data = post_data)
        if res.status_code == 200:
            tree = ET.fromstring(res.text)
            data_el = tree.find('data')
            return PublicShare(
                int(data_el.find('id').text),
                path,
                data_el.find('url').text,
                data_el.find('token').text
            )
        return False

    def getAttribute(self, app = None, key = None):
        url = self.url + 'ocs/v1.php/privatedata/getattribute'
        if app != None:
            url += '/' + urllib.quote(app)
            if key != None:
                url += '/' + urllib.quote(key)
        res = requests.get(url, auth = self.__auth)
        if res.status_code == 200:
            tree = ET.fromstring(res.text)
            values = []
            for element in tree.find('data').iter('element'):
                app_text = element.find('app').text
                key_text = element.find('key').text
                value_text = element.find('value').text
                if key == None:
                    if app == None:
                        values.append((app_text, key_text, value_text))
                    else:
                        values.append((key_text, value_text))
                else:
                    return value_text

            return values
        return False

    def setAttribute(self, app, key, value):
        url = self.url + 'ocs/v1.php/privatedata/setattribute/' + urllib.quote(app) + '/' + urllib.quote(key)
        print url
        res = requests.post(url, auth = self.__auth, data = {'value': value})
        if res.status_code == 200:
            return True
        return False

    def deleteAttribute(self, app, key):
        url = self.url + 'ocs/v1.php/privatedata/deleteattribute/' + urllib.quote(app) + '/' + urllib.quote(key)
        print url
        res = requests.post(url, auth = self.__auth)
        if res.status_code == 200:
            return True
        return False

    @staticmethod
    def __normalizePath(path):
        if isinstance(path, File):
            path = path.path
        if len(path) == 0:
            return '/'
        if path[0] != '/':
            path = '/' + path
        return path

    def __makeDAVRequest(self, method, path, attributes = {}):
        if self.__DEBUG:
            print 'DAV request: %s %s' % (method, path)

        path = self.__normalizePath(path)
        attributes = attributes.copy()
        attributes['auth'] = self.__auth
        res = requests.request(method, self.__webdav_url + path, **attributes)
        if self.__DEBUG:
            print 'DAV status: %i' % res.status_code
        if res.status_code == 200 or res.status_code == 207:
            return self.__parseDAVResponse(res)
        if res.status_code == 204 or res.status_code == 201:
            return True
        return False

    def __parseDAVResponse(self, res):
        if res.status_code == 207:
            tree = ET.fromstring(res.text)
            items = []
            for child in tree:
                items.append(self.__parseDAVElement(child))
            return items
        return True

    def __parseDAVElement(self, el):
        href = urllib.unquote(self.__stripDAVPath(el.find('{DAV:}href').text))
        is_collection = el.find('{DAV:}collection')
        if is_collection:
            file_type = 'dir'
        else:
            file_type = 'file'

        file_attrs = {}
        attrs = el.find('{DAV:}propstat')
        attrs = attrs.find('{DAV:}prop')
        for attr in attrs:
            file_attrs[attr.tag] = attr.text

        return File(href, file_type, file_attrs)

    def __stripDAVPath(self, path):
        if (path.startswith(self.__davpath)):
            return path[len(self.__davpath):]
        return path

<|endoftext|>


<commit_before>"""
Common utilities/lib for use by multiple services
"""

subscription_types = ['policy_eval', 'tag_update', 'vuln_update', 'repo_update', 'analysis_update']
resource_types = ['registries', 'users', 'images', 'policies', 'evaluations', 'subscriptions', 'archive']
bucket_types = ["analysis_data", "policy_bundles", "policy_evaluations", "query_data", "vulnerability_scan", "image_content_data", "manifest_data"]
super_users = ['admin', 'anchore-system']
image_content_types = ['os', 'files', 'npm', 'gem', 'python', 'java']
image_metadata_types = ['manifest', 'docker_history', 'dockerfile']
image_vulnerability_types = ['os', 'non-os']
os_package_types = ['rpm', 'dpkg', 'APKG']
nonos_package_types = ('java', 'python', 'npm', 'gem', 'maven', 'js', 'composer', 'nuget')
<commit_msg>Add some package and feed group types for api handling<commit_after>"""
Common utilities/lib for use by multiple services
"""

subscription_types = ['policy_eval', 'tag_update', 'vuln_update', 'repo_update', 'analysis_update']
resource_types = ['registries', 'users', 'images', 'policies', 'evaluations', 'subscriptions', 'archive']
bucket_types = ["analysis_data", "policy_bundles", "policy_evaluations", "query_data", "vulnerability_scan", "image_content_data", "manifest_data"]
super_users = ['admin', 'anchore-system']
image_content_types = ['os', 'files', 'npm', 'gem', 'python', 'java']
image_metadata_types = ['manifest', 'docker_history', 'dockerfile']
image_vulnerability_types = ['os', 'non-os']
os_package_types = ['rpm', 'dpkg', 'apkg', 'kb']
nonos_package_types = ('java', 'python', 'npm', 'gem', 'maven', 'js', 'composer', 'nuget')
<|endoftext|>


<commit_before>__version_info__ = (1, 0, 1)
__version__ = '.'.join(map(str, __version_info__))
<commit_msg>Replace Markdown README with reStructured text<commit_after>__version_info__ = (1, 0, 2)
__version__ = '.'.join(map(str, __version_info__))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright 2018 Novo Nordisk Foundation Center for Biosustainability,
# Technical University of Denmark.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Provide an interface for growth experiments."""

from __future__ import absolute_import

import logging

from pandas import DataFrame

from memote.experimental.experiment import Experiment

__all__ = ("GrowthExperiment",)

LOGGER = logging.getLogger(__name__)

class GrowthExperiment(Experiment):
    """Represent a growth experiment."""

    SCHEMA = "growth.json"

    def __init__(self, **kwargs):
        """
        Initialize a growth experiment.

        Parameters
        ----------
        kwargs

        """
        super(GrowthExperiment, self).__init__(**kwargs)

    def load(self, dtype_conversion=None):
        """
        Load the data table and corresponding validation schema.

        Parameters
        ----------
        dtype_conversion : dict
            Column names as keys and corresponding type for loading the data.
            Please take a look at the `pandas documentation
            <https://pandas.pydata.org/pandas-docs/stable/io.html#specifying-column-data-types>`__
            for detailed explanations.

        """
        if dtype_conversion is None:
            dtype_conversion = {"growth": str}
        super(GrowthExperiment, self).load(dtype_conversion=dtype_conversion)
        self.data["growth"] = self.data["growth"].isin(self.TRUTHY)

    def evaluate(self, model):
        """Evaluate in silico growth rates."""
        with model:
            if self.medium is not None:
                self.medium.apply(model)
            if self.objective is not None:
                model.objective = self.objective
            model.add_cons_vars(self.constraints)
            growth = list()
            for row in self.data.itertuples(index=False):
                with model:
                    exchange = model.reactions.get_by_id(row.exchange)
                    if bool(exchange.reactants):
                        exchange.lower_bound = -row.uptake
                    else:
                        exchange.upper_bound = row.uptake
                    growth.append(model.slim_optimize() >= 0.002)
        return DataFrame({
            "exchange": self.data["exchange"],
            "growth": growth
        })
<commit_msg>fix: remove forgotten hardcoded value<commit_after># -*- coding: utf-8 -*-

# Copyright 2018 Novo Nordisk Foundation Center for Biosustainability,
# Technical University of Denmark.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Provide an interface for growth experiments."""

from __future__ import absolute_import

import logging

from pandas import DataFrame

from memote.experimental.experiment import Experiment

__all__ = ("GrowthExperiment",)

LOGGER = logging.getLogger(__name__)

class GrowthExperiment(Experiment):
    """Represent a growth experiment."""

    SCHEMA = "growth.json"

    def __init__(self, **kwargs):
        """
        Initialize a growth experiment.

        Parameters
        ----------
        kwargs

        """
        super(GrowthExperiment, self).__init__(**kwargs)

    def load(self, dtype_conversion=None):
        """
        Load the data table and corresponding validation schema.

        Parameters
        ----------
        dtype_conversion : dict
            Column names as keys and corresponding type for loading the data.
            Please take a look at the `pandas documentation
            <https://pandas.pydata.org/pandas-docs/stable/io.html#specifying-column-data-types>`__
            for detailed explanations.

        """
        if dtype_conversion is None:
            dtype_conversion = {"growth": str}
        super(GrowthExperiment, self).load(dtype_conversion=dtype_conversion)
        self.data["growth"] = self.data["growth"].isin(self.TRUTHY)

    def evaluate(self, model):
        """Evaluate in silico growth rates."""
        with model:
            if self.medium is not None:
                self.medium.apply(model)
            if self.objective is not None:
                model.objective = self.objective
            model.add_cons_vars(self.constraints)
            growth = list()
            for row in self.data.itertuples(index=False):
                with model:
                    exchange = model.reactions.get_by_id(row.exchange)
                    if bool(exchange.reactants):
                        exchange.lower_bound = -row.uptake
                    else:
                        exchange.upper_bound = row.uptake
                    growth.append(model.slim_optimize() >= self.min_growth)
        return DataFrame({
            "exchange": self.data["exchange"],
            "growth": growth
        })
<|endoftext|>


<commit_before># Copyright 2019 Omar Castiñeira, Comunitea Servicios Tecnológicos S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models

class ProductProduct(models.Model):

    _inherit = "product.product"

    tariff = fields.Float('Tariff', digits=(16, 2))

class ProductTemplate(models.Model):

    _inherit = "product.template"

    split_method = fields.Selection(selection_add=[('by_tariff',
                                                    'By tariff')])
<commit_msg>[FIX] pmp_landed_cost: Ahora el hs_code lleva asociado el arancel<commit_after># Copyright 2019 Omar Castiñeira, Comunitea Servicios Tecnológicos S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models

class ProductProduct(models.Model):

    _inherit = "product.product"

    tariff = fields.Float('Tariff', related="product_tmpl_id.hs_code_id.tariff" ,readonly=True)

class ProductTemplate(models.Model):

    _inherit = "product.template"

    split_method = fields.Selection(selection_add=[('by_tariff',
                                                    'By tariff')])
class HSCode(models.Model):
    _inherit = "hs.code"
    tariff = fields.Float('Tariff', digits=(16,2))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Copyright 2017 Rooms For (Hong Kong) Limited T/A OSCG
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models, _

class ProjectDateUpate(models.TransientModel):
    _name = 'project.date.update'

    @api.model
    def _default_description(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', [])
        active_model = context.get('active_model', False)
        if active_model:
            order = self.env[active_model].browse(active_ids)
            if order:
                return order.doc_title
        return ''

    start_date = fields.Date(
        string="Start Date",
        required=True,
        default=fields.Date.context_today,
    )
    end_date = fields.Date(
        string="End Date",
        required=True,
        default=fields.Date.context_today,
    )

    @api.multi
    def update_project_dates(self):
        return
<commit_msg>[IMP] add logic to update task deadlines<commit_after># -*- coding: utf-8 -*-
# Copyright 2017 Rooms For (Hong Kong) Limited T/A OSCG
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import datetime
from odoo import api, fields, models, _

class ProjectDateUpate(models.TransientModel):
    _name = 'project.date.update'

    @api.model
    def _default_description(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', [])
        active_model = context.get('active_model', False)
        if active_model:
            order = self.env[active_model].browse(active_ids)
            if order:
                return order.doc_title
        return ''

    start_date = fields.Date(
        string="Start Date",
        required=True,
        default=fields.Date.context_today,
    )
    end_date = fields.Date(
        string="End Date",
        required=True,
        default=fields.Date.context_today,
    )

    @api.multi
    def update_task_dates(self, project):
        self.ensure_one()
        for task in project.task_ids:
            task.date_deadline = fields.Date.to_string(
                fields.Date.from_string(project.date) -
                datetime.timedelta(days=task.days_project_due)
            )
        return

    @api.multi
    def update_project_dates(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', [])
        active_model = context.get('active_model', False)
        project = self.env[active_model].browse(active_ids)
        default = {
            'date_start': self.start_date,
            'date': self.end_date,
        }
        project.write(default)
        self.update_task_dates(project)
        return
<|endoftext|>


<commit_before>"""
Custom storage for django with Mosso Cloud Files backend.
Created by Rich Leland <rich@richleland.com>.
"""
import re

from django.conf import settings
from django.core.files import File
from django.core.files.storage import Storage
from django.core.exceptions import ImproperlyConfigured
from django.utils.text import get_valid_filename

try:
    import cloudfiles
    from cloudfiles.errors import NoSuchObject
except ImportError:
    raise ImproperlyConfigured, "Could not load cloudfiles dependency. See http://www.mosso.com/cloudfiles.jsp."

try:
    CLOUDFILES_USERNAME = settings.CLOUDFILES_USERNAME
    CLOUDFILES_API_KEY = settings.CLOUDFILES_API_KEY
    CLOUDFILES_CONTAINER = settings.CLOUDFILES_CONTAINER
except AttributeError:
    raise ImproperlyConfigured, "CLOUDFILES_USERNAME, CLOUDFILES_API_KEY, and CLOUDFILES_CONTAINER must be supplied in settings.py."

# TODO: implement TTL into cloudfiles methods
CLOUDFILES_TTL = getattr(settings, 'CLOUDFILES_TTL', 600)

def cloudfiles_upload_to(self, filename):
    """
    Simple, custom upload_to because Cloud Files doesn't support
    nested containers (directories).

    Actually found this out from @minter:
    @richleland The Cloud Files APIs do support pseudo-subdirectories, by
    creating zero-byte files with type application/directory.

    May implement in a future version.
    """
    return get_valid_filename(filename)

class CloudFilesStorage(Storage):
    """
    Custom storage for Mosso Cloud Files.
    """

    def __init__(self):
        """
        Here we set up the connection and select the user-supplied container.
        If the container isn't public (available on Limelight CDN), we make
        it a publicly available container.
        """
        self.connection = cloudfiles.get_connection(CLOUDFILES_USERNAME,
                                                    CLOUDFILES_API_KEY)
        self.container = self.connection.get_container(CLOUDFILES_CONTAINER)
        if not self.container.is_public():
            self.container.make_public()

    def _get_cloud_obj(self, name):
        """
        Helper function to get retrieve the requested Cloud Files Object.
        """
        return self.container.get_object(name)

    def _open(self, name, mode='rb'):
        """
        Not sure if this is the proper way to execute this. Would love input.
        """
        return File(self._get_cloud_obj(name).read())

    def _save(self, name, content):
        """
        Here we're opening the content object and saving it to the Cloud Files
        service. We have to set the content_type so it's delivered properly
        when requested via public URI.
        """
        content.open()
        if hasattr(content, 'chunks'):
            content_str = ''.join(chunk for chunk in content.chunks())
        else:
            content_str = content.read()
        cloud_obj = self.container.create_object(name)
        if hasattr(content.file, 'content_type'):
            cloud_obj.content_type = content.file.content_type
        cloud_obj.send(content_str)
        content.close()
        return name

    def delete(self, name):
        """
        Deletes the specified file from the storage system.
        """
        self.container.delete_object(name)

    def exists(self, name):
        """
        Returns True if a file referened by the given name already exists in the
        storage system, or False if the name is available for a new file.
        """
        try:
            self._get_cloud_obj(name)
            return True
        except NoSuchObject:
            return False

    def listdir(self, path):
        """
        Lists the contents of the specified path, returning a 2-tuple of lists;
        the first item being directories, the second item being files.
        """
        return ([], self.container.list_objects(path=path))

    def size(self, name):
        """
        Returns the total size, in bytes, of the file specified by name.
        """
        return self._get_cloud_obj(name).size()

    def url(self, name):
        """
        Returns an absolute URL where the file's contents can be accessed
        directly by a web browser.
        """
        return self._get_cloud_obj(name).public_uri()
<commit_msg>Pulled mosso changes from smileychris<commit_after>"""
Custom storage for django with Mosso Cloud Files backend.
Created by Rich Leland <rich@richleland.com>.
"""
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files import File
from django.core.files.storage import Storage
from django.utils.text import get_valid_filename

try:
    import cloudfiles
    from cloudfiles.errors import NoSuchObject
except ImportError:
    raise ImproperlyConfigured("Could not load cloudfiles dependency. See "
                               "http://www.mosso.com/cloudfiles.jsp.")

# TODO: implement TTL into cloudfiles methods
CLOUDFILES_TTL = getattr(settings, 'CLOUDFILES_TTL', 600)

def cloudfiles_upload_to(self, filename):
    """
    Simple, custom upload_to because Cloud Files doesn't support
    nested containers (directories).

    Actually found this out from @minter:
    @richleland The Cloud Files APIs do support pseudo-subdirectories, by
    creating zero-byte files with type application/directory.

    May implement in a future version.
    """
    return get_valid_filename(filename)

class CloudFilesStorage(Storage):
    """
    Custom storage for Mosso Cloud Files.
    """
    default_quick_listdir = True

    def __init__(self, username=None, api_key=None, container=None,
                 connection_kwargs=None):
        """
        Initialize the settings for the connection and container.
        """
        self.username = username or settings.CLOUDFILES_USERNAME
        self.api_key = api_key or settings.CLOUDFILES_API_KEY
        self.container_name = container or settings.CLOUDFILES_CONTAINER
        self.connection_kwargs = connection_kwargs or {}

    def __getstate__(self):
        """
        Return a picklable representation of the storage.
        """
        return dict(username=self.username,
                    api_key=self.api_key,
                    container_name=self.container_name,
                    connection_kwargs=self.connection_kwargs)

    def _get_connection(self):
        if not hasattr(self, '_connection'):
            self._connection = cloudfiles.get_connection(self.username,
                                    self.api_key, **self.connection_kwargs)
        return self._connection

    def _set_connection(self, value):
        self._connection = value

    connection = property(_get_connection, _set_connection)

    def _get_container(self):
        if not hasattr(self, '_container'):
            self.container = self.connection.get_container(
                                                        self.container_name)
        return self._container

    def _set_container(self, container):
        """
        Set the container, making it publicly available (on Limelight CDN) if
        it is not already.
        """
        if not container.is_public():
            container.make_public()
        if hasattr(self, '_container_public_uri'):
            delattr(self, '_container_public_uri')
        self._container = container

    container = property(_get_container, _set_container)

    def _get_container_url(self):
        if not hasattr(self, '_container_public_uri'):
            self._container_public_uri = self.container.public_uri()
        return self._container_public_uri

    container_url = property(_get_container_url)

    def _get_cloud_obj(self, name):
        """
        Helper function to get retrieve the requested Cloud Files Object.
        """
        return self.container.get_object(name)

    def _open(self, name, mode='rb'):
        """
        Return the CloudFilesStorageFile.
        """
        return CloudFilesStorageFile(storage=self, name=name)

    def _save(self, name, content):
        """
        Use the Cloud Files service to write ``content`` to a remote file
        (called ``name``).
        """
        content.open()
        cloud_obj = self.container.create_object(name)
        # If the content type is available, pass it in directly rather than
        # getting the cloud object to try to guess.
        if hasattr(content.file, 'content_type'):
            cloud_obj.content_type = content.file.content_type
        cloud_obj.send(content)
        content.close()
        return name

    def delete(self, name):
        """
        Deletes the specified file from the storage system.
        """
        self.container.delete_object(name)

    def exists(self, name):
        """
        Returns True if a file referenced by the given name already exists in
        the storage system, or False if the name is available for a new file.
        """
        try:
            self._get_cloud_obj(name)
            return True
        except NoSuchObject:
            return False

    def listdir(self, path):
        """
        Lists the contents of the specified path, returning a 2-tuple; the
        first being an empty list of directories (not available for quick-
        listing), the second being a list of filenames.

        If the list of directories is required, use the full_listdir method.
        """
        files = []
        if path and not path.endswith('/'):
            path = '%s/' % path
        path_len = len(path)
        for name in self.container.list_objects(path=path):
            files.append(name[path_len:])
        return ([], files)

    def full_listdir(self, path):
        """
        Lists the contents of the specified path, returning a 2-tuple of lists;
        the first item being directories, the second item being files.

        On large containers, this may be a slow operation for root containers
        because every single object must be returned (cloudfiles does not
        provide an explicit way of listing directories).
        """
        dirs = set()
        files = []
        if path and not path.endswith('/'):
            path = '%s/' % path
        path_len = len(path)
        for name in self.container.list_objects(prefix=path):
            name = name[path_len:]
            slash = name[1:-1].find('/') + 1
            if slash:
                dirs.add(name[:slash])
            elif name:
                files.append(name)
        dirs = list(dirs)
        dirs.sort()
        return (dirs, files)

    def size(self, name):
        """
        Returns the total size, in bytes, of the file specified by name.
        """
        return self._get_cloud_obj(name).size

    def url(self, name):
        """
        Returns an absolute URL where the file's contents can be accessed
        directly by a web browser.
        """
        return '%s/%s' % (self.container_url, name)

class CloudFilesStorageFile(File):
    closed = False

    def __init__(self, storage, name, *args, **kwargs):
        self._storage = storage
        super(CloudFilesStorageFile, self).__init__(file=None, name=name,
                                                    *args, **kwargs)

    def _get_size(self):
        if not hasattr(self, '_size'):
            self._size = self._storage.size(self.name)
        return self._size

    def _set_size(self, size):
        self._size = size

    size = property(_get_size, _set_size)

    def _get_file(self):
        if not hasattr(self, '_file'):
            self._file = self._storage._get_cloud_obj(self.name)
        return self._file

    def _set_file(self, value):
        if value is None:
            if hasattr(self, '_file'):
                del self._file
        else:
            self._file = value

    file = property(_get_file, _set_file)

    def read(self, num_bytes=None):
        data = self.file.read(size=num_bytes or -1, offset=self._pos)
        self._pos += len(data)
        return data

    def open(self, *args, **kwargs):
        """
        Open the cloud file object.
        """
        self.file
        self._pos = 0

    def close(self, *args, **kwargs):
        self._pos = 0

    @property
    def closed(self):
        return not hasattr(self, '_file')

    def seek(self, pos):
        self._pos = pos
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from subprocess import call, check_output#, run
import subprocess
import os
import time
import datetime
import argparse

import logging

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

parser = argparse.ArgumentParser()

parser.add_argument("-i", "--input", help="BAM files (can be the location on S3)", nargs='+')
parser.add_argument("-o", "--output", help="Output folder")
parser.add_argument("-l", "--log", help="Log File")
parser.add_argument("-n", "--cores", help="Number of Cores to use")
parser.add_argument("-m", "--memory", help="RAM Memory to use in GB")

args = parser.parse_args()

bam_files = args.input
output_folder = args.output

# if not os.path.exists(output_folder):
#     os.makedirs(output_folder)

print(bam_files)

n_cores = int(args.cores)
memory = int(args.memory)
log_file = args.log

bam_groups = list(chunks(bam_files,n_cores))
print(bam_groups)

# print(bam_file)

human_reference = "/home/ubuntu/projects/input/b37/human_g1k_v37.fasta" #84 features
human_reference = "/home/ubuntu/projects/input/grch37/d5/hs37d5.fa" #86 features
gtf_file = "/home/ubuntu/projects/input/gtf/Homo_sapiens.GRCh37.75.gtf"

fastqc_dir = "/home/ubuntu/projects/programs/fastqc/FastQC/"
samtools_dir = "/home/ubuntu/projects/programs/samtools-1.3.1"
bamtools_dir = "/home/ubuntu/projects/programs/bamtools/bin/bamtools"
programs_dir = "/home/ubuntu/projects/programs/"
picard_dir = "/home/ubuntu/projects/programs/picard"
gatk_dir = "/home/ubuntu/projects/programs/gatk"
qualimap_dir = "/home/ubuntu/projects/programs/qualimap/qualimap_v2.2"
featurecounts_dir = "/home/ubuntu/projects/programs/subread-1.5.1-Linux-x86_64/bin"

input_folder = '/home/ubuntu/projects/input/bam'

# print(base, base_name)

# output_folder = '/home/ubuntu/projects/output/bam/1_run' % (base_name)

logging.basicConfig(filename=log_file,level=logging.DEBUG)
# your code
start_time = datetime.datetime.now()
logging.info("Start time: "+str(start_time))
# print(base_name)
# print(bam_file)

def download_bams_from_s3():
    for bam_group in bam_groups:
        for bam_file in bam_group:
            original_bam = bam_file
            base=os.path.basename(bam_file)
            base_name = os.path.splitext(base)[0]
            if bam_file.startswith('s3://'):
                #download file to input folder
                command = "s3cmd get --continue %s %s/" % (bam_file, input_folder)
                output = check_output(command, shell=True)
                logging.info(output)
                print(output)
                # print(command)
                bam_file = "%s/%s" % (input_folder, base)

            print(bam_file)

            if not os.path.exists(bam_file+'.bai'):
                #Download index
                command = "s3cmd get --continue %s.bai %s/" % (original_bam, input_folder)
                # print(command)
                output = check_output(command, shell=True)
                logging.info(output)
                print(output)

download_bams_from_s3()

for bam_group in bam_groups:
    command = "%s/fastqc -t %s %s -o %s" % (fastqc_dir, n_cores, " ".join(bam_group), output_folder)
    print(command)
    output = check_output(command, shell=True)
    logging.info(output)
    print(output)
# os.remove(bam_file)
finish_time = datetime.datetime.now()
logging.info("Finish time: "+str(finish_time))
logging.info("Time Taken: "+str(finish_time-start_time))
<commit_msg>bam genome metrics<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from subprocess import call, check_output#, run
import subprocess
import os
import time
import datetime
import argparse

import logging

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

parser = argparse.ArgumentParser()

parser.add_argument("-i", "--input", help="BAM files (can be the location on S3)", nargs='+')
parser.add_argument("-o", "--output", help="Output folder")
parser.add_argument("-l", "--log", help="Log File")
parser.add_argument("-n", "--cores", help="Number of Cores to use")
parser.add_argument("-m", "--memory", help="RAM Memory to use in GB")

args = parser.parse_args()

bam_files = args.input
output_folder = args.output

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

print(bam_files)

n_cores = int(args.cores)
memory = int(args.memory)
log_file = args.log

bam_groups = list(chunks(bam_files,n_cores))
print(bam_groups)

# print(bam_file)

human_reference = "/home/ubuntu/projects/input/b37/human_g1k_v37.fasta" #84 features
human_reference = "/home/ubuntu/projects/input/grch37/d5/hs37d5.fa" #86 features
gtf_file = "/home/ubuntu/projects/input/gtf/Homo_sapiens.GRCh37.75.gtf"

fastqc_dir = "/home/ubuntu/projects/programs/fastqc/FastQC/"
samtools_dir = "/home/ubuntu/projects/programs/samtools-1.3.1"
bamtools_dir = "/home/ubuntu/projects/programs/bamtools/bin/bamtools"
programs_dir = "/home/ubuntu/projects/programs/"
picard_dir = "/home/ubuntu/projects/programs/picard"
gatk_dir = "/home/ubuntu/projects/programs/gatk"
qualimap_dir = "/home/ubuntu/projects/programs/qualimap/qualimap_v2.2"
featurecounts_dir = "/home/ubuntu/projects/programs/subread-1.5.1-Linux-x86_64/bin"

input_folder = '/home/ubuntu/projects/input/bam'

# print(base, base_name)

# output_folder = '/home/ubuntu/projects/output/bam/1_run' % (base_name)

logging.basicConfig(filename=log_file,level=logging.DEBUG)
# your code
start_time = datetime.datetime.now()
logging.info("Start time: "+str(start_time))
# print(base_name)
# print(bam_file)

def download_bams_from_s3():
    for bam_group in bam_groups:
        for bam_file in bam_group:
            original_bam = bam_file
            base=os.path.basename(bam_file)
            base_name = os.path.splitext(base)[0]
            if bam_file.startswith('s3://'):
                #download file to input folder
                command = "s3cmd get --continue %s %s/" % (bam_file, input_folder)
                output = check_output(command, shell=True)
                logging.info(output)
                print(output)
                # print(command)
                bam_file = "%s/%s" % (input_folder, base)

            print(bam_file)

            if not os.path.exists(bam_file+'.bai'):
                #Download index
                command = "s3cmd get --continue %s.bai %s/" % (original_bam, input_folder)
                # print(command)
                output = check_output(command, shell=True)
                logging.info(output)
                print(output)

download_bams_from_s3()

for bam_group in bam_groups:
    command = "%s/fastqc -t %s %s -o %s" % (fastqc_dir, n_cores, " ".join(bam_group), output_folder)
    print(command)
    output = check_output(command, shell=True)
    logging.info(output)
    print(output)
# os.remove(bam_file)
finish_time = datetime.datetime.now()
logging.info("Finish time: "+str(finish_time))
logging.info("Time Taken: "+str(finish_time-start_time))
<|endoftext|>


<commit_before>'''
Module to build images
'''

# third party imports
import os
import re
import sys
import docker

# barnacle imports
import barnacle
import barnacle.helper

def _get_dockerfile(b_dir):
    '''
    helper method to find dockerfiles in a directory
    '''
    files = []
    for root, dirs, d_file in os.walk(b_dir):
        if 'Dockerfile' in d_file:
            files.append(root)
    return files

def build(conf, img_os=None, all_os=False, no_cache=False):
    '''
    build docker images
    '''
    def _build_image(path, img_os, no_cache):
        try:
            for line in client.build(path=path,
                                     tag='salt-' + img_os,
                                     stream=True, nocache=no_cache):
                line = line.decode()
                if '":"' in line:
                    print(re.split('":"|}|', line)[1])
        except docker.errors.APIError as err:
            print("There was an issue building the VM: {0}".format(err))
            sys.exit(1)
    client = barnacle.helper.get_client()

    if all_os:
        for dirs in _get_dockerfile(conf.get('barnacle_dir')):
            img_os = dirs.split('/')[-1]
            _build_image(dirs, img_os, no_cache)
    else:
        _build_image(conf.get('barnacle_dir') + img_os, img_os, no_cache)

def main():
    '''
    main method for building images
    '''
    b_client = barnacle.Barnacle()
    build(b_client.opts, img_os=b_client.args.os, all_os=b_client.args.all,
          no_cache=b_client.args.no_cache)

if __name__ == "__main__":
    main()
<commit_msg>Update build.py to work with docker-py 3.0 (#44)<commit_after>'''
Module to build images
'''

# third party imports
import os
import re
import sys
import docker
from distutils.version import LooseVersion

# barnacle imports
import barnacle
import barnacle.helper

def _get_dockerfile(b_dir):
    '''
    helper method to find dockerfiles in a directory
    '''
    files = []
    for root, dirs, d_file in os.walk(b_dir):
        if 'Dockerfile' in d_file:
            files.append(root)
    return files

def build(conf, img_os=None, all_os=False, no_cache=False):
    '''
    build docker images
    '''
    def _build_image(path, img_os, no_cache):
        try:
            kwargs = {'path': path, 'tag': 'salt-' + img_os,
                      'nocache': no_cache}
            if LooseVersion(docker.version) < LooseVersion('3.0.0'):
                kwargs['stream'] = True
            for line in client.build(**kwargs):
                line = line.decode()
                if '":"' in line:
                    print(re.split('":"|}', line)[1])
        except docker.errors.APIError as err:
            print("There was an issue building the VM: {0}".format(err))
            sys.exit(1)
    client = barnacle.helper.get_client()

    if all_os:
        for dirs in _get_dockerfile(conf.get('barnacle_dir')):
            img_os = dirs.split('/')[-1]
            _build_image(dirs, img_os, no_cache)
    else:
        _build_image(conf.get('barnacle_dir') + img_os, img_os, no_cache)

def main():
    '''
    main method for building images
    '''
    b_client = barnacle.Barnacle()
    build(b_client.opts, img_os=b_client.args.os, all_os=b_client.args.all,
          no_cache=b_client.args.no_cache)

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>#!/usr/bin/python
from __future__ import division
import copy
import unittest

def round_point(point):
    return [int(point[0]), int(point[1])]

def scale_point(point, k):
    return [k[0]*point[0], k[1]*point[1]]

def shift_point(point, offset):
    return [point[0]+offset[0], point[1]+offset[1]]

def round_points(points):
    return [round_point(p) for p in points]

def scale_points(points, k):
    return [scale_point(p, k) for p in points]

def shift_points(points, offset):
    return [shift_point(p, offset) for p in points]

def get_square():
    return [[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]

def get_rectangular(w, h):
    return scale_points(get_square(), [w, h])

def get_color(text):
    t = {
        'white': '#fff',
        'black': '#000',
        'red': '#f00',
        'green': '#0f0',
        'blue': '#00f'
    }
    return t.get(text, text)

def close_points(points):
    res = points[:]
    if len(res) < 1:
        return res
    first = res[0]
    last = res[-1]
    res.append([last[0], 0])
    res.append([first[0], 0])
    res.append(first)
    return res

def tostr(point):
    return '({0}, {1})'.format(point[0], point[1])

class BoundingBox:

    def __init__(self, point=None):
        self.left_bottom = None
        self.right_top = None
        self.include(point)

    def include(self, point):
        if self.left_bottom is None or self.right_top is None:
            self.left_bottom = point[:]
            self.right_top = point[:]
            return

        self.left_bottom[0] = min(self.left_bottom[0], point[0])
        self.left_bottom[1] = min(self.left_bottom[1], point[1])
        self.right_top[0] = max(self.right_top[0], point[0])
        self.right_top[1] = max(self.right_top[1], point[1])

    def width(self):
        return self.right_top[0] - self.left_bottom[0]

    def height(self):
        return self.right_top[1] - self.left_bottom[1]

class Chart:

    def __init__(self, width=650, height=75,
                 padding_top=10, padding_bottom=20,
                 padding_left=20, padding_right=40,
                 inverseX=False,
                 xlabels=[], ylabels=[]):
        self.width = width
        self.height = height
        self.padding_top = padding_top
        self.padding_bottom = padding_bottom
        self.padding_left = padding_left
        self.padding_right = padding_right
        self.inverseX = inverseX
        self.traces = []
        self.texts = []
        self.canvas = BoundingBox([0, 0])
        self.xlabels = xlabels
        self.ylabels = ylabels
        self.is_axes_on_top = False

        # self.add_frame()  # TODO: remove
        self.add_background()
        self.add_labels()
        self.add_axes()

    def set_minimal_canvas(self, point1, point2):
        self.canvas.include(point1)
        self.canvas.include(point2)

    def add_frame(self):
        points = get_rectangular(self.width-2, self.height-2)
        points = shift_points(points, [1, 1])
        data = {}
        data['points'] = points
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#ddd'
        data['atr']['shape-rendering'] = 'crispEdges'
        self.traces.append(data)

    def add_background(self):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        points = get_rectangular(w, h)
        padding = [self.padding_left, self.padding_bottom]
        points = shift_points(points, padding)
        data = {}
        data['points'] = points
        data['atr'] = {}
        data['atr']['fill'] = get_color('white')
        self.traces.append(data)

    def add_axes(self):
        d = 3
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        padding = [self.padding_left, self.padding_bottom]

        data = {}
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#999'
        data['atr']['shape-rendering'] = 'crispEdges'

        dx0 = 1 if self.inverseX else d
        dx1 = d if self.inverseX else 0

        # X top
        data = copy.deepcopy(data)
        points = [[-dx0, h], [w+dx1, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # X bottom
        data = copy.deepcopy(data)
        points = [[-dx0, 0], [w+dx1, 0]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # Y left
        data = copy.deepcopy(data)
        points = [[0, -d], [0, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # Y right
        data = copy.deepcopy(data)
        points = [[w, -d], [w, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

    def add_labels(self):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        padding = [self.padding_left, self.padding_bottom]

        data = {}
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#ddd'
        data['atr']['shape-rendering'] = 'crispEdges'
        if self.is_axes_on_top:
            data['atr']['stroke-dasharray'] = '1, 5'

        text = {}
        text['atr'] = {}
        text['atr']['font-family'] = 'Verdana'
        text['atr']['font-size'] = 10
        text['atr']['fill'] = '#777'

        yn = len(self.ylabels)
        step = h / (yn-1)
        for i in xrange(0, yn):
            data = copy.deepcopy(data)
            y = i * step
            points = [[0, y], [w, y]]
            points = shift_points(points, padding)
            data['points'] = points
            self.traces.append(data)

            x = w+5 if self.inverseX else -5

            text = copy.deepcopy(text)
            text['text'] = self.ylabels[i]
            point = shift_point([x, y-3], padding)
            point = self.to_real_coords(point)
            text['atr']['x'] = point[0]
            text['atr']['y'] = point[1]
            text['atr']['text-anchor'] = 'start' if self.inverseX else 'end'
            self.texts.append(text)

        xn = len(self.xlabels)
        step = w / (xn-1)
        for i in xrange(0, xn):
            data = copy.deepcopy(data)
            x = i * step
            points = [[x, 0], [x, h]]
            points = shift_points(points, padding)
            data['points'] = points
            self.traces.append(data)

            text = copy.deepcopy(text)
            j = xn - i - 1 if self.inverseX else i
            text['text'] = self.xlabels[j]
            point = shift_point([x, -15], padding)
            point = self.to_real_coords(point)
            text['atr']['x'] = point[0]
            text['atr']['y'] = point[1]
            text['atr']['text-anchor'] = 'middle'
            self.texts.append(text)

    def add(self, ys, xs=None, stroke_width=1, stroke='black',
            fill='none', stroke_dash=False, drop=None):
        ny = len(ys)
        if xs is None:
            xs = range(0, ny)
        n = min(len(xs), ny)
        xs = xs[:n]
        ys = ys[:n]

        points = [[xs[i], ys[i]] for i in xrange(0, n)]

        drops = []
        if drop is not None and len(points) >= 1:
            first = points[0]
            last = points[-1]
            drops.append(first)
            drops.append([first[0], 0])
            drops.append([last[0], 0])
            drops.append(last)

        if fill != 'none':
            self.is_axes_on_top = True
            points = close_points(points)

        for p in points:
            self.canvas.include(p)

        data = {}
        data['canvas'] = points
        data['atr'] = {}
        data['atr']['fill'] = fill
        data['atr']['stroke-width'] = stroke_width
        data['atr']['stroke'] = get_color(stroke)
        if stroke_dash:
            if stroke_dash is True:
                stroke_dash = '10, 5'
            data['atr']['stroke-dasharray'] = stroke_dash
        self.traces.append(data)

        if len(drops) > 0:
            data = {}
            data['canvas'] = drops
            data['atr'] = {}
            data['atr']['fill'] = 'none'
            data['atr']['stroke-width'] = 1
            data['atr']['stroke'] = get_color(drop)
            self.traces.append(data)

    def canvas_to_points(self, canvas):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom

        xk = w
        yk = h
        if self.canvas.width():
            xk /= self.canvas.width()
        if self.canvas.height():
            yk /= self.canvas.height()

        if self.inverseX:
            canvas = shift_points(canvas, [-self.canvas.width(), 0])
            canvas = scale_points(canvas, [-1, 1])
        points = scale_points(canvas, [xk, yk])
        points = round_points(points)
        padding = [self.padding_left, self.padding_bottom]
        points = shift_points(points, padding)
        return points

    def to_real_coords(self, point):
        point = shift_point(point, [0, -self.height])
        point = scale_point(point, [1, -1])
        return point

    def render_points(self, points):
        points = [self.to_real_coords(p) for p in points]

        coords = ['{0},{1}'.format(p[0], p[1]) for p in points]

        pts = ' '.join(coords)
        return '\tpoints="{0}"'.format(pts)

    def render_cirle(self, point, color='red'):
        p = self.to_real_coords(point)
        return '<circle cx="{0}" cy="{1}" r="{2}" fill="{3}"/>'.format(
            p[0], p[1], 1, color)

    def render_trace(self, trace):
        res = []
        res.append('<polyline')

        canvas = trace.get('canvas')
        if canvas:
            trace['points'] = self.canvas_to_points(canvas)

        points = trace.get('points')
        if points:
            res.append(self.render_points(points))

        atr = trace.get('atr')
        if atr:
            for a in atr:
                res.append('\t{0}=\"{1}\"'.format(a, atr[a]))

        res.append('/>')

        # for p in points:
        #     res.append(self.render_cirle(p, color))

        return res

    def render_text(self, text):
        res = []
        res.append('<text')

        atr = text.get('atr')
        if atr:
            for a in atr:
                res.append('\t{0}=\"{1}\"'.format(a, atr[a]))

        res.append('>')
        res.append(str(text['text']))
        res.append('</text>')
        return res

    def render(self):
        if self.is_axes_on_top:
            self.add_labels()
            self.add_axes()

        svg = []
        svg.append('<svg>')
        for t in self.traces:
            svg.extend(self.render_trace(t))

        for t in self.texts:
            svg.extend(self.render_text(t))
        svg.append('</svg>')
        return svg

    def render_to_svg(self, filepath):
        with open(filepath, 'w') as f:
            lines = self.render()
            for line in lines:
                f.write(line + '\n')

def main():
    xlabels = [0, 2, 4, 6, 8, 10, '12 hours']
    ylabels = ['0 %', '50 %', '100 %']
    chart = Chart(inverseX=True, xlabels=xlabels, ylabels=ylabels,
                  height=400)

    #import random
    #ys = [random.randrange(0, 100) for i in xrange(200)]
    # c90c28 dark red
    # 2e7eb3 blue
    # fa730c orange
    # 4aa635 green

    color = '#2e7eb3'
    ys = [10, 60, 60]
    xs = [10, 20, 30]
    chart.add(xs=xs, ys=ys, stroke=color, fill=color)

    color = '#4aa635'
    ys = [40, 70, 100, 98]
    xs = [30, 40, 50, 60]
    chart.add(xs=xs, ys=ys, stroke=color, fill=color)

    chart.render_to_svg('test.svg')

if __name__ == '__main__':
    main()
<commit_msg>comment debug code<commit_after>#!/usr/bin/python
from __future__ import division
import copy
import unittest

def round_point(point):
    return [int(point[0]), int(point[1])]

def scale_point(point, k):
    return [k[0]*point[0], k[1]*point[1]]

def shift_point(point, offset):
    return [point[0]+offset[0], point[1]+offset[1]]

def round_points(points):
    return [round_point(p) for p in points]

def scale_points(points, k):
    return [scale_point(p, k) for p in points]

def shift_points(points, offset):
    return [shift_point(p, offset) for p in points]

def get_square():
    return [[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]

def get_rectangular(w, h):
    return scale_points(get_square(), [w, h])

def get_color(text):
    t = {
        'white': '#fff',
        'black': '#000',
        'red': '#f00',
        'green': '#0f0',
        'blue': '#00f'
    }
    return t.get(text, text)

def close_points(points):
    res = points[:]
    if len(res) < 1:
        return res
    first = res[0]
    last = res[-1]
    res.append([last[0], 0])
    res.append([first[0], 0])
    res.append(first)
    return res

def tostr(point):
    return '({0}, {1})'.format(point[0], point[1])

class BoundingBox:

    def __init__(self, point=None):
        self.left_bottom = None
        self.right_top = None
        self.include(point)

    def include(self, point):
        if self.left_bottom is None or self.right_top is None:
            self.left_bottom = point[:]
            self.right_top = point[:]
            return

        self.left_bottom[0] = min(self.left_bottom[0], point[0])
        self.left_bottom[1] = min(self.left_bottom[1], point[1])
        self.right_top[0] = max(self.right_top[0], point[0])
        self.right_top[1] = max(self.right_top[1], point[1])

    def width(self):
        return self.right_top[0] - self.left_bottom[0]

    def height(self):
        return self.right_top[1] - self.left_bottom[1]

class Chart:

    def __init__(self, width=650, height=75,
                 padding_top=10, padding_bottom=20,
                 padding_left=20, padding_right=40,
                 inverseX=False,
                 xlabels=[], ylabels=[]):
        self.width = width
        self.height = height
        self.padding_top = padding_top
        self.padding_bottom = padding_bottom
        self.padding_left = padding_left
        self.padding_right = padding_right
        self.inverseX = inverseX
        self.traces = []
        self.texts = []
        self.canvas = BoundingBox([0, 0])
        self.xlabels = xlabels
        self.ylabels = ylabels
        self.is_axes_on_top = False

        # self.add_frame()  # TODO: remove
        self.add_background()
        self.add_labels()
        self.add_axes()

    def set_minimal_canvas(self, point1, point2):
        self.canvas.include(point1)
        self.canvas.include(point2)

    def add_frame(self):
        points = get_rectangular(self.width-2, self.height-2)
        points = shift_points(points, [1, 1])
        data = {}
        data['points'] = points
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#ddd'
        data['atr']['shape-rendering'] = 'crispEdges'
        self.traces.append(data)

    def add_background(self):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        points = get_rectangular(w, h)
        padding = [self.padding_left, self.padding_bottom]
        points = shift_points(points, padding)
        data = {}
        data['points'] = points
        data['atr'] = {}
        data['atr']['fill'] = get_color('white')
        self.traces.append(data)

    def add_axes(self):
        d = 3
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        padding = [self.padding_left, self.padding_bottom]

        data = {}
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#999'
        data['atr']['shape-rendering'] = 'crispEdges'

        dx0 = 1 if self.inverseX else d
        dx1 = d if self.inverseX else 0

        # X top
        data = copy.deepcopy(data)
        points = [[-dx0, h], [w+dx1, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # X bottom
        data = copy.deepcopy(data)
        points = [[-dx0, 0], [w+dx1, 0]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # Y left
        data = copy.deepcopy(data)
        points = [[0, -d], [0, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

        # Y right
        data = copy.deepcopy(data)
        points = [[w, -d], [w, h]]
        points = shift_points(points, padding)
        data['points'] = points
        self.traces.append(data)

    def add_labels(self):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom
        padding = [self.padding_left, self.padding_bottom]

        data = {}
        data['atr'] = {}
        data['atr']['fill'] = 'none'
        data['atr']['stroke-width'] = 1
        data['atr']['stroke'] = '#ddd'
        data['atr']['shape-rendering'] = 'crispEdges'
        if self.is_axes_on_top:
            data['atr']['stroke-dasharray'] = '1, 5'

        text = {}
        text['atr'] = {}
        text['atr']['font-family'] = 'Verdana'
        text['atr']['font-size'] = 10
        text['atr']['fill'] = '#777'

        yn = len(self.ylabels)
        step = h / (yn-1)
        for i in xrange(0, yn):
            data = copy.deepcopy(data)
            y = i * step
            points = [[0, y], [w, y]]
            points = shift_points(points, padding)
            data['points'] = points
            self.traces.append(data)

            x = w+5 if self.inverseX else -5

            text = copy.deepcopy(text)
            text['text'] = self.ylabels[i]
            point = shift_point([x, y-3], padding)
            point = self.to_real_coords(point)
            text['atr']['x'] = point[0]
            text['atr']['y'] = point[1]
            text['atr']['text-anchor'] = 'start' if self.inverseX else 'end'
            self.texts.append(text)

        xn = len(self.xlabels)
        step = w / (xn-1)
        for i in xrange(0, xn):
            data = copy.deepcopy(data)
            x = i * step
            points = [[x, 0], [x, h]]
            points = shift_points(points, padding)
            data['points'] = points
            self.traces.append(data)

            text = copy.deepcopy(text)
            j = xn - i - 1 if self.inverseX else i
            text['text'] = self.xlabels[j]
            point = shift_point([x, -15], padding)
            point = self.to_real_coords(point)
            text['atr']['x'] = point[0]
            text['atr']['y'] = point[1]
            text['atr']['text-anchor'] = 'middle'
            self.texts.append(text)

    def add(self, ys, xs=None, stroke_width=1, stroke='black',
            fill='none', stroke_dash=False, drop=None):
        ny = len(ys)
        if xs is None:
            xs = range(0, ny)
        n = min(len(xs), ny)
        xs = xs[:n]
        ys = ys[:n]

        points = [[xs[i], ys[i]] for i in xrange(0, n)]

        drops = []
        if drop is not None and len(points) >= 1:
            first = points[0]
            last = points[-1]
            drops.append(first)
            drops.append([first[0], 0])
            drops.append([last[0], 0])
            drops.append(last)

        if fill != 'none':
            self.is_axes_on_top = True
            points = close_points(points)

        for p in points:
            self.canvas.include(p)

        data = {}
        data['canvas'] = points
        data['atr'] = {}
        data['atr']['fill'] = fill
        data['atr']['stroke-width'] = stroke_width
        data['atr']['stroke'] = get_color(stroke)
        if stroke_dash:
            if stroke_dash is True:
                stroke_dash = '10, 5'
            data['atr']['stroke-dasharray'] = stroke_dash
        self.traces.append(data)

        if len(drops) > 0:
            data = {}
            data['canvas'] = drops
            data['atr'] = {}
            data['atr']['fill'] = 'none'
            data['atr']['stroke-width'] = 1
            data['atr']['stroke'] = get_color(drop)
            self.traces.append(data)

    def canvas_to_points(self, canvas):
        w = self.width - self.padding_left - self.padding_right
        h = self.height - self.padding_top - self.padding_bottom

        xk = w
        yk = h
        if self.canvas.width():
            xk /= self.canvas.width()
        if self.canvas.height():
            yk /= self.canvas.height()

        if self.inverseX:
            canvas = shift_points(canvas, [-self.canvas.width(), 0])
            canvas = scale_points(canvas, [-1, 1])
        points = scale_points(canvas, [xk, yk])
        points = round_points(points)
        padding = [self.padding_left, self.padding_bottom]
        points = shift_points(points, padding)
        return points

    def to_real_coords(self, point):
        point = shift_point(point, [0, -self.height])
        point = scale_point(point, [1, -1])
        return point

    def render_points(self, points):
        points = [self.to_real_coords(p) for p in points]

        coords = ['{0},{1}'.format(p[0], p[1]) for p in points]

        pts = ' '.join(coords)
        return '\tpoints="{0}"'.format(pts)

    def render_cirle(self, point, color='red'):
        p = self.to_real_coords(point)
        return '<circle cx="{0}" cy="{1}" r="{2}" fill="{3}"/>'.format(
            p[0], p[1], 1, color)

    def render_trace(self, trace):
        res = []
        res.append('<polyline')

        canvas = trace.get('canvas')
        if canvas:
            trace['points'] = self.canvas_to_points(canvas)

        points = trace.get('points')
        if points:
            res.append(self.render_points(points))

        atr = trace.get('atr')
        if atr:
            for a in atr:
                res.append('\t{0}=\"{1}\"'.format(a, atr[a]))

        res.append('/>')

        # for p in points:
        #     res.append(self.render_cirle(p, color))

        return res

    def render_text(self, text):
        res = []
        res.append('<text')

        atr = text.get('atr')
        if atr:
            for a in atr:
                res.append('\t{0}=\"{1}\"'.format(a, atr[a]))

        res.append('>')
        res.append(str(text['text']))
        res.append('</text>')
        return res

    def render(self):
        if self.is_axes_on_top:
            self.add_labels()
            self.add_axes()

        svg = []
        svg.append('<svg>')
        for t in self.traces:
            svg.extend(self.render_trace(t))

        for t in self.texts:
            svg.extend(self.render_text(t))
        svg.append('</svg>')
        return svg

    def render_to_svg(self, filepath):
        with open(filepath, 'w') as f:
            lines = self.render()
            for line in lines:
                f.write(line + '\n')

# def main():
#     xlabels = [0, 2, 4, 6, 8, 10, '12 hours']
#     ylabels = ['0 %', '50 %', '100 %']
#     chart = Chart(inverseX=True, xlabels=xlabels, ylabels=ylabels,
#                   height=400)

#     #import random
#     #ys = [random.randrange(0, 100) for i in xrange(200)]
#     # c90c28 dark red
#     # 2e7eb3 blue
#     # fa730c orange
#     # 4aa635 green

#     color = '#2e7eb3'
#     ys = [10, 60, 60]
#     xs = [10, 20, 30]
#     chart.add(xs=xs, ys=ys, stroke=color, fill=color)

#     color = '#4aa635'
#     ys = [40, 70, 100, 98]
#     xs = [30, 40, 50, 60]
#     chart.add(xs=xs, ys=ys, stroke=color, fill=color)

#     chart.render_to_svg('test.svg')

# if __name__ == '__main__':
#     main()
<|endoftext|>


<commit_before>import sys

sys.path.append('../')

import unittest
from bayesian import Bayes, classify

class TestBayes(unittest.TestCase):
    def test_empty_constructor(self):
        with self.assertRaises(ValueError):
            b = Bayes()

    def test_list_constructor(self):
        self.assertEqual(Bayes([]), [])
        self.assertEqual(Bayes(()), [])
        self.assertEqual(Bayes(range(5)), [0, 1, 2, 3, 4])
        self.assertEqual(Bayes({'a': 10, 'b': 50}), [10, 50])
        self.assertEqual(Bayes([10, 10, 20]), [10, 10, 20])
        self.assertEqual(Bayes([('a', 10), ('b', 50)]), [10, 50])
        with self.assertRaises(ValueError):
            b = Bayes([('a', 10), ('b', 50), ('a', 15)])

    def test_get_odds(self):
        b = Bayes({'a': 10, 'b': 50})
        self.assertEqual(b['a'],   10)
        self.assertEqual(b['b'],   50)
        self.assertEqual(b[0], 10)
        self.assertEqual(b[1], 50)

        with self.assertRaises(IndexError):
            b[2]

        with self.assertRaises(ValueError):
            b['c']

    def test_set_odds(self):
        b = Bayes((10, 20, 30))
        b[0] = 50
        b[1] = 40
        b[2] = 30
        self.assertEqual(b, [50, 40, 30])

    def test_opposite(self):
        b = Bayes([0.2, 0.8])
        opposite = b.opposite()
        self.assertEqual(opposite[0] / opposite[1], b[1] / b[0])

        b = Bayes([0.2, 0.4, 0.4])
        opposite = b.opposite()
        self.assertEqual(opposite[0] / opposite[1], b[1] / b[0])
        self.assertEqual(opposite[1] / opposite[2], b[2] / b[1])
        self.assertEqual(opposite[0] / opposite[2], b[2] / b[0])

    def test_normalized(self):
        self.assertEqual(Bayes([]).normalized(), [])
        self.assertEqual(Bayes([2]).normalized(), [1])
        self.assertEqual(Bayes([9, 1]).normalized(), [0.9, 0.1])
        self.assertEqual(Bayes([2, 4, 4]).normalized(), [0.2, 0.4, 0.4])
        self.assertEqual(Bayes([2, 0]).normalized(), [1.0, 0])
        with self.assertRaises(ZeroDivisionError):
            self.assertEqual(Bayes([0, 0]).normalized(), [1.0, 0])

    def test_operators(self):
        b = Bayes([5, 2, 3])
        b *= (2, 2, 1)
        b /= (2, 2, 1)
        self.assertEqual(b, [5, 2, 3])

        self.assertEqual(Bayes([.5, .5]) * (.9, .1), [0.45, 0.05])
        self.assertEqual(Bayes([.5, .5]) / (.9, .1), [5 / 9, 5])

        self.assertEqual(Bayes([.5, .5]) * {'0': 0.9, '1': 0.1}, [0.45, 0.05])
        self.assertEqual(Bayes([.5, .5]) * [('0', 0.9), ('1', 0.1)], [0.45, 0.05])

    def test_equality(self):
        b1 = Bayes([0.5, 0.2, 0.3])
        b2 = Bayes([5, 2, 3])
        b3 = Bayes([5, 2, 5])
        self.assertEqual(b1, b2)
        self.assertNotEqual(b1, b3)
        self.assertNotEqual(b2, b3)

    def test_update(self):
        b = Bayes([1, 2])
        b.update((2, 1))
        self.assertEqual(b, [1, 1])
        b.update((2, 1))
        self.assertEqual(b, [2, 1])
        b.update((2, 0))
        self.assertEqual(b, [1, 0])

    def test_update_from_events(self):
        b = Bayes([1, 1])
        b.update_from_events(['a', 'a', 'a'], {'a': (0.5, 2)})
        self.assertEqual(b, [0.5 ** 3, 2 ** 3])

    def test_update_from_tests(self):
        b = Bayes([1, 1])
        b.update_from_tests([True], [0.9, 0.1])
        self.assertEqual(b, [0.45, 0.05])

        b = Bayes([1, 1])
        b.update_from_tests([True, True, True, False], [0.5, 2])
        self.assertEqual(b, [0.5 ** 2, 2 ** 2])

    def test_most_likely(self):
        b = Bayes({'a': 9, 'b': 1})
        self.assertEqual(b.most_likely(), 'a')
        self.assertEqual(b.most_likely(0), 'a')
        self.assertEqual(b.most_likely(0.89), 'a')
        self.assertIsNone(b.most_likely(0.91))

    def test_is_likely(self):
        b = Bayes({'a': 9, 'b': 1})
        self.assertTrue(b.is_likely('a'))
        self.assertTrue(b.is_likely('a', 0.89))
        self.assertFalse(b.is_likely('a', 0.91))

    def test_conversions(self):
        b = Bayes({'a': 9, 'b': 1, 'c': 0})
        self.assertEqual(b, b.normalized())
        self.assertEqual(b.normalized()['a'], 0.9)
        self.assertEqual(b.opposite().opposite(), b)

    def test_extract_events_odds(self):
        instances = {'spam': ["buy viagra", "buy cialis"] * 100 + ["meeting love"],
                     'genuine': ["meeting tomorrow", "buy milk"] * 100}
        odds = Bayes.extract_events_odds(instances)

        b = Bayes({'spam': 0.9, 'genuine': 0.1})
        b.update_from_events('buy coffee for meeting'.split(), odds)
        self.assertEqual(b.most_likely(0.8), 'genuine')

class TestClassify(unittest.TestCase):
    def test_single(self):
        self.assertEqual(classify('a', {'A': []}), 'A')
        self.assertEqual(classify('a', {'A': ['a']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'a']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'b']}), 'A')

    def test_basic(self):
        self.assertEqual(classify('a', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a a', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a b', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a b', {'A': ['a', 'a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a b b', {'A': ['a', 'a'], 'B': ['b']}), 'B')
        self.assertEqual(classify('b b b', {'A': ['a', 'a'], 'B': ['b']}), 'B')

    def test_with_extraction(self):
        self.assertEqual(classify('a', {'A': ['a a a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'a'], 'B': ['b b b']}), 'A')

    def test_sample(self):
        spams = ["buy viagra", "dear recipient", "meet sexy singles"]
        genuines = ["let's meet tomorrow", "remember to buy milk"]
        message = "remember the meeting tomorrow"
        instances = {'spam': spams, 'genuine': genuines}
        self.assertEqual(classify(message, instances), 'genuine')

if __name__ == '__main__':
    unittest.main()
<commit_msg>Add test for `classify_normal`<commit_after>import sys

sys.path.append('../')

import unittest
from bayesian import Bayes, classify, classify_normal

class TestBayes(unittest.TestCase):
    def test_empty_constructor(self):
        with self.assertRaises(ValueError):
            b = Bayes()

    def test_list_constructor(self):
        self.assertEqual(Bayes([]), [])
        self.assertEqual(Bayes(()), [])
        self.assertEqual(Bayes(range(5)), [0, 1, 2, 3, 4])
        self.assertEqual(Bayes({'a': 10, 'b': 50}), [10, 50])
        self.assertEqual(Bayes([10, 10, 20]), [10, 10, 20])
        self.assertEqual(Bayes([('a', 10), ('b', 50)]), [10, 50])
        with self.assertRaises(ValueError):
            b = Bayes([('a', 10), ('b', 50), ('a', 15)])

    def test_get_odds(self):
        b = Bayes({'a': 10, 'b': 50})
        self.assertEqual(b['a'],   10)
        self.assertEqual(b['b'],   50)
        self.assertEqual(b[0], 10)
        self.assertEqual(b[1], 50)

        with self.assertRaises(IndexError):
            b[2]

        with self.assertRaises(ValueError):
            b['c']

    def test_set_odds(self):
        b = Bayes((10, 20, 30))
        b[0] = 50
        b[1] = 40
        b[2] = 30
        self.assertEqual(b, [50, 40, 30])

    def test_opposite(self):
        b = Bayes([0.2, 0.8])
        opposite = b.opposite()
        self.assertEqual(opposite[0] / opposite[1], b[1] / b[0])

        b = Bayes([0.2, 0.4, 0.4])
        opposite = b.opposite()
        self.assertEqual(opposite[0] / opposite[1], b[1] / b[0])
        self.assertEqual(opposite[1] / opposite[2], b[2] / b[1])
        self.assertEqual(opposite[0] / opposite[2], b[2] / b[0])

    def test_normalized(self):
        self.assertEqual(Bayes([]).normalized(), [])
        self.assertEqual(Bayes([2]).normalized(), [1])
        self.assertEqual(Bayes([9, 1]).normalized(), [0.9, 0.1])
        self.assertEqual(Bayes([2, 4, 4]).normalized(), [0.2, 0.4, 0.4])
        self.assertEqual(Bayes([2, 0]).normalized(), [1.0, 0])
        with self.assertRaises(ZeroDivisionError):
            self.assertEqual(Bayes([0, 0]).normalized(), [1.0, 0])

    def test_operators(self):
        b = Bayes([5, 2, 3])
        b *= (2, 2, 1)
        b /= (2, 2, 1)
        self.assertEqual(b, [5, 2, 3])

        self.assertEqual(Bayes([.5, .5]) * (.9, .1), [0.45, 0.05])
        self.assertEqual(Bayes([.5, .5]) / (.9, .1), [5 / 9, 5])

        self.assertEqual(Bayes([.5, .5]) * {'0': 0.9, '1': 0.1}, [0.45, 0.05])
        self.assertEqual(Bayes([.5, .5]) * [('0', 0.9), ('1', 0.1)], [0.45, 0.05])

    def test_equality(self):
        b1 = Bayes([0.5, 0.2, 0.3])
        b2 = Bayes([5, 2, 3])
        b3 = Bayes([5, 2, 5])
        self.assertEqual(b1, b2)
        self.assertNotEqual(b1, b3)
        self.assertNotEqual(b2, b3)

    def test_update(self):
        b = Bayes([1, 2])
        b.update((2, 1))
        self.assertEqual(b, [1, 1])
        b.update((2, 1))
        self.assertEqual(b, [2, 1])
        b.update((2, 0))
        self.assertEqual(b, [1, 0])

    def test_update_from_events(self):
        b = Bayes([1, 1])
        b.update_from_events(['a', 'a', 'a'], {'a': (0.5, 2)})
        self.assertEqual(b, [0.5 ** 3, 2 ** 3])

    def test_update_from_tests(self):
        b = Bayes([1, 1])
        b.update_from_tests([True], [0.9, 0.1])
        self.assertEqual(b, [0.45, 0.05])

        b = Bayes([1, 1])
        b.update_from_tests([True, True, True, False], [0.5, 2])
        self.assertEqual(b, [0.5 ** 2, 2 ** 2])

    def test_most_likely(self):
        b = Bayes({'a': 9, 'b': 1})
        self.assertEqual(b.most_likely(), 'a')
        self.assertEqual(b.most_likely(0), 'a')
        self.assertEqual(b.most_likely(0.89), 'a')
        self.assertIsNone(b.most_likely(0.91))

    def test_is_likely(self):
        b = Bayes({'a': 9, 'b': 1})
        self.assertTrue(b.is_likely('a'))
        self.assertTrue(b.is_likely('a', 0.89))
        self.assertFalse(b.is_likely('a', 0.91))

    def test_conversions(self):
        b = Bayes({'a': 9, 'b': 1, 'c': 0})
        self.assertEqual(b, b.normalized())
        self.assertEqual(b.normalized()['a'], 0.9)
        self.assertEqual(b.opposite().opposite(), b)

    def test_extract_events_odds(self):
        instances = {'spam': ["buy viagra", "buy cialis"] * 100 + ["meeting love"],
                     'genuine': ["meeting tomorrow", "buy milk"] * 100}
        odds = Bayes.extract_events_odds(instances)

        b = Bayes({'spam': 0.9, 'genuine': 0.1})
        b.update_from_events('buy coffee for meeting'.split(), odds)
        self.assertEqual(b.most_likely(0.8), 'genuine')

class TestClassify(unittest.TestCase):
    def test_single(self):
        self.assertEqual(classify('a', {'A': []}), 'A')
        self.assertEqual(classify('a', {'A': ['a']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'a']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'b']}), 'A')

    def test_basic(self):
        self.assertEqual(classify('a', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a a', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a b', {'A': ['a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a a b', {'A': ['a', 'a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a b b', {'A': ['a', 'a'], 'B': ['b']}), 'B')
        self.assertEqual(classify('b b b', {'A': ['a', 'a'], 'B': ['b']}), 'B')

    def test_with_extraction(self):
        self.assertEqual(classify('a', {'A': ['a a a'], 'B': ['b']}), 'A')
        self.assertEqual(classify('a', {'A': ['a', 'a'], 'B': ['b b b']}), 'A')

    def test_sample(self):
        spams = ["buy viagra", "dear recipient", "meet sexy singles"]
        genuines = ["let's meet tomorrow", "remember to buy milk"]
        message = "remember the meeting tomorrow"
        instances = {'spam': spams, 'genuine': genuines}
        self.assertEqual(classify(message, instances), 'genuine')

# Classify File and Classify Folder require too much of a test harness for now.

class TestClassifyNormal(unittest.TestCase):
    def test_single(self):
        pass

    def test_sample(self):
        instance = {'height': 6, 'weight': 130, 'foot size': 8}
        training = {'male': [{'height': 6, 'weight': 180, 'foot size': 12},
                            {'height': 5.92, 'weight': 190, 'foot size': 11},
                            {'height': 5.58, 'weight': 170, 'foot size': 12},
                            {'height': 5.92, 'weight': 165, 'foot size': 10}],
                   'female': [{'height': 5, 'weight': 100, 'foot size': 6},
                              {'height': 5.5, 'weight': 150, 'foot size': 8},
                              {'height': 5.42, 'weight': 130, 'foot size': 7},
                              {'height': 5.75, 'weight': 150, 'foot size': 9}]}
        self.assertEqual(classify_normal(instance, training), 'female')

if __name__ == '__main__':
    unittest.main()
<|endoftext|>