<commit_before>import biothings_client
import copy
from itertools import islice, chain
import logging
import re
from biothings.hub.datatransform.datatransform import DataTransform, DataTransformEdge, IDStruct, nested_lookup
from biothings.utils.loggers import get_logger
from biothings import config as btconfig

class DataTransformAPI(DataTransform):
    """
    Perform key lookup or key conversion from one key type to another using
    an API endpoint as a data source.

    This class uses biothings apis to conversion from one key type to another.
    Base classes are used with the decorator syntax shown below:

    @IDLookupMyChemInfo(input_types, output_types)
    def load_document(doc_lst):
        for d in doc_lst:
            yield d

    Lookup fields are configured in the 'lookup_fields' object, examples of which
    can be found in 'IDLookupMyGeneInfo' and 'IDLookupMyChemInfo'.

    Required Options:
    - input_types
        - 'type'
        - ('type', 'nested_source_field')
        - [('type1', 'nested.source_field1'), ('type2', 'nested.source_field2'), ...]
    - output_types:
        - 'type'
        - ['type1', 'type2']

    Additional Options:
    - skip_on_failure:  Do not include a document where key lookup fails in the results
    - skip_w_regex:  skip key lookup if the provided regex matches
    """
    batch_size = 10
    default_source = '_id'
    lookup_fields = {}

    def __init__(self, input_types, output_types, skip_on_failure=False, skip_w_regex=None):
        """
        Initialize the IDLookupAPI object.
        """
        self._generate_return_fields()
        super().__init__(input_types, output_types, skip_on_failure, skip_w_regex)

        # default value of None for client
        self.client = None

        # Keep track of one_to_many relationships
        self.one_to_many_cnt = 0

        self.logger,_ = get_logger('keylookup_api')

    def _valid_input_type(self, input_type):
        """
        Check if the input_type is valid
        :param input_type:
        :return:
        """
        if not isinstance(input_type, str):
            return False
        return input_type.lower() in self.lookup_fields.keys()

    def _valid_output_type(self, output_type):
        """
        Check if the output_type is valid
        :param output_type:
        :return:
        """
        if not isinstance(output_type, str):
            return False
        return output_type.lower() in self.lookup_fields.keys()

    def _generate_return_fields(self):
        """
        Generate the return_fields member variable from the lookup_fields dictionary.
        :return:
        """
        self.return_fields = ''
        for k in self.lookup_fields:
            for field in self._get_lookup_field(k):
                self.return_fields += field + ','
        self.logger.debug("IDLookupAPI return_fields:  {}".format(self.return_fields))

    def key_lookup_batch(self, batchiter):
        """
        Look up all keys for ids given in the batch iterator (1 block)
        :param batchiter:  1 lock of records to look up keys for
        :return:
        """

        id_lst, doc_cache = self._build_cache(batchiter)
        self.logger.info("key_lookup_batch num. id_lst items:  {}".format(len(id_lst)))
        qr = self._query_many(id_lst)
        qm_struct = self._parse_querymany(qr)
        return self._replace_keys(qm_struct, doc_cache)

    def _build_cache(self, batchiter):
        """
        Build an id list and document cache for documents read from the
        batch iterator.
        :param batchiter:  an iterator for a batch of documents.
        :return:
        """
        id_lst = []
        doc_cache = []
        for doc in batchiter:

            # handle skip logic
            if self.skip_w_regex and self.skip_w_regex.match(doc['_id']):
                pass
            else:
                for input_type in self.input_types:
                    val = DataTransformAPI._nested_lookup(doc, input_type[1])
                    if val:
                        id_lst.append('"{}"'.format(val))

            # always place the document in the cache
            doc_cache.append(doc)
        return list(set(id_lst)), doc_cache

    def _query_many(self, id_lst):
        """
        Call the biothings_client querymany function with a list of identifiers
        and output fields that will be returned.
        :param id_lst: list of identifiers to query
        :return:
        """
        # Query MyGene.info
        # self.logger.debug("query_many scopes:  {}".format(self.lookup_fields[self.input_type]))
        scopes = []
        for input_type in self.input_types:
            for field in self._get_lookup_field(input_type[0]):
                scopes.append(field)
        client = self._get_client()

        return client.querymany(id_lst,
                                scopes=scopes,
                                fields=self.return_fields,
                                as_generator=True,
                                returnall=True,
                                size=self.batch_size)

    def _parse_querymany(self, qr):
        """
        Parse the querymany results from the biothings_client into a structure
        that will later be used for document key replacement.
        :param qr: querymany results
        :return:
        """
        # self.logger.debug("QueryMany Structure:  {}".format(qr))
        qm_struct = {}
        for q in qr['out']:
            query = q['query']
            val = self._parse_h(q)
            if val:
                if query not in qm_struct.keys():
                    qm_struct[query] = [val]
                else:
                    self.one_to_many_cnt += 1
                    qm_struct[query] = qm_struct[query] + [val]
        # self.logger.debug("parse_querymany num qm_struct keys: {}".format(len(qm_struct.keys())))
        # self.logger.info("parse_querymany running one_to_many_cnt: {}".format(self.one_to_many_cnt))
        # self.logger.debug("parse_querymany qm_struct: {}".format(qm_struct.keys()))
        return qm_struct

    def _parse_h(self, h):
        """
        Parse a single hit from the API.
        :param h:
        :return: dictionary of keys
        """
        for output_type in self.output_types:
            for doc_field in self._get_lookup_field(output_type):
                val = DataTransformAPI._nested_lookup(h, doc_field)
                if val:
                    return val

    def _replace_keys(self, qm_struct, doc_cache):
        """
        Build a new list of documents to return that have their keys
        replaced by answers specified in the qm_structure which
        was built earlier.
        :param qm_struct: structure of keys from _parse_querymany
        :param doc_cache: cache of documents that will have keys replaced.
        :return:
        """
        # Replace the keys and build up a new result list
        res_lst = []
        for doc in doc_cache:
            new_doc = None
            for input_type in self.input_types:
                # doc[input_type[1]] must be typed to a string because qm_struct.keys are always strings
                if DataTransformAPI._nested_lookup(doc, input_type[1]) in qm_struct.keys():
                    for key in qm_struct[DataTransformAPI._nested_lookup(doc, input_type[1])]:
                        new_doc = copy.deepcopy(doc)
                        new_doc['_id'] = key
                        res_lst.append(new_doc)
                # Break out if an input type was used.
                if new_doc:
                    break
            if not new_doc and ((self.skip_w_regex and self.skip_w_regex.match(doc['_id'])) or not self.skip_on_failure):
                res_lst.append(doc)

        self.logger.info("_replace_keys:  Num of documents yielded:  {}".format(len(res_lst)))
        # Yield the results
        for r in res_lst:
            yield r

    def _get_lookup_field(self, field):
        """
        Getter for lookup fields which may be either a string or a list of string fields.
        :param field: the name of the field to lookup
        :return:
        """
        if field not in self.lookup_fields.keys():
            raise KeyError('provided field {} is not in self.lookup_fields'.format(field))
        if isinstance(self.lookup_fields[field], str):
            return [self.lookup_fields[field]]
        else:
            return self.lookup_fields[field]

class DataTransformMyChemInfo(DataTransformAPI):
    lookup_fields = {
        'unii': 'unii.unii',
        'rxnorm': [
            'unii.rxcui'
        ],
        'drugbank': 'drugbank.drugbank_id',
        'chebi': 'chebi.chebi_id',
        'chembl': 'chembl.molecule_chembl_id',
        'pubchem': 'pubchem.cid',
        'drugname': [
            'drugbank.name',
            'unii.preferred_term',
            'chebi.chebi_name',
            'chembl.pref_name'
        ],
        'inchi': [
            'drugbank.inchi',
            'chembl.inchi',
            'pubchem.inchi'
            ],
        'inchikey': [
            'drugbank.inchi_key',
            'chembl.inchi_key',
            'pubchem.inchi_key'
        ]
    }
    # The order of output_types decides the priority of the key types we used to get _id value
    output_types=['inchikey', 'unii', 'rxnorm', 'drugbank', 'chebi', 'chembl', 'pubchem', 'drugname'],

    def __init__(self, input_types,
                 output_types=None,
                 skip_on_failure=False,
                 skip_w_regex=None):
        """
        Initialize the class by seting up the client object.
        """
        _output_types = output_types or self.output_types
        super(DataTransformMyChemInfo, self).__init__(input_types, _output_types, skip_on_failure, skip_w_regex)

    def _get_client(self):
        """
        Get Client - return a client appropriate for IDLookup

        This method must be defined in the child class.  It is an artifact
        of multithreading.
        :return:
        """
        if not self.client:
            self.client = biothings_client.get_client('drug')
        return self.client

class BiothingsAPIEdge(DataTransformEdge):
    """
    APIEdge - IDLookupEdge object for API calls
    """
    def __init__(self, lookup, fields, weight=1):
        super().__init__()
        self.init_state()
        self.scope = lookup
        if isinstance(fields, str):
            self.fields = [fields]
        elif isinstance(fields, list):
            self.fields = fields
        else:
            raise TypeError("fields argument must be str or list")
        self.weight = weight

    def init_state(self):
        self._state = {
            "client": None,
            "logger": None
        }

    @property
    def client(self):
        if not self._state["client"]:
            try:
                self.prepare_client()
            except Exception as e:
                # if accessed but not ready, then just ignore and return invalid value for a client
                return None
        return self._state["client"]

    def prepare_client(self):
        raise NotImplementedError("Define in subclass")

    def edge_lookup(self, keylookup_obj, id_strct):
        """
        Follow an edge given a key.

        This method uses the data in the edge_object
        to find one key to another key using an api.
        :param edge:
        :param key:
        :return:
        """
        qr = self._query_many(keylookup_obj, id_strct)
        new_id_strct = self._parse_querymany(keylookup_obj, qr, id_strct, self.fields)
        return new_id_strct

    def _query_many(self, keylookup_obj, id_strct):
        """
        Call the biothings_client querymany function with a list of identifiers
        and output fields that will be returned.
        :param id_lst: list of identifiers to query
        :return:
        """
        if not isinstance(id_strct, IDStruct):
            raise TypeError("id_strct shouldb be of type IDStruct")
        id_lst = []
        for id in id_strct.id_lst:
            id_lst.append('"{}"'.format(id))
        return self.client.querymany(id_lst,
                                     scopes=self.scope,
                                     fields=self.fields,
                                     as_generator=True,
                                     returnall=True,
                                     size=keylookup_obj.batch_size)

    def _parse_querymany(self, keylookup_obj, qr, id_strct, fields):
        """
        Parse the querymany results from the biothings_client into a structure
        that will later be used for document key replacement.
        :param qr: querymany results
        :return:
        """
        # self.logger.debug("QueryMany Structure:  {}".format(qr))
        qm_struct = IDStruct()
        for q in qr['out']:
            query = q['query']
            for field in fields:
                val = nested_lookup(q, field)
                if val:
                    for (orig_id, curr_id) in id_strct:
                        # query is always a string, so this check requires conversion
                        if query == str(curr_id):
                            qm_struct.add(orig_id, val)
        return qm_struct

class MyChemInfoEdge(BiothingsAPIEdge):
    """
    The MyChemInfoEdge uses the MyChem.info API to convert identifiers.
    """

    def __init__(self, lookup, field, weight=1):
        """
        :param lookup: The field in the API to search with the input identifier.
        :type lookup: str
        :param field: The field in the API to convert to.
        :type field: str
        :param weight: Weights are used to prefer one path over another. The path with the lowest weight is preferred. The default weight is 1.
        :type weight: int
        """
        super().__init__(lookup, field, weight)

    def prepare_client(self):
        """
        Load the biothings_client for the class
        :return:
        """
        client = "drug"
        self._state["client"] = biothings_client.get_client(client)
        self.logger.info("Registering biothings_client {}".format(client))

class MyGeneInfoEdge(BiothingsAPIEdge):
    """
    The MyGeneInfoEdge uses the MyGene.info API to convert identifiers.
    """

    def __init__(self, lookup, field, weight=1):
        """
        :param lookup: The field in the API to search with the input identifier.
        :type lookup: str
        :param field: The field in the API to convert to.
        :type field: str
        :param weight: Weights are used to prefer one path over another. The path with the lowest weight is preferred. The default weight is 1.
        :type weight: int
        """
        super().__init__(lookup, field, weight)

    def prepare_client(self):
        """
        Load the biothings_client for the class
        :return:
        """
        client = "gene"
        self._state["client"] = biothings_client.get_client(client)
        self.logger.info("Registering biothings_client {}".format(client))

####################

class DataTransformMyGeneInfo(DataTransformAPI):
    lookup_fields = {
        'ensembl': 'ensembl.gene',
        'entrezgene': 'entrezgene',
        'symbol': 'symbol',
        'uniprot': 'uniprot.Swiss-Prot'
    }

    def __init__(self, input_types,
                 output_types=['entrezgene'],
                 skip_on_failure=False,
                 skip_w_regex=None):
        """
        Initialize the class by seting up the client object.
        """
        super(DataTransformMyGeneInfo, self).__init__(input_types, output_types, skip_on_failure, skip_w_regex)

    def _get_client(self):
        """
        Get Client - return a client appropriate for IDLookup

        This method must be defined in the child class.  It is an artifact
        of multithreading.
        :return:
        """
        if not self.client:
            self.client = biothings_client.get_client('gene')
        return self.client
<commit_msg>DataTransform - abstract API edge client_name<commit_after>import biothings_client
import copy
from itertools import islice, chain
import logging
import re
from biothings.hub.datatransform.datatransform import DataTransform, DataTransformEdge, IDStruct, nested_lookup
from biothings.utils.loggers import get_logger
from biothings import config as btconfig

class DataTransformAPI(DataTransform):
    """
    Perform key lookup or key conversion from one key type to another using
    an API endpoint as a data source.

    This class uses biothings apis to conversion from one key type to another.
    Base classes are used with the decorator syntax shown below:

    @IDLookupMyChemInfo(input_types, output_types)
    def load_document(doc_lst):
        for d in doc_lst:
            yield d

    Lookup fields are configured in the 'lookup_fields' object, examples of which
    can be found in 'IDLookupMyGeneInfo' and 'IDLookupMyChemInfo'.

    Required Options:
    - input_types
        - 'type'
        - ('type', 'nested_source_field')
        - [('type1', 'nested.source_field1'), ('type2', 'nested.source_field2'), ...]
    - output_types:
        - 'type'
        - ['type1', 'type2']

    Additional Options:
    - skip_on_failure:  Do not include a document where key lookup fails in the results
    - skip_w_regex:  skip key lookup if the provided regex matches
    """
    batch_size = 10
    default_source = '_id'
    lookup_fields = {}

    def __init__(self, input_types, output_types, skip_on_failure=False, skip_w_regex=None):
        """
        Initialize the IDLookupAPI object.
        """
        self._generate_return_fields()
        super().__init__(input_types, output_types, skip_on_failure, skip_w_regex)

        # default value of None for client
        self.client = None

        # Keep track of one_to_many relationships
        self.one_to_many_cnt = 0

        self.logger,_ = get_logger('keylookup_api')

    def _valid_input_type(self, input_type):
        """
        Check if the input_type is valid
        :param input_type:
        :return:
        """
        if not isinstance(input_type, str):
            return False
        return input_type.lower() in self.lookup_fields.keys()

    def _valid_output_type(self, output_type):
        """
        Check if the output_type is valid
        :param output_type:
        :return:
        """
        if not isinstance(output_type, str):
            return False
        return output_type.lower() in self.lookup_fields.keys()

    def _generate_return_fields(self):
        """
        Generate the return_fields member variable from the lookup_fields dictionary.
        :return:
        """
        self.return_fields = ''
        for k in self.lookup_fields:
            for field in self._get_lookup_field(k):
                self.return_fields += field + ','
        self.logger.debug("IDLookupAPI return_fields:  {}".format(self.return_fields))

    def key_lookup_batch(self, batchiter):
        """
        Look up all keys for ids given in the batch iterator (1 block)
        :param batchiter:  1 lock of records to look up keys for
        :return:
        """

        id_lst, doc_cache = self._build_cache(batchiter)
        self.logger.info("key_lookup_batch num. id_lst items:  {}".format(len(id_lst)))
        qr = self._query_many(id_lst)
        qm_struct = self._parse_querymany(qr)
        return self._replace_keys(qm_struct, doc_cache)

    def _build_cache(self, batchiter):
        """
        Build an id list and document cache for documents read from the
        batch iterator.
        :param batchiter:  an iterator for a batch of documents.
        :return:
        """
        id_lst = []
        doc_cache = []
        for doc in batchiter:

            # handle skip logic
            if self.skip_w_regex and self.skip_w_regex.match(doc['_id']):
                pass
            else:
                for input_type in self.input_types:
                    val = DataTransformAPI._nested_lookup(doc, input_type[1])
                    if val:
                        id_lst.append('"{}"'.format(val))

            # always place the document in the cache
            doc_cache.append(doc)
        return list(set(id_lst)), doc_cache

    def _query_many(self, id_lst):
        """
        Call the biothings_client querymany function with a list of identifiers
        and output fields that will be returned.
        :param id_lst: list of identifiers to query
        :return:
        """
        # Query MyGene.info
        # self.logger.debug("query_many scopes:  {}".format(self.lookup_fields[self.input_type]))
        scopes = []
        for input_type in self.input_types:
            for field in self._get_lookup_field(input_type[0]):
                scopes.append(field)
        client = self._get_client()

        return client.querymany(id_lst,
                                scopes=scopes,
                                fields=self.return_fields,
                                as_generator=True,
                                returnall=True,
                                size=self.batch_size)

    def _parse_querymany(self, qr):
        """
        Parse the querymany results from the biothings_client into a structure
        that will later be used for document key replacement.
        :param qr: querymany results
        :return:
        """
        # self.logger.debug("QueryMany Structure:  {}".format(qr))
        qm_struct = {}
        for q in qr['out']:
            query = q['query']
            val = self._parse_h(q)
            if val:
                if query not in qm_struct.keys():
                    qm_struct[query] = [val]
                else:
                    self.one_to_many_cnt += 1
                    qm_struct[query] = qm_struct[query] + [val]
        # self.logger.debug("parse_querymany num qm_struct keys: {}".format(len(qm_struct.keys())))
        # self.logger.info("parse_querymany running one_to_many_cnt: {}".format(self.one_to_many_cnt))
        # self.logger.debug("parse_querymany qm_struct: {}".format(qm_struct.keys()))
        return qm_struct

    def _parse_h(self, h):
        """
        Parse a single hit from the API.
        :param h:
        :return: dictionary of keys
        """
        for output_type in self.output_types:
            for doc_field in self._get_lookup_field(output_type):
                val = DataTransformAPI._nested_lookup(h, doc_field)
                if val:
                    return val

    def _replace_keys(self, qm_struct, doc_cache):
        """
        Build a new list of documents to return that have their keys
        replaced by answers specified in the qm_structure which
        was built earlier.
        :param qm_struct: structure of keys from _parse_querymany
        :param doc_cache: cache of documents that will have keys replaced.
        :return:
        """
        # Replace the keys and build up a new result list
        res_lst = []
        for doc in doc_cache:
            new_doc = None
            for input_type in self.input_types:
                # doc[input_type[1]] must be typed to a string because qm_struct.keys are always strings
                if DataTransformAPI._nested_lookup(doc, input_type[1]) in qm_struct.keys():
                    for key in qm_struct[DataTransformAPI._nested_lookup(doc, input_type[1])]:
                        new_doc = copy.deepcopy(doc)
                        new_doc['_id'] = key
                        res_lst.append(new_doc)
                # Break out if an input type was used.
                if new_doc:
                    break
            if not new_doc and ((self.skip_w_regex and self.skip_w_regex.match(doc['_id'])) or not self.skip_on_failure):
                res_lst.append(doc)

        self.logger.info("_replace_keys:  Num of documents yielded:  {}".format(len(res_lst)))
        # Yield the results
        for r in res_lst:
            yield r

    def _get_lookup_field(self, field):
        """
        Getter for lookup fields which may be either a string or a list of string fields.
        :param field: the name of the field to lookup
        :return:
        """
        if field not in self.lookup_fields.keys():
            raise KeyError('provided field {} is not in self.lookup_fields'.format(field))
        if isinstance(self.lookup_fields[field], str):
            return [self.lookup_fields[field]]
        else:
            return self.lookup_fields[field]

class DataTransformMyChemInfo(DataTransformAPI):
    lookup_fields = {
        'unii': 'unii.unii',
        'rxnorm': [
            'unii.rxcui'
        ],
        'drugbank': 'drugbank.drugbank_id',
        'chebi': 'chebi.chebi_id',
        'chembl': 'chembl.molecule_chembl_id',
        'pubchem': 'pubchem.cid',
        'drugname': [
            'drugbank.name',
            'unii.preferred_term',
            'chebi.chebi_name',
            'chembl.pref_name'
        ],
        'inchi': [
            'drugbank.inchi',
            'chembl.inchi',
            'pubchem.inchi'
            ],
        'inchikey': [
            'drugbank.inchi_key',
            'chembl.inchi_key',
            'pubchem.inchi_key'
        ]
    }
    # The order of output_types decides the priority of the key types we used to get _id value
    output_types=['inchikey', 'unii', 'rxnorm', 'drugbank', 'chebi', 'chembl', 'pubchem', 'drugname'],

    def __init__(self, input_types,
                 output_types=None,
                 skip_on_failure=False,
                 skip_w_regex=None):
        """
        Initialize the class by seting up the client object.
        """
        _output_types = output_types or self.output_types
        super(DataTransformMyChemInfo, self).__init__(input_types, _output_types, skip_on_failure, skip_w_regex)

    def _get_client(self):
        """
        Get Client - return a client appropriate for IDLookup

        This method must be defined in the child class.  It is an artifact
        of multithreading.
        :return:
        """
        if not self.client:
            self.client = biothings_client.get_client('drug')
        return self.client

class BiothingsAPIEdge(DataTransformEdge):
    """
    APIEdge - IDLookupEdge object for API calls
    """
    # define in subclass
    client_name = None

    def __init__(self, lookup, fields, weight=1):
        super().__init__()
        self.init_state()
        self.scope = lookup
        if isinstance(fields, str):
            self.fields = [fields]
        elif isinstance(fields, list):
            self.fields = fields
        else:
            raise TypeError("fields argument must be str or list")
        self.weight = weight

    def init_state(self):
        self._state = {
            "client": None,
            "logger": None
        }

    @property
    def client(self):
        if not self._state["client"]:
            try:
                self.prepare_client()
            except Exception as e:
                # if accessed but not ready, then just ignore and return invalid value for a client
                return None
        return self._state["client"]

    def prepare_client(self):
        """
        Load the biothings_client for the class
        :return:
        """
        if not self.client_name:
            raise NotImplementedError("Define client_name in subclass")
        self._state["client"] = biothings_client.get_client(self.client_name)
        self.logger.info("Registering biothings_client {}".format(self.client_name))

    def edge_lookup(self, keylookup_obj, id_strct):
        """
        Follow an edge given a key.

        This method uses the data in the edge_object
        to find one key to another key using an api.
        :param edge:
        :param key:
        :return:
        """
        qr = self._query_many(keylookup_obj, id_strct)
        new_id_strct = self._parse_querymany(keylookup_obj, qr, id_strct, self.fields)
        return new_id_strct

    def _query_many(self, keylookup_obj, id_strct):
        """
        Call the biothings_client querymany function with a list of identifiers
        and output fields that will be returned.
        :param id_lst: list of identifiers to query
        :return:
        """
        if not isinstance(id_strct, IDStruct):
            raise TypeError("id_strct shouldb be of type IDStruct")
        id_lst = []
        for id in id_strct.id_lst:
            id_lst.append('"{}"'.format(id))
        return self.client.querymany(id_lst,
                                     scopes=self.scope,
                                     fields=self.fields,
                                     as_generator=True,
                                     returnall=True,
                                     size=keylookup_obj.batch_size)

    def _parse_querymany(self, keylookup_obj, qr, id_strct, fields):
        """
        Parse the querymany results from the biothings_client into a structure
        that will later be used for document key replacement.
        :param qr: querymany results
        :return:
        """
        # self.logger.debug("QueryMany Structure:  {}".format(qr))
        qm_struct = IDStruct()
        for q in qr['out']:
            query = q['query']
            for field in fields:
                val = nested_lookup(q, field)
                if val:
                    for (orig_id, curr_id) in id_strct:
                        # query is always a string, so this check requires conversion
                        if query == str(curr_id):
                            qm_struct.add(orig_id, val)
        return qm_struct

class MyChemInfoEdge(BiothingsAPIEdge):
    """
    The MyChemInfoEdge uses the MyChem.info API to convert identifiers.
    """
    client_name = "drug"

    def __init__(self, lookup, field, weight=1):
        """
        :param lookup: The field in the API to search with the input identifier.
        :type lookup: str
        :param field: The field in the API to convert to.
        :type field: str
        :param weight: Weights are used to prefer one path over another. The path with the lowest weight is preferred. The default weight is 1.
        :type weight: int
        """
        super().__init__(lookup, field, weight)

class MyGeneInfoEdge(BiothingsAPIEdge):
    """
    The MyGeneInfoEdge uses the MyGene.info API to convert identifiers.
    """
    client_name = "gene"

    def __init__(self, lookup, field, weight=1):
        """
        :param lookup: The field in the API to search with the input identifier.
        :type lookup: str
        :param field: The field in the API to convert to.
        :type field: str
        :param weight: Weights are used to prefer one path over another. The path with the lowest weight is preferred. The default weight is 1.
        :type weight: int
        """
        super().__init__(lookup, field, weight)

####################

class DataTransformMyGeneInfo(DataTransformAPI):
    lookup_fields = {
        'ensembl': 'ensembl.gene',
        'entrezgene': 'entrezgene',
        'symbol': 'symbol',
        'uniprot': 'uniprot.Swiss-Prot'
    }

    def __init__(self, input_types,
                 output_types=['entrezgene'],
                 skip_on_failure=False,
                 skip_w_regex=None):
        """
        Initialize the class by seting up the client object.
        """
        super(DataTransformMyGeneInfo, self).__init__(input_types, output_types, skip_on_failure, skip_w_regex)

    def _get_client(self):
        """
        Get Client - return a client appropriate for IDLookup

        This method must be defined in the child class.  It is an artifact
        of multithreading.
        :return:
        """
        if not self.client:
            self.client = biothings_client.get_client('gene')
        return self.client
<|endoftext|>


<commit_before>#=========================================================================
# PortBundle
#=========================================================================
# This module defines a base class and utility function for creating user
# defined port bundles.  A user first defines a template class which
# subclasses PortBundle, and then passes this template class into the
# create_PortBundles() utility function.  create_PortBundles()
# will return two new classes that implement the two halves (Left and
# Right) of the bundle interface.
#
#   def MyBundle( PortBundle ):
#     def __init__( nbits ):
#       self.data = InPort ( nbits )
#       self.rdy  = OutPort( 1 )
#
#   InMyBundle, OutMyBundle = create_PortBundles( MyBundle )
#
# Some metaclass magic is used to make this work. create_PortBundles
# uses the built-in type() method provided by the Python language
# to create the Left/Right bundle subclasses, additionally adding a
# "flip" class attribute, which is False for left and True for right.
#
# The Left/Right classes are subclasses of the user defined port bundle,
# which in turn should subclass PortBundle, whose __metaclass__ is set
# to be MetaPortBundle. Whenever an instance of the left or right
# port bundle object is created, not only is the __init__ function of
# the PortBundle called (creating the Ports of the bundle), but also
# the __call__ function of MetaPortBundle.  __call__ inspects the
# "flip" class attribute, and then sets the direction of the bundles
# ports based on the value of "flip".

from metaclasses import MetaListConstructor
from signals     import InPort, OutPort

#-------------------------------------------------------------------------
# MetaPortBundle
#-------------------------------------------------------------------------
# Metaclass that customizes PortBundle subclass creation

class MetaPortBundle( MetaListConstructor ):

  def __call__( self, *args, **kwargs ):

    # Create the instance
    inst = super( MetaPortBundle, self ).__call__( *args, **kwargs )

    # Set direction of ports
    if self.flip: inst._reverse()

    # Collect all the ports into a list
    ports = []
    for port_name, port in inst.__dict__.items():
      port.name = port_name
      ports.append( port )
    inst._ports = ports

    # Return the instance
    return inst

#-------------------------------------------------------------------------
# PortBundle
#-------------------------------------------------------------------------
# Base class for user defined port bundles.  These port bundles should
# create a definition class which subclasses PortBundle, and then pass
# the defination class into create_PortBundles to create the input and
# output versions of the bundle.

class PortBundle( object ):
  __metaclass__ = MetaPortBundle

  #-----------------------------------------------------------------------
  # _reverse
  #-----------------------------------------------------------------------
  # Reverse Bundle Direction
  def _reverse( self ):

    for var_name, var_obj in self.__dict__.items():

      if   isinstance( var_obj, InPort ):
        self.__dict__[var_name] = OutPort ( var_obj.msg_type )
      elif isinstance( var_obj, OutPort ):
        self.__dict__[var_name] = InPort  ( var_obj.msg_type )

    return self

  #-----------------------------------------------------------------------
  # get_ports
  #-----------------------------------------------------------------------
  # Get list of ports in PortBundle.
  def get_ports( self ):
    return self._ports

#-------------------------------------------------------------------------
# create_PortBundles
#-------------------------------------------------------------------------
# Utility function that takes a user defined PortBundle class and
# generates the Left and Right (flipped and unflipped) versions of the
# class.

def create_PortBundles( bundle_def ):
  name = bundle_def.__name__
  a = type( '_Left'+name,  (bundle_def,), {'flip':False})
  b = type( '_Right'+name, (bundle_def,), {'flip':True} )
  return a, b

<commit_msg>[pymtl] sort port list in PortBundle, fixes ordering issue in pypy<commit_after>#=========================================================================
# PortBundle
#=========================================================================
# This module defines a base class and utility function for creating user
# defined port bundles.  A user first defines a template class which
# subclasses PortBundle, and then passes this template class into the
# create_PortBundles() utility function.  create_PortBundles()
# will return two new classes that implement the two halves (Left and
# Right) of the bundle interface.
#
#   def MyBundle( PortBundle ):
#     def __init__( nbits ):
#       self.data = InPort ( nbits )
#       self.rdy  = OutPort( 1 )
#
#   InMyBundle, OutMyBundle = create_PortBundles( MyBundle )
#
# Some metaclass magic is used to make this work. create_PortBundles
# uses the built-in type() method provided by the Python language
# to create the Left/Right bundle subclasses, additionally adding a
# "flip" class attribute, which is False for left and True for right.
#
# The Left/Right classes are subclasses of the user defined port bundle,
# which in turn should subclass PortBundle, whose __metaclass__ is set
# to be MetaPortBundle. Whenever an instance of the left or right
# port bundle object is created, not only is the __init__ function of
# the PortBundle called (creating the Ports of the bundle), but also
# the __call__ function of MetaPortBundle.  __call__ inspects the
# "flip" class attribute, and then sets the direction of the bundles
# ports based on the value of "flip".

from metaclasses import MetaListConstructor
from signals     import InPort, OutPort

#-------------------------------------------------------------------------
# MetaPortBundle
#-------------------------------------------------------------------------
# Metaclass that customizes PortBundle subclass creation

class MetaPortBundle( MetaListConstructor ):

  def __call__( self, *args, **kwargs ):

    # Create the instance
    inst = super( MetaPortBundle, self ).__call__( *args, **kwargs )

    # Set direction of ports
    if self.flip: inst._reverse()

    # Collect all the ports into a list
    ports = []
    for port_name, port in inst.__dict__.items():
      port.name = port_name
      ports.append( port )
    inst._ports = sorted( ports, key=lambda x: x.name )

    # Return the instance
    return inst

#-------------------------------------------------------------------------
# PortBundle
#-------------------------------------------------------------------------
# Base class for user defined port bundles.  These port bundles should
# create a definition class which subclasses PortBundle, and then pass
# the defination class into create_PortBundles to create the input and
# output versions of the bundle.

class PortBundle( object ):
  __metaclass__ = MetaPortBundle

  #-----------------------------------------------------------------------
  # _reverse
  #-----------------------------------------------------------------------
  # Reverse Bundle Direction
  def _reverse( self ):

    for var_name, var_obj in self.__dict__.items():

      if   isinstance( var_obj, InPort ):
        self.__dict__[var_name] = OutPort ( var_obj.msg_type )
      elif isinstance( var_obj, OutPort ):
        self.__dict__[var_name] = InPort  ( var_obj.msg_type )

    return self

  #-----------------------------------------------------------------------
  # get_ports
  #-----------------------------------------------------------------------
  # Get list of ports in PortBundle.
  def get_ports( self ):
    return self._ports

#-------------------------------------------------------------------------
# create_PortBundles
#-------------------------------------------------------------------------
# Utility function that takes a user defined PortBundle class and
# generates the Left and Right (flipped and unflipped) versions of the
# class.

def create_PortBundles( bundle_def ):
  name = bundle_def.__name__
  a = type( '_Left'+name,  (bundle_def,), {'flip':False})
  b = type( '_Right'+name, (bundle_def,), {'flip':True} )
  return a, b

<|endoftext|>


<commit_before># Copyright (C) 2014 Linaro Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from utils.log import get_log

BASE_PATH = '/var/www/images/kernel-ci'
LOG = get_log()
<commit_msg>Create function to test hidden files/dirs.<commit_after># Copyright (C) 2014 Linaro Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from utils.log import get_log

BASE_PATH = '/var/www/images/kernel-ci'
LOG = get_log()

def is_hidden(value):
    """Verify if a file name or dir name is hidden (starts with .).

    :param value: The value to verify.
    :return True or False.
    """
    hidden = False
    if value.startswith('.'):
        hidden = True
    return hidden
<|endoftext|>


<commit_before># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from UM.Signal import Signal, SignalEmitter
from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry

##  Manages all available output devices and the factory objects used to create them.
#
#
class OutputDeviceManager(SignalEmitter):
    def __init__(self):
        super().__init__()

        self._output_devices = {}
        self._plugins = {}

        PluginRegistry.addType("output_device", self.addOutputDevicePlugin)

    def getOutputDevices(self):
        return self._output_devices.values()

    def getOutputDeviceNames(self):
        return self._output_devices.keys()

    def getOutputDevice(self, name):
        if not name in self._output_devices:
            return None

        return self._output_devices[name]

    outputDevicesChanged = Signal()

    def addOutputDevice(self, device):
        if device.getId() in self._output_devices:
            Logger.log("i", "Output Device %s already added", device.getId())
            return

        self._output_devices[device.getId()] = device
        self.outputDevicesChanged.emit()

    def removeOutputDevice(self, name):
        if name not in self._output_devices:
            return

        del self._output_devices[name]
        self.outputDevicesChanged.emit()

    def getDefaultOutputDevice(self):
        pass

    def addOutputDevicePlugin(self, plugin):
        if plugin.getPluginId() in self._plugins:
            Logger.log("i", "Output Device Plugin %s was already added", plugin.getPluginId())
            return

        self._plugins[plugin.getPluginId()] = plugin
        plugin.start()

    def removeOutputDevicePlugin(self, name):
        if name not in self._plugins:
            return

        self._plugins[name].stop()
        del self._plugins[name]
<commit_msg>Add state signals that are connected to invidual device state signals<commit_after># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from UM.Signal import Signal, SignalEmitter
from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry

##  Manages all available output devices and the factory objects used to create them.
#
#
class OutputDeviceManager(SignalEmitter):
    def __init__(self):
        super().__init__()

        self._output_devices = {}
        self._plugins = {}

        PluginRegistry.addType("output_device", self.addOutputDevicePlugin)

    writeStarted = Signal()
    writeProgress = Signal()
    writeFinished = Signal()
    writeError = Signal()
    writeSuccess = Signal()

    def getOutputDevices(self):
        return self._output_devices.values()

    def getOutputDeviceNames(self):
        return self._output_devices.keys()

    def getOutputDevice(self, name):
        if not name in self._output_devices:
            return None

        return self._output_devices[name]

    outputDevicesChanged = Signal()

    def addOutputDevice(self, device):
        if device.getId() in self._output_devices:
            Logger.log("i", "Output Device %s already added", device.getId())
            return

        self._output_devices[device.getId()] = device
        device.writeStarted.connect(self.writeStarted)
        device.writeProgress.connect(self.writeProgress)
        device.writeFinished.connect(self.writeFinished)
        device.writeError.connect(self.writeError)
        device.writeSuccess.connect(self.writeSuccess)
        self.outputDevicesChanged.emit()

    def removeOutputDevice(self, name):
        if name not in self._output_devices:
            return

        device = self._output_devices[name]
        del self._output_devices[name]
        device.writeStarted.disconnect(self.writeStarted)
        device.writeProgress.disconnect(self.writeProgress)
        device.writeFinished.disconnect(self.writeFinished)
        device.writeError.disconnect(self.writeError)
        device.writeSuccess.disconnect(self.writeSuccess)
        self.outputDevicesChanged.emit()

    def getDefaultOutputDevice(self):
        pass

    def addOutputDevicePlugin(self, plugin):
        if plugin.getPluginId() in self._plugins:
            Logger.log("i", "Output Device Plugin %s was already added", plugin.getPluginId())
            return

        self._plugins[plugin.getPluginId()] = plugin
        plugin.start()

    def removeOutputDevicePlugin(self, name):
        if name not in self._plugins:
            return

        self._plugins[name].stop()
        del self._plugins[name]
<|endoftext|>


<commit_before>#!/usr/bin/env python3

import os
import subprocess
import sys

cc_mapping = {'gcc-5': 'g++-5', 'gcc-6': 'g++-6', 'clang-3.8': 'clang++-3.8', 'clang-3.9': 'clang++-3.9'}

def update(branch, cc):
    gdt_super_dir = os.path.join(os.path.dirname(__file__), '..', '..',)
    dockerfile = os.path.join(os.path.dirname(__file__), 'dune-gdt-testing.docker')

    os.chdir(gdt_super_dir)

    cxx = cc_mapping[cc]
    subprocess.check_call(['docker', 'build', '-f', '.travis/docker/dune-gdt-testing.docker',
                        '-t', 'dunecommunity/dune-gdt-testing:{}_{}'.format(cc, branch), '--build-arg', 'cc={}'.format(cc),
                        '--build-arg', 'cxx={}'.format(cxx), '.'])

if __name__ == '__main__':
    if len(sys.argv) > 2:
        ccs = [sys.argv[1]]
        branches = [sys.argv[2]]
    else:
        ccs = list(cc_mapping.keys())
        branches = ['master']

    for b in branches:
        for c in ccs:
            update(b, c)

    subprocess.check_call(['docker', 'push', 'dunecommunity/dune-gdt-testing'])
<commit_msg>[travis] try to debug docker push<commit_after>#!/usr/bin/env python3

import os
import subprocess
import sys

cc_mapping = {'gcc-5': 'g++-5', 'gcc-6': 'g++-6', 'clang-3.8': 'clang++-3.8', 'clang-3.9': 'clang++-3.9'}

def update(branch, cc):
    gdt_super_dir = os.path.join(os.path.dirname(__file__), '..', '..',)
    dockerfile = os.path.join(os.path.dirname(__file__), 'dune-gdt-testing.docker')

    os.chdir(gdt_super_dir)

    cxx = cc_mapping[cc]
    subprocess.check_call(['docker', 'build', '-f', '.travis/docker/dune-gdt-testing.docker',
                        '-t', 'dunecommunity/dune-gdt-testing:{}_{}'.format(cc, branch), '--build-arg', 'cc={}'.format(cc),
                        '--build-arg', 'cxx={}'.format(cxx), '.'])

if __name__ == '__main__':
    if len(sys.argv) > 2:
        ccs = [sys.argv[1]]
        branches = [sys.argv[2]]
    else:
        ccs = list(cc_mapping.keys())
        branches = ['master']

    for b in branches:
        for c in ccs:
            update(b, c)

    subprocess.check_call(['docker', '--log-level="debug"', 'images'])
    subprocess.check_call(['docker', '--log-level="debug"', 'push', 'dunecommunity/dune-gdt-testing'])
<|endoftext|>


<commit_before>class Base:

    def meth(self):
        print("in Base meth")

class Sub(Base):

    def meth(self):
        print("in Sub meth")
        return super().meth()

a = Sub()
a.meth()
<commit_msg>test/class-super: Expose super() breakage.<commit_after>class Base:

    def __init__(self):
        self.a = 1

    def meth(self):
        print("in Base meth", self.a)

class Sub(Base):

    def meth(self):
        print("in Sub meth")
        return super().meth()

a = Sub()
a.meth()
<|endoftext|>


<commit_before># Copyright 2016 Reahl Software Services (Pty) Ltd. All rights reserved.
# -*- encoding: utf-8 -*-
#
#    This file is part of Reahl.
#
#    Reahl is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation; version 3 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

""".. versionadded:: 3.2

A Bootstrap Navbar is a header for a web application with all manner
of useful content, including a navigation menu.

"""
from __future__ import print_function, unicode_literals, absolute_import, division

# noinspection PyUnresolvedReferences
import six

from reahl.component.exceptions import arg_checks, IsInstance, ProgrammerError

from reahl.web.fw import Layout
from reahl.web.ui import Url, Widget, HTMLWidget, HTMLElement, HTMLAttributeValueOption
from reahl.component.i18n import Translator
from reahl.web.bootstrap.ui import Div, Nav, A, TextNode, Span
from reahl.web.bootstrap.forms import Form
import reahl.web.bootstrap.navs
from reahl.web.bootstrap.grid import Container, DeviceClass

_ = Translator('reahl-web')

class CollapseToggle(HTMLElement):
    def __init__(self, view, target_widget, text=None):
        super(CollapseToggle, self).__init__(view, 'button', children_allowed=True)
        self.set_attribute('type', 'button')

        self.target_widget = target_widget
        self.append_class('navbar-toggler')
        self.set_attribute('data-toggle', 'collapse')
        self.set_attribute('data-target', '#%s' % target_widget.css_id)
        self.set_attribute('aria-controls', '%s' % target_widget.css_id)
        self.set_attribute('aria-label', _('Toggle navigation'))

        if text is None:
            collapse_toggle_widget = Span(self.view)
            collapse_toggle_widget.append_class('navbar-toggler-icon')
        else:
            collapse_toggle_widget = TextNode(view, text)
        self.add_child(collapse_toggle_widget)

class NavbarFixed(HTMLAttributeValueOption):
    def __init__(self, fixed_to):
        super(NavbarFixed, self).__init__(fixed_to, fixed_to is not None,
                                          prefix='', constrain_value_to=['fixed-top', 'fixed-bottom', 'sticky-top'])

class NavbarTogglerAlignment(HTMLAttributeValueOption):
    def __init__(self, alignment):
        super(NavbarTogglerAlignment, self).__init__(alignment, alignment is not None,
                                                     prefix='navbar-toggler', constrain_value_to=['left', 'right'])

class ColourTheme(HTMLAttributeValueOption):
    def __init__(self, name):
        super(ColourTheme, self).__init__(name, name is not None,
                                          prefix='navbar', constrain_value_to=['light', 'dark'])

class BackgroundScheme(HTMLAttributeValueOption):
    def __init__(self, name):
        super(BackgroundScheme, self).__init__(name, name is not None,
                                               prefix='bg', constrain_value_to=['primary', 'dark', 'light'])

class NavbarLayout(Layout):
    """Used to populate a Navbar.

    :param fixed_to: May be one of 'top','bottom' or 'stickytop'.
                    The Navbar will stick to the top or bottom of the viewport.
    :param center_contents: If True, all the contents of the Navbar is centered within the Navbar itself.
    :param colour_theme: Whether the Navbar has a 'light' or 'dark' background.
    :param bg_scheme: Whether the Navbar should use 'primary' colors, a 'dark' (light on dark) scheme
                        or a 'light' background.
    """
    def __init__(self, fixed_to=None, center_contents=False, colour_theme=None, bg_scheme=None):
        super(NavbarLayout, self).__init__()

        self.fixed = NavbarFixed(fixed_to)
        self.center_contents = center_contents
        self.colour_theme = ColourTheme(colour_theme)
        self.bg_scheme = BackgroundScheme(bg_scheme)
        self.brand = None
        self.contents_container = None

    @property
    def nav(self):
        return self.widget.html_representation

    def customise_widget(self):
        super(NavbarLayout, self).customise_widget()
        if self.center_contents:
            centering_div = self.nav.add_child(Div(self.view).use_layout(Container()))
            self.contents_container = centering_div
        else:
            self.contents_container = self.nav

        if self.fixed.is_set:
            self.widget.append_class(self.fixed.as_html_snippet())

        for option in [self.colour_theme, self.bg_scheme]:
            if option.is_set:
                self.nav.append_class(option.as_html_snippet())

    def set_brand_text(self, brand_text):
        """Sets the brand to be a link to the home page that contains the given text.

        :param brand_text: Text to use for branding.
        """
        brand_a = A(self.view, Url('#'), description=brand_text)
        self.set_brand(brand_a)

    def insert_brand_widget(self, brand_html_element):
        self.contents_container.insert_child(0, brand_html_element)

    @arg_checks(brand_html_element=IsInstance(HTMLWidget))
    def set_brand(self, brand_htmlwidget):
        """Sets `brand_widget` to be used as branding.

        :param brand_htmlwidget: An :class:`~reahl.web.ui.HTMLWidget` to be used as branding.
        """
        if self.brand:
            raise ProgrammerError('Brand has already been set to: %s' % self.brand)

        self.insert_brand_widget(brand_htmlwidget)
        brand_htmlwidget.append_class('navbar-brand')
        self.brand = brand_htmlwidget
        return self.brand

    @arg_checks(widget=IsInstance((reahl.web.bootstrap.navs.Nav, Form, TextNode)))
    def add(self, widget):
        """Adds the given Form or Nav `widget` to the Navbar.

        :param widget: A :class:`~reahl.web.bootstrap.navs.Nav`, :class:`~reahl.web.bootstrap.ui.Form` or
                       :class:`~reahl.web.bootstrap.ui.TextNode` to add.
        """
        if isinstance(widget, reahl.web.bootstrap.navs.Nav):
            widget.append_class('navbar-nav')
        if isinstance(widget, Form):
            widget.append_class('form-inline')
        if isinstance(widget, TextNode):
            span = Span(self.view)
            span.add_child(widget)
            span.append_class('navbar-text')
            widget = span
        return self.contents_container.add_child(widget)

    def add_toggle(self, target_html_element, text=None, alignment=None):
        """Adds a link that toggles the display of the given `target_html_element`.

        :param target_html_element: A :class:`~reahl.web.ui.HTMLElement`
        :param text: Text to be used on the toggle link. If None, the boostrap navbar-toggler-icon is used
        :param alignment: May be None(bootstrap default), 'left' or 'right' to indicate
                                          where the toggle button should be displayed.
        """
        if not target_html_element.css_id_is_set:
            raise ProgrammerError('%s has no css_id set. A toggle is required to have a css_id' % target_html_element)
        target_html_element.append_class('collapse')
        toggle = CollapseToggle(self.view, target_html_element, text=text)
        if alignment:
            toggle.append_class(NavbarTogglerAlignment(alignment).as_html_snippet())

        self.contents_container.insert_child(0, toggle)
        return toggle

class ResponsiveLayout(NavbarLayout):
    """Makes the Navbar responsive and collapseable depending on the device.

    :param collapse_below_device_class: Which device class should trigger responsive collapsing.
                                        Valid values: xs, sm, md, lg, xl
    :param fixed_to: May be one of 'fixed-top','fixed-bottom' or 'sticky-top'.
                    The Navbar will stick to the top or bottom of the viewport.
    :param center_contents: If True, all the contents of the Navbar is centered within the Navbar itself.
    :param toggle_button_alignment: May be None, 'left' or 'right' to indicate where the toggle button is displayed.
    :param collapse_brand_with_content: When set to True, the brand should collapse with the content.
    :param colour_theme: Whether the Navbar has a 'dark' or 'light' background.
    :param bg_scheme: Whether the Navbar should use 'primary' colors, an 'inverse' (light on dark) scheme
                        or a 'faded' background.
    :param text: Text to be used on the toggle link. If None, the boostrap navbar-toggler-icon is used.

    """
    def __init__(self, collapse_below_device_class, center_contents=False, fixed_to=None, toggle_button_alignment=None,
                 collapse_brand_with_content=False,
                 colour_theme=None, bg_scheme=None, text=None):
        super(ResponsiveLayout, self).__init__(fixed_to=fixed_to, center_contents=center_contents,
                                               colour_theme=colour_theme, bg_scheme=bg_scheme)
        self.collapse_below_device_class = DeviceClass(collapse_below_device_class)
        self.collapse_brand_with_content = collapse_brand_with_content
        self.toggle_button_alignment = toggle_button_alignment
        if not self.collapse_below_device_class.one_smaller:
            raise ProgrammerError(('There is no device class smaller than %s' %
                                   self.collapse_below_device_class) +
                                  ' It does not make sense to collapse only '
                                  'if the viewport is smaller than the smallest device')
        self.text = text

    def insert_brand_widget(self, brand_html_element):
        if self.collapse_brand_with_content:
            super(ResponsiveLayout, self).insert_brand_widget(brand_html_element)
        else:
            # child[0] is the toggle
            self.nav.insert_child(1, brand_html_element)

    def customise_widget(self):
        super(ResponsiveLayout, self).customise_widget()
        if not self.widget.css_id_is_set:
            raise ProgrammerError('%s has no css_id set. A %s can only be used with a Widget that has a css_id' %
                                  (self.widget, self.__class__))

        collapsable = Div(self.view, css_id='%s_collapsable' % self.widget.css_id)
        collapsable.append_class('navbar-collapse')

        self.add_toggle(collapsable, text=self.text, alignment=self.toggle_button_alignment)

        toggle_size = self.collapse_below_device_class.one_smaller
        self.nav.append_class('navbar-expand-%s' % toggle_size.name)

        self.contents_container.add_child(collapsable)
        self.contents_container = collapsable

class Navbar(HTMLWidget):
    """A bootstrap Navbar can be used as page header in a web
    application. A Navbar can contain some branding text, a
    :class:`~reahl.web.bootstrap.navs.Nav` and a small
    :class:`~reahl.web.bootstrap.forms.Form`.

    You populate a Navbar using a NavbarLayout for complete control
    over how the Navbar is laid out, which of its possible elements
    are present and how they are composed themselves.

    :param view: (See :class:`reahl.web.fw.Widget`)
    :param css_id: (See :class:`reahl.web.fw.Widget`)
    """
    def __init__(self, view, css_id=None):
        super(Navbar, self).__init__(view)

        self.navbar = self.add_child(Nav(view))
        self.navbar.append_class('navbar')
        self.set_html_representation(self.navbar)
        if css_id:
            self.set_id(css_id)
<commit_msg>fixed docs<commit_after># Copyright 2016 Reahl Software Services (Pty) Ltd. All rights reserved.
# -*- encoding: utf-8 -*-
#
#    This file is part of Reahl.
#
#    Reahl is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation; version 3 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

""".. versionadded:: 3.2

A Bootstrap Navbar is a header for a web application with all manner
of useful content, including a navigation menu.

"""
from __future__ import print_function, unicode_literals, absolute_import, division

# noinspection PyUnresolvedReferences
import six

from reahl.component.exceptions import arg_checks, IsInstance, ProgrammerError

from reahl.web.fw import Layout
from reahl.web.ui import Url, Widget, HTMLWidget, HTMLElement, HTMLAttributeValueOption
from reahl.component.i18n import Translator
from reahl.web.bootstrap.ui import Div, Nav, A, TextNode, Span
from reahl.web.bootstrap.forms import Form
import reahl.web.bootstrap.navs
from reahl.web.bootstrap.grid import Container, DeviceClass

_ = Translator('reahl-web')

class CollapseToggle(HTMLElement):
    def __init__(self, view, target_widget, text=None):
        super(CollapseToggle, self).__init__(view, 'button', children_allowed=True)
        self.set_attribute('type', 'button')

        self.target_widget = target_widget
        self.append_class('navbar-toggler')
        self.set_attribute('data-toggle', 'collapse')
        self.set_attribute('data-target', '#%s' % target_widget.css_id)
        self.set_attribute('aria-controls', '%s' % target_widget.css_id)
        self.set_attribute('aria-label', _('Toggle navigation'))

        if text is None:
            collapse_toggle_widget = Span(self.view)
            collapse_toggle_widget.append_class('navbar-toggler-icon')
        else:
            collapse_toggle_widget = TextNode(view, text)
        self.add_child(collapse_toggle_widget)

class NavbarFixed(HTMLAttributeValueOption):
    def __init__(self, fixed_to):
        super(NavbarFixed, self).__init__(fixed_to, fixed_to is not None,
                                          prefix='', constrain_value_to=['fixed-top', 'fixed-bottom', 'sticky-top'])

class NavbarTogglerAlignment(HTMLAttributeValueOption):
    def __init__(self, alignment):
        super(NavbarTogglerAlignment, self).__init__(alignment, alignment is not None,
                                                     prefix='navbar-toggler', constrain_value_to=['left', 'right'])

class ColourTheme(HTMLAttributeValueOption):
    def __init__(self, name):
        super(ColourTheme, self).__init__(name, name is not None,
                                          prefix='navbar', constrain_value_to=['light', 'dark'])

class BackgroundScheme(HTMLAttributeValueOption):
    def __init__(self, name):
        super(BackgroundScheme, self).__init__(name, name is not None,
                                               prefix='bg', constrain_value_to=['primary', 'dark', 'light'])

class NavbarLayout(Layout):
    """Used to populate a Navbar.

    :param fixed_to: May be one of 'top','bottom' or 'stickytop'.
                    The Navbar will stick to the top or bottom of the viewport.
    :param center_contents: If True, all the contents of the Navbar is centered within the Navbar itself.
    :param colour_theme: Use 'light' for use with light background colors, or 'dark' with dark background colors.
    :param bg_scheme: Whether the Navbar should use 'primary' colors, a 'dark' (light on dark) scheme
                        or a 'light' background.
    """
    def __init__(self, fixed_to=None, center_contents=False, colour_theme=None, bg_scheme=None):
        super(NavbarLayout, self).__init__()

        self.fixed = NavbarFixed(fixed_to)
        self.center_contents = center_contents
        self.colour_theme = ColourTheme(colour_theme)
        self.bg_scheme = BackgroundScheme(bg_scheme)
        self.brand = None
        self.contents_container = None

    @property
    def nav(self):
        return self.widget.html_representation

    def customise_widget(self):
        super(NavbarLayout, self).customise_widget()
        if self.center_contents:
            centering_div = self.nav.add_child(Div(self.view).use_layout(Container()))
            self.contents_container = centering_div
        else:
            self.contents_container = self.nav

        if self.fixed.is_set:
            self.widget.append_class(self.fixed.as_html_snippet())

        for option in [self.colour_theme, self.bg_scheme]:
            if option.is_set:
                self.nav.append_class(option.as_html_snippet())

    def set_brand_text(self, brand_text):
        """Sets the brand to be a link to the home page that contains the given text.

        :param brand_text: Text to use for branding.
        """
        brand_a = A(self.view, Url('#'), description=brand_text)
        self.set_brand(brand_a)

    def insert_brand_widget(self, brand_html_element):
        self.contents_container.insert_child(0, brand_html_element)

    @arg_checks(brand_html_element=IsInstance(HTMLWidget))
    def set_brand(self, brand_htmlwidget):
        """Sets `brand_widget` to be used as branding.

        :param brand_htmlwidget: An :class:`~reahl.web.ui.HTMLWidget` to be used as branding.
        """
        if self.brand:
            raise ProgrammerError('Brand has already been set to: %s' % self.brand)

        self.insert_brand_widget(brand_htmlwidget)
        brand_htmlwidget.append_class('navbar-brand')
        self.brand = brand_htmlwidget
        return self.brand

    @arg_checks(widget=IsInstance((reahl.web.bootstrap.navs.Nav, Form, TextNode)))
    def add(self, widget):
        """Adds the given Form or Nav `widget` to the Navbar.

        :param widget: A :class:`~reahl.web.bootstrap.navs.Nav`, :class:`~reahl.web.bootstrap.ui.Form` or
                       :class:`~reahl.web.bootstrap.ui.TextNode` to add.
        """
        if isinstance(widget, reahl.web.bootstrap.navs.Nav):
            widget.append_class('navbar-nav')
        if isinstance(widget, Form):
            widget.append_class('form-inline')
        if isinstance(widget, TextNode):
            span = Span(self.view)
            span.add_child(widget)
            span.append_class('navbar-text')
            widget = span
        return self.contents_container.add_child(widget)

    def add_toggle(self, target_html_element, text=None, alignment=None):
        """Adds a link that toggles the display of the given `target_html_element`.

        :param target_html_element: A :class:`~reahl.web.ui.HTMLElement`
        :param text: Text to be used on the toggle link. If None, the boostrap navbar-toggler-icon is used
        :param alignment: May be None(bootstrap default), 'left' or 'right' to indicate
                                          where the toggle button should be displayed.
        """
        if not target_html_element.css_id_is_set:
            raise ProgrammerError('%s has no css_id set. A toggle is required to have a css_id' % target_html_element)
        target_html_element.append_class('collapse')
        toggle = CollapseToggle(self.view, target_html_element, text=text)
        if alignment:
            toggle.append_class(NavbarTogglerAlignment(alignment).as_html_snippet())

        self.contents_container.insert_child(0, toggle)
        return toggle

class ResponsiveLayout(NavbarLayout):
    """Makes the Navbar responsive and collapseable depending on the device.

    :param collapse_below_device_class: Which device class should trigger responsive collapsing.
                                        Valid values: xs, sm, md, lg, xl
    :param fixed_to: May be one of 'fixed-top','fixed-bottom' or 'sticky-top'.
                    The Navbar will stick to the top or bottom of the viewport.
    :param center_contents: If True, all the contents of the Navbar is centered within the Navbar itself.
    :param toggle_button_alignment: May be None, 'left' or 'right' to indicate where the toggle button is displayed.
    :param collapse_brand_with_content: When set to True, the brand should collapse with the content.
    :param colour_theme: Use 'light' for use with light background colors, or 'dark' with dark background colors.
    :param bg_scheme: Whether the Navbar should use 'primary' colors, a 'dark' (light on dark) scheme
                        or a 'light' background.
    :param text: Text to be used on the toggle link. If None, the boostrap navbar-toggler-icon is used.

    """
    def __init__(self, collapse_below_device_class, center_contents=False, fixed_to=None, toggle_button_alignment=None,
                 collapse_brand_with_content=False,
                 colour_theme=None, bg_scheme=None, text=None):
        super(ResponsiveLayout, self).__init__(fixed_to=fixed_to, center_contents=center_contents,
                                               colour_theme=colour_theme, bg_scheme=bg_scheme)
        self.collapse_below_device_class = DeviceClass(collapse_below_device_class)
        self.collapse_brand_with_content = collapse_brand_with_content
        self.toggle_button_alignment = toggle_button_alignment
        if not self.collapse_below_device_class.one_smaller:
            raise ProgrammerError(('There is no device class smaller than %s' %
                                   self.collapse_below_device_class) +
                                  ' It does not make sense to collapse only '
                                  'if the viewport is smaller than the smallest device')
        self.text = text

    def insert_brand_widget(self, brand_html_element):
        if self.collapse_brand_with_content:
            super(ResponsiveLayout, self).insert_brand_widget(brand_html_element)
        else:
            # child[0] is the toggle
            self.nav.insert_child(1, brand_html_element)

    def customise_widget(self):
        super(ResponsiveLayout, self).customise_widget()
        if not self.widget.css_id_is_set:
            raise ProgrammerError('%s has no css_id set. A %s can only be used with a Widget that has a css_id' %
                                  (self.widget, self.__class__))

        collapsable = Div(self.view, css_id='%s_collapsable' % self.widget.css_id)
        collapsable.append_class('navbar-collapse')

        self.add_toggle(collapsable, text=self.text, alignment=self.toggle_button_alignment)

        toggle_size = self.collapse_below_device_class.one_smaller
        self.nav.append_class('navbar-expand-%s' % toggle_size.name)

        self.contents_container.add_child(collapsable)
        self.contents_container = collapsable

class Navbar(HTMLWidget):
    """A bootstrap Navbar can be used as page header in a web
    application. A Navbar can contain some branding text, a
    :class:`~reahl.web.bootstrap.navs.Nav` and a small
    :class:`~reahl.web.bootstrap.forms.Form`.

    You populate a Navbar using a NavbarLayout for complete control
    over how the Navbar is laid out, which of its possible elements
    are present and how they are composed themselves.

    :param view: (See :class:`reahl.web.fw.Widget`)
    :param css_id: (See :class:`reahl.web.fw.Widget`)
    """
    def __init__(self, view, css_id=None):
        super(Navbar, self).__init__(view)

        self.navbar = self.add_child(Nav(view))
        self.navbar.append_class('navbar')
        self.set_html_representation(self.navbar)
        if css_id:
            self.set_id(css_id)
<|endoftext|>


<commit_before>import os
import socket
import string
import logging

import pytest
try:
    from path import Path
except ImportError:
    from path import path as Path

from pytest_fixture_config import yield_requires_config
from pytest_server_fixtures import CONFIG

from .http import HTTPTestServer

log = logging.getLogger(__name__)

@pytest.yield_fixture(scope='function')
@yield_requires_config(CONFIG, ['httpd_executable', 'httpd_modules'])
def httpd_server():
    """ Function-scoped httpd server in a local thread.

        Methods
        -------
        get()   : Query url relative to the server root.
        ..        Parse as json and retry failures by default.
        post()  : Post payload to url relative to the server root.
        ..        Parse as json and retry failures by default.
    """
    test_server = HTTPDServer()
    test_server.start()
    yield test_server
    test_server.teardown()

class HTTPDServer(HTTPTestServer):
    port_seed = 65531

    cfg_modules_template = """
      LoadModule headers_module $modules/mod_headers.so
      LoadModule proxy_module $modules/mod_proxy.so
      LoadModule proxy_http_module $modules/mod_proxy_http.so
      LoadModule proxy_connect_module $modules/mod_proxy_connect.so
      LoadModule alias_module $modules/mod_alias.so
      LoadModule dir_module $modules/mod_dir.so
      LoadModule autoindex_module $modules/mod_autoindex.so
      <IfModule !mod_log_config.c>
          LoadModule log_config_module $modules/mod_log_config.so
      </IfModule>
      LoadModule mime_module $modules/mod_mime.so
      LoadModule authz_core_module $modules/mod_authz_core.so
    """

    cfg_mpm_template = """
      LoadModule mpm_prefork_module $modules/mod_mpm_prefork.so
      LoadModule unixd_module modules/mod_unixd.so
      StartServers       1
      MinSpareServers    1
      MaxSpareServers   4
      ServerLimit      4
      MaxClients       4
      MaxRequestsPerChild  10000
    """

    cfg_template = """
      TypesConfig /etc/mime.types

      ServerRoot $server_root
      Listen $listen_addr
      PidFile $server_root/run/httpd.pid

      ErrorLog $log_dir/error.log
      LogFormat "%h %l %u %t \\"%r\\" %>s %b" common
      CustomLog $log_dir/access.log common
      LogLevel info

      $proxy_rules

      Alias / $document_root/

      <Directory $server_root>
          Options +Indexes
      </Directory>
    """

    def __init__(self, proxy_rules=None, extra_cfg='', document_root=None, log_dir=None, **kwargs):
        """ httpd Proxy Server

        Parameters
        ----------
        proxy_rules: `dict`
            { proxy_src: proxy_dest }. Eg   {'/downstream_url/' : server.uri}
        extra_cfg: `str`
            Any extra Apache config
        document_root : `str`
            Server document root, defaults to temporary workspace
        log_dir : `str`
            Server log directory, defaults to $(workspace)/logs
        """
        self.proxy_rules = proxy_rules if proxy_rules is not None else {}
        self.cfg_template = string.Template(self.cfg_modules_template +
                                            self.cfg_mpm_template +
                                            self.cfg_template +
                                            extra_cfg)

        # Always print debug output for this process
        os.environ['DEBUG'] = '1'

        # Discover externally accessable hostname so selenium can get to it
        kwargs['hostname'] = kwargs.get('hostname', socket.gethostbyname(os.uname()[1]))

        super(HTTPDServer, self).__init__(**kwargs)

        self.document_root = document_root or self.workspace
        self.document_root = Path(self.document_root)
        self.log_dir = log_dir or self.workspace / 'logs'
        self.log_dir = Path(self.log_dir)

    def pre_setup(self):
        """ Write out the config file
        """
        self.config = self.workspace / 'httpd.conf'
        rules = []
        for source in self.proxy_rules:
            rules.append("ProxyPass {0} {1}".format(source, self.proxy_rules[source]))
            rules.append("ProxyPassReverse {0} {1} \n".format(source, self.proxy_rules[source]))
        cfg = self.cfg_template.substitute(
            server_root=self.workspace,
            document_root=self.document_root,
            log_dir=self.log_dir,
            listen_addr="{host}:{port}".format(host=self.hostname, port=self.port),
            proxy_rules='\n'.join(rules),
            modules=CONFIG.httpd_modules,
        )
        self.config.write_text(cfg)
        log.debug("=========== HTTPD Server Config =============\n{}".format(cfg))

        # This is where it stores PID files
        (self.workspace / 'run').mkdir()
        if not os.path.exists(self.log_dir):
            self.log_dir.mkdir()

    @property
    def run_cmd(self):
        return [CONFIG.httpd_executable, '-f', self.config]
<commit_msg>fix httpd module load<commit_after>import os
import socket
import string
import logging

import pytest
try:
    from path import Path
except ImportError:
    from path import path as Path

from pytest_fixture_config import yield_requires_config
from pytest_server_fixtures import CONFIG

from .http import HTTPTestServer

log = logging.getLogger(__name__)

@pytest.yield_fixture(scope='function')
@yield_requires_config(CONFIG, ['httpd_executable', 'httpd_modules'])
def httpd_server():
    """ Function-scoped httpd server in a local thread.

        Methods
        -------
        get()   : Query url relative to the server root.
        ..        Parse as json and retry failures by default.
        post()  : Post payload to url relative to the server root.
        ..        Parse as json and retry failures by default.
    """
    test_server = HTTPDServer()
    test_server.start()
    yield test_server
    test_server.teardown()

class HTTPDServer(HTTPTestServer):
    port_seed = 65531

    cfg_modules_template = """
      LoadModule headers_module $modules/mod_headers.so
      LoadModule proxy_module $modules/mod_proxy.so
      LoadModule proxy_http_module $modules/mod_proxy_http.so
      LoadModule proxy_connect_module $modules/mod_proxy_connect.so
      LoadModule alias_module $modules/mod_alias.so
      LoadModule dir_module $modules/mod_dir.so
      LoadModule autoindex_module $modules/mod_autoindex.so
      <IfModule !mod_log_config.c>
          LoadModule log_config_module $modules/mod_log_config.so
      </IfModule>
      LoadModule mime_module $modules/mod_mime.so
      LoadModule authz_core_module $modules/mod_authz_core.so
    """

    cfg_mpm_template = """
      LoadModule mpm_prefork_module $modules/mod_mpm_prefork.so
      LoadModule unixd_module $modules/mod_unixd.so
      StartServers       1
      MinSpareServers    1
      MaxSpareServers   4
      ServerLimit      4
      MaxClients       4
      MaxRequestsPerChild  10000
    """

    cfg_template = """
      TypesConfig /etc/mime.types

      ServerRoot $server_root
      Listen $listen_addr
      PidFile $server_root/run/httpd.pid

      ErrorLog $log_dir/error.log
      LogFormat "%h %l %u %t \\"%r\\" %>s %b" common
      CustomLog $log_dir/access.log common
      LogLevel info

      $proxy_rules

      Alias / $document_root/

      <Directory $server_root>
          Options +Indexes
      </Directory>
    """

    def __init__(self, proxy_rules=None, extra_cfg='', document_root=None, log_dir=None, **kwargs):
        """ httpd Proxy Server

        Parameters
        ----------
        proxy_rules: `dict`
            { proxy_src: proxy_dest }. Eg   {'/downstream_url/' : server.uri}
        extra_cfg: `str`
            Any extra Apache config
        document_root : `str`
            Server document root, defaults to temporary workspace
        log_dir : `str`
            Server log directory, defaults to $(workspace)/logs
        """
        self.proxy_rules = proxy_rules if proxy_rules is not None else {}
        self.cfg_template = string.Template(self.cfg_modules_template +
                                            self.cfg_mpm_template +
                                            self.cfg_template +
                                            extra_cfg)

        # Always print debug output for this process
        os.environ['DEBUG'] = '1'

        # Discover externally accessable hostname so selenium can get to it
        kwargs['hostname'] = kwargs.get('hostname', socket.gethostbyname(os.uname()[1]))

        super(HTTPDServer, self).__init__(**kwargs)

        self.document_root = document_root or self.workspace
        self.document_root = Path(self.document_root)
        self.log_dir = log_dir or self.workspace / 'logs'
        self.log_dir = Path(self.log_dir)

    def pre_setup(self):
        """ Write out the config file
        """
        self.config = self.workspace / 'httpd.conf'
        rules = []
        for source in self.proxy_rules:
            rules.append("ProxyPass {0} {1}".format(source, self.proxy_rules[source]))
            rules.append("ProxyPassReverse {0} {1} \n".format(source, self.proxy_rules[source]))
        cfg = self.cfg_template.substitute(
            server_root=self.workspace,
            document_root=self.document_root,
            log_dir=self.log_dir,
            listen_addr="{host}:{port}".format(host=self.hostname, port=self.port),
            proxy_rules='\n'.join(rules),
            modules=CONFIG.httpd_modules,
        )
        self.config.write_text(cfg)
        log.debug("=========== HTTPD Server Config =============\n{}".format(cfg))

        # This is where it stores PID files
        (self.workspace / 'run').mkdir()
        if not os.path.exists(self.log_dir):
            self.log_dir.mkdir()

    @property
    def run_cmd(self):
        return [CONFIG.httpd_executable, '-f', self.config]
<|endoftext|>


<commit_before># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal, QUrl
from PyQt5.QtGui import QDesktopServices

from UM.Application import Application
from UM.Logger import Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.PointCloudNode import PointCloudNode
from UM.Mesh.MeshData import MeshType
from UM.Mesh.ReadMeshJob import ReadMeshJob
from UM.Mesh.WriteMeshJob import WriteMeshJob
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Message import Message

import os.path
import platform

from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("uranium")

class MeshFileHandlerProxy(QObject):
    def __init__(self, parent = None):
        super().__init__(parent)
        self._mesh_handler = Application.getInstance().getMeshFileHandler()
        self._scene = Application.getInstance().getController().getScene()

    @pyqtProperty("QStringList", constant=True)
    def supportedReadFileTypes(self):
        file_types = []
        all_types = []

        if platform.system() == "Linux":
            for ext, desc in self._mesh_handler.getSupportedFileTypesRead().items():
                file_types.append("{0} (*.{1} *.{2})".format(desc, ext.lower(), ext.upper()))
                all_types.append("*.{0} *.{1}".format(ext.lower(), ext.upper()))
        else:
            for ext, desc in self._mesh_handler.getSupportedFileTypesRead().items():
                file_types.append("{0} (*.{1})".format(desc, ext))
                all_types.append("*.{0}".format(ext))

        file_types.sort()
        file_types.insert(0, i18n_catalog.i18nc("@item:inlistbox", "All Supported Types ({0})".format(" ".join(all_types))))
        file_types.append(i18n_catalog.i18nc("@item:inlistbox", "All Files (*)"))

        return file_types

    @pyqtProperty("QStringList", constant=True)
    def supportedWriteFileTypes(self):
        file_types = []

        for item in self._mesh_handler.getSupportedFileTypesWrite():
            file_types.append("{0} (*.{1})".format(item["description"], item["extension"]))

        file_types.sort()

        return file_types

    @pyqtSlot(QUrl)
    def readLocalFile(self, file):
        if not file.isValid():
            return
        job = ReadMeshJob(file.toLocalFile())
        job.finished.connect(self._readMeshFinished)
        job.start()

    def _readMeshFinished(self, job):
        node = job.getResult()
        if node != None:
            node.setSelectable(True)
            node.setName(os.path.basename(job.getFileName()))

            op = AddSceneNodeOperation(node, self._scene.getRoot())
            op.push()

            self._scene.sceneChanged.emit(node)

def createMeshFileHandlerProxy(engine, script_engine):
    return MeshFileHandlerProxy()
<commit_msg>Fix translation of file dialogue<commit_after># Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal, QUrl
from PyQt5.QtGui import QDesktopServices

from UM.Application import Application
from UM.Logger import Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Scene.PointCloudNode import PointCloudNode
from UM.Mesh.MeshData import MeshType
from UM.Mesh.ReadMeshJob import ReadMeshJob
from UM.Mesh.WriteMeshJob import WriteMeshJob
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Message import Message

import os.path
import platform

from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("uranium")

class MeshFileHandlerProxy(QObject):
    def __init__(self, parent = None):
        super().__init__(parent)
        self._mesh_handler = Application.getInstance().getMeshFileHandler()
        self._scene = Application.getInstance().getController().getScene()

    @pyqtProperty("QStringList", constant=True)
    def supportedReadFileTypes(self):
        file_types = []
        all_types = []

        if platform.system() == "Linux":
            for ext, desc in self._mesh_handler.getSupportedFileTypesRead().items():
                file_types.append("{0} (*.{1} *.{2})".format(desc, ext.lower(), ext.upper()))
                all_types.append("*.{0} *.{1}".format(ext.lower(), ext.upper()))
        else:
            for ext, desc in self._mesh_handler.getSupportedFileTypesRead().items():
                file_types.append("{0} (*.{1})".format(desc, ext))
                all_types.append("*.{0}".format(ext))

        file_types.sort()
        file_types.insert(0, i18n_catalog.i18nc("@item:inlistbox", "All Supported Types ({0})", " ".join(all_types)))
        file_types.append(i18n_catalog.i18nc("@item:inlistbox", "All Files (*)"))

        return file_types

    @pyqtProperty("QStringList", constant=True)
    def supportedWriteFileTypes(self):
        file_types = []

        for item in self._mesh_handler.getSupportedFileTypesWrite():
            file_types.append("{0} (*.{1})".format(item["description"], item["extension"]))

        file_types.sort()

        return file_types

    @pyqtSlot(QUrl)
    def readLocalFile(self, file):
        if not file.isValid():
            return
        job = ReadMeshJob(file.toLocalFile())
        job.finished.connect(self._readMeshFinished)
        job.start()

    def _readMeshFinished(self, job):
        node = job.getResult()
        if node != None:
            node.setSelectable(True)
            node.setName(os.path.basename(job.getFileName()))

            op = AddSceneNodeOperation(node, self._scene.getRoot())
            op.push()

            self._scene.sceneChanged.emit(node)

def createMeshFileHandlerProxy(engine, script_engine):
    return MeshFileHandlerProxy()
<|endoftext|>


<commit_before>""" Core Bot Functions """
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#

# Import Libraries
import os
import logging
from telegram.ext import Updater, CommandHandler
from bot import gov
from bot import draw
from bot import promo

# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)

logger = logging.getLogger(__name__)

"""Response
weather - Get Latest Weather Report
psi - Get Latest PSI Report
traffic - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
4d - Get Latest 4D Draw Results
ridepromos - Get Latest Promos from Uber/Grab
"""

def fourdresults(bot, update):
    """ Send results from 4D """
    final_string = draw.FourD()
    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def taxipromos(bot, update):
    """ Get Latest taxipromos """

    text_ = "<b> Latest Uber Promo Codes </b> \n\n"
    text_ += promo.get_code(1)
    text_ += "\n<b> Latest Grab Promo Codes </b> \n\n"
    text_ += promo.get_code(0)

    bot.sendMessage(update.message.chat_id, text=text_, parse_mode='HTML')

def traffic(bot, update, args):
    """ Get Traffic Updates """

    if len(args) == 0:
        final_string = 'Please enter either traffic Woodlands or traffic Tuas'
    else:
        final_string = gov.traffic_get(args[0])
    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def psi3hour(bot, update):
    """ Get Latest Singapore PSI """

    final_string = gov.psi3hour_get()
    bot.sendMessage(update.message.chat_id, text=final_string)

def weathernow(bot, update):
    """ Get Latest Singapore Weather """
    final_string = gov.weathernow_get()

    bot.sendMessage(update.message.chat_id, text=final_string)

def start(bot, update):
    """ Start Text """
    bot.sendMessage(update.message.chat_id,
                    text='''Hello! I am @ShiokBot!
                     \nThe helpful singlish spouting bot!
                     \n\nAvailable Commands
                     \n/psi - Report the latest PSI readings lo
                     \n/weather - Report the latest weather lah
                     \n/4d - Give you latest 4d results wor
                     \n/ridepromos - Help you save money give you uber/grab codes
                     \n/traffic woodlands - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
                     ''')

def help(bot, update):
    """ Help Text"""
    bot.sendMessage(update.message.chat_id,
                    text='''Hello! I am @ShiokBot!
                     \nThe helpful singlish spouting bot!
                     \n\nAvailable Commands
                     \n/psi - Report the latest PSI readings lo
                     \n/weather - Report the latest weather lah
                     \n/4d - Give you latest 4d results wor
                     \n/ridepromos - Help you save money give you uber/grab codes
                     \n/traffic woodlands - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
                     ''')

def error(bot, update, error):
    """ Log Errors"""
    logger.warn('Update "%s" caused error "%s"' % (update, error))

def main():
    """ This is where the bot starts from! """

    # Create the EventHandler and pass it your bot's token.
    telegram = str(os.environ.get('TELEGRAM'))
    updater = Updater(telegram)

    # Get the dispatcher to register handlers
    dispatch = updater.dispatcher

    # on different commands - answer in Telegram
    dispatch.add_handler(CommandHandler("start", start))
    dispatch.add_handler(CommandHandler("help", help))
    dispatch.add_handler(CommandHandler("psi", psi3hour))
    dispatch.add_handler(CommandHandler("weather", weathernow))
    dispatch.add_handler(CommandHandler("4d", fourdresults))
    dispatch.add_handler(CommandHandler("ridepromos", taxipromos))
    dispatch.add_handler(CommandHandler("traffic", traffic, pass_args=True))

    # log all errors
    dispatch.add_error_handler(error)

    # Start the Bot
    """
    #DEV
    updater.start_polling()

    # Run the bot until the you presses Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()
    """

    #PROD
    port_number = int(os.environ.get('PORT', '5000'))
    updater.start_webhook(listen="0.0.0.0",
                          port=port_number,
                          url_path=telegram)
    updater.bot.setWebhook("https://shiokbot.herokuapp.com/" + telegram)
    updater.idle()

if __name__ == '__main__':
    main()
<commit_msg>send html message<commit_after>""" Core Bot Functions """
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#

# Import Libraries
import os
import logging
from telegram.ext import Updater, CommandHandler
from bot import gov
from bot import draw
from bot import promo

# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)

logger = logging.getLogger(__name__)

"""Response
weather - Get Latest Weather Report
psi - Get Latest PSI Report
traffic - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
4d - Get Latest 4D Draw Results
ridepromos - Get Latest Promos from Uber/Grab
"""

def fourdresults(bot, update):
    """ Send results from 4D """
    final_string = draw.FourD()
    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def taxipromos(bot, update):
    """ Get Latest taxipromos """

    text_ = "<b> Latest Uber Promo Codes </b> \n\n"
    text_ += promo.get_code(1)
    text_ += "\n<b> Latest Grab Promo Codes </b> \n\n"
    text_ += promo.get_code(0)

    bot.sendMessage(update.message.chat_id, text=text_, parse_mode='HTML')

def traffic(bot, update, args):
    """ Get Traffic Updates """

    if len(args) == 0:
        final_string = 'Please enter either traffic Woodlands or traffic Tuas'
    else:
        final_string = gov.traffic_get(args[0])
    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def psi3hour(bot, update):
    """ Get Latest Singapore PSI """

    final_string = gov.psi3hour_get()
    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def weathernow(bot, update):
    """ Get Latest Singapore Weather """
    final_string = gov.weathernow_get()

    bot.sendMessage(update.message.chat_id, text=final_string, parse_mode='HTML')

def start(bot, update):
    """ Start Text """
    bot.sendMessage(update.message.chat_id,
                    text='''Hello! I am @ShiokBot!
                     \nThe helpful singlish spouting bot!
                     \n\nAvailable Commands
                     \n/psi - Report the latest PSI readings lo
                     \n/weather - Report the latest weather lah
                     \n/4d - Give you latest 4d results wor
                     \n/ridepromos - Help you save money give you uber/grab codes
                     \n/traffic woodlands - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
                     ''')

def help(bot, update):
    """ Help Text"""
    bot.sendMessage(update.message.chat_id,
                    text='''Hello! I am @ShiokBot!
                     \nThe helpful singlish spouting bot!
                     \n\nAvailable Commands
                     \n/psi - Report the latest PSI readings lo
                     \n/weather - Report the latest weather lah
                     \n/4d - Give you latest 4d results wor
                     \n/ridepromos - Help you save money give you uber/grab codes
                     \n/traffic woodlands - Get Latest Woodlands or Tuas Traffic Image. Example traffic Tuas
                     ''')

def error(bot, update, error):
    """ Log Errors"""
    logger.warn('Update "%s" caused error "%s"' % (update, error))

def main():
    """ This is where the bot starts from! """

    # Create the EventHandler and pass it your bot's token.
    telegram = str(os.environ.get('TELEGRAM'))
    updater = Updater(telegram)

    # Get the dispatcher to register handlers
    dispatch = updater.dispatcher

    # on different commands - answer in Telegram
    dispatch.add_handler(CommandHandler("start", start))
    dispatch.add_handler(CommandHandler("help", help))
    dispatch.add_handler(CommandHandler("psi", psi3hour))
    dispatch.add_handler(CommandHandler("weather", weathernow))
    dispatch.add_handler(CommandHandler("4d", fourdresults))
    dispatch.add_handler(CommandHandler("ridepromos", taxipromos))
    dispatch.add_handler(CommandHandler("traffic", traffic, pass_args=True))

    # log all errors
    dispatch.add_error_handler(error)

    # Start the Bot
    """
    #DEV
    updater.start_polling()

    # Run the bot until the you presses Ctrl-C or the process receives SIGINT,
    # SIGTERM or SIGABRT. This should be used most of the time, since
    # start_polling() is non-blocking and will stop the bot gracefully.
    updater.idle()
    """

    #PROD
    port_number = int(os.environ.get('PORT', '5000'))
    updater.start_webhook(listen="0.0.0.0",
                          port=port_number,
                          url_path=telegram)
    updater.bot.setWebhook("https://shiokbot.herokuapp.com/" + telegram)
    updater.idle()

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