<filename>pyontutils/scigraph_client.py
#!/usr/bin/env python3
"""WARNING: DO NOT MODIFY THIS FILE
IT IS AUTOMATICALLY GENERATED BY scigraph.py
AND WILL BE OVERWRITTEN
Swagger Version: 2.0, API Version: 1.0.1
generated for http://localhost:9000/scigraph/swagger.json
by scigraph.py
"""
import re
import builtins
import requests
from ast import literal_eval
from json import dumps
from urllib import parse

BASEPATH = 'https://scicrunch.org/api/1/scigraph'

exten_mapping = {'application/graphml+xml': 'graphml+xml', 'application/graphson': 'graphson', 'application/javascript': 'javascript', 'application/json': 'json', 'application/xgmml': 'xgmml', 'application/xml': 'xml', 'image/jpeg': 'jpeg', 'image/png': 'png', 'text/csv': 'csv', 'text/gml': 'gml', 'text/html': 'html', 'text/plain': 'plain', 'text/plain; charset=utf-8': 'plain; charset=utf-8', 'text/tab-separated-values': 'tab-separated-values'}

class restService:
    """ Base class for SciGraph rest services. """

    _api_key = None

    def __init__(self, cache=False, key=None):
        self._session = requests.Session()
        adapter = requests.adapters.HTTPAdapter(pool_connections=1000, pool_maxsize=1000)
        self._session.mount('http://', adapter)

        if cache:
            #print('WARNING: cache enabled, if you mutate the contents of return values you will mutate the cache!')
            self._cache = dict()
            self._get = self._cache_get
        else:
            self._get = self._normal_get

        self.api_key = key

    @property
    def api_key(self):
        return self._api_key

    @api_key.setter
    def api_key(self, value):
        self._api_key = value

    def __del__(self):
        self._session.close()

    def _safe_url(self, url):
        return url.replace(self.api_key, '[secure]') if self.api_key else url

    @property
    def _last_url(self):
        return self._safe_url(self.__last_url)

    def _normal_get(self, method, url, params=None, output=None):
        s = self._session
        if self.api_key is not None:
            params['key'] = self.api_key
        if method == 'POST':
            req = requests.Request(method=method, url=url, data=params)
        else:
            req = requests.Request(method=method, url=url, params=params)
        if output:
            req.headers['Accept'] = output
        prep = req.prepare()
        if self._verbose: print(self._safe_url(prep.url))
        try:
            resp = s.send(prep)
            self.__last_url = resp.url
        except requests.exceptions.ConnectionError as e:
            host_port = prep.url.split(prep.path_url)[0]
            raise ConnectionError(f'Could not connect to {host_port}. '
                                  'Are SciGraph services running?') from e
        if resp.status_code == 401:
            raise ConnectionError(f'{resp.reason}. '
                                  f'Did you set {self.__class__.__name__}.api_key'
                                  ' = my_api_key?')
        elif not resp.ok:
            return None
        elif resp.headers['content-type'] == 'application/json':
            return resp.json()
        elif resp.headers['content-type'].startswith('text/plain'):
            return resp.text
        else:
            return resp

    def _cache_get(self, method, url, params=None, output=None):
        if params:
            pkey = '?' + '&'.join(['%s=%s' % (k,v) for k,v in sorted(params.items()) if v is not None])
        else:
            pkey = ''
        key = url + pkey + ' ' + method + ' ' + str(output)
        if  key in self._cache:
            if self._verbose:
                print('cache hit', key)
            self.__last_url, resp = self._cache[key]
        else:
            resp = self._normal_get(method, url, params, output)
            self._cache[key] = self.__last_url, resp

        return resp

    def _make_rest(self, default=None, **kwargs):
        kwargs = {k:v for k, v in kwargs.items() if v}
        param_rest = '&'.join(['%s={%s}' % (arg, arg) for arg in kwargs if arg != default])
        param_rest = param_rest if param_rest else ''
        return param_rest


class Analyzer(restService):
    """ Analysis services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def enrich(self, sample, ontologyClass, path, callback=None, output='application/json'):
        """ Class Enrichment Service from: /analyzer/enrichment

            Arguments:
            sample: A list of CURIEs for nodes whose attributes are to be tested for
                    enrichment. For example, a list of genes.
            ontologyClass: CURIE for parent ontology class for the attribute to be tested.
                           For example, GO biological process
            path: A path expression that connects sample nodes to attribute class nodes
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
        """

        kwargs = {'sample': sample, 'ontologyClass': ontologyClass, 'path': path, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/analyzer/enrichment').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def enrichPost(self, output='application/json'):
        """  from: /analyzer/enrichment

            Arguments:

            outputs:
                application/json
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/analyzer/enrichment').format(**kwargs)
        requests_params = kwargs
        output = self._get('POST', url, requests_params, output)
        return output if output else []


class Annotations(restService):
    """ Annotation services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def annotate(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, output='text/plain; charset=utf-8'):
        """ Annotate text from: /annotations

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            outputs:
                text/plain; charset=utf-8
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def annotatePost(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, ignoreTag=None, stylesheet=None, scripts=None, targetId=None, targetClass=None, output='application/json'):
        """ Annotate text from: /annotations

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            ignoreTag: HTML tags that should not be annotated
            stylesheet: CSS stylesheets to add to the HEAD
            scripts: JavaScripts that should to add to the HEAD
            targetId: A set of element IDs to annotate
            targetClass: A set of CSS class names to annotate
            outputs:
                application/json
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers, 'ignoreTag': ignoreTag, 'stylesheet': stylesheet, 'scripts': scripts, 'targetId': targetId, 'targetClass': targetClass}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations').format(**kwargs)
        requests_params = kwargs
        output = self._get('POST', url, requests_params, output)
        return output if output else None

    def getEntitiesAndContent(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, output='application/json'):
        """ Get embedded annotations as well as a separate list from: /annotations/complete

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            outputs:
                application/json
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations/complete').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def postEntitiesAndContent(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, output='application/json'):
        """ Get embedded annotations as well as a separate list from: /annotations/complete

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            outputs:
                application/json
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations/complete').format(**kwargs)
        requests_params = kwargs
        output = self._get('POST', url, requests_params, output)
        return output if output else []

    def getEntities(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, output='application/json'):
        """ Get entities from text from: /annotations/entities

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            outputs:
                application/json
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations/entities').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def postEntities(self, content, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, output='application/json'):
        """ Get entities from text from: /annotations/entities

            Arguments:
            content: The content to annotate
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            outputs:
                application/json
        """

        kwargs = {'content': content, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations/entities').format(**kwargs)
        requests_params = kwargs
        output = self._get('POST', url, requests_params, output)
        return output if output else []

    def annotateUrl(self, url, includeCat=None, excludeCat=None, minLength=None, longestOnly=None, includeAbbrev=None, includeAcronym=None, includeNumbers=None, ignoreTag=None, stylesheet=None, scripts=None, targetId=None, targetClass=None, output='text/html'):
        """ Annotate a URL from: /annotations/url

            Arguments:
            url:
            includeCat: A set of categories to include
            excludeCat: A set of categories to exclude
            minLength: The minimum number of characters in annotated entities
            longestOnly: Should only the longest entity be returned for an overlapping group
            includeAbbrev: Should abbreviations be included
            includeAcronym: Should acronyms be included
            includeNumbers: Should numbers be included
            ignoreTag: HTML tags that should not be annotated
            stylesheet: CSS stylesheets to add to the HEAD
            scripts: JavaScripts that should to add to the HEAD
            targetId: A set of element IDs to annotate
            targetClass: A set of CSS class names to annotate
            outputs:
                text/html
        """

        if url and url.startswith('http:'):
            url = parse.quote(url, safe='')
        kwargs = {'url': url, 'includeCat': includeCat, 'excludeCat': excludeCat, 'minLength': minLength, 'longestOnly': longestOnly, 'includeAbbrev': includeAbbrev, 'includeAcronym': includeAcronym, 'includeNumbers': includeNumbers, 'ignoreTag': ignoreTag, 'stylesheet': stylesheet, 'scripts': scripts, 'targetId': targetId, 'targetClass': targetClass}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/annotations/url').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None


class CypherBase(restService):
    """ Cypher utility services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def getCuries(self, callback=None, output='application/json'):
        """ Get the curie map from: /cypher/curies

            Arguments:
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
        """

        kwargs = {'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/cypher/curies').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else {}

    def execute(self, cypherQuery, limit, output='text/plain'):
        """ Execute an arbitrary Cypher query. from: /cypher/execute

            Arguments:
            cypherQuery: The cypher query to execute
            limit: Limit
            outputs:
                text/plain
                application/json
        """

        kwargs = {'cypherQuery': cypherQuery, 'limit': limit}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/cypher/execute').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def resolve(self, cypherQuery, output='text/plain'):
        """ Cypher query resolver from: /cypher/resolve

            Arguments:
            cypherQuery: The cypher query to resolve
            outputs:
                text/plain
        """

        kwargs = {'cypherQuery': cypherQuery}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/cypher/resolve').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None


class Cypher(CypherBase):
    @staticmethod
    def fix_quotes(string, s1=':["', s2='"],'):
        out = []
        def subsplit(sstr, s=s2):
            #print(s)
            if s == '",' and sstr.endswith('"}'):  # special case for end of record
                s = '"}'
            if s:
                string, *rest = sstr.rsplit(s, 1)
            else:
                string = sstr
                rest = '',

            if rest:
                #print('>>>>', string)
                #print('>>>>', rest)
                r, = rest
                if s == '"],':
                    fixed_string = Cypher.fix_quotes(string, '","', '') + s + r
                else:
                    fixed_string = string.replace('"', r'\"') + s + r

                return fixed_string

        for sub1 in string.split(s1):
            ss = subsplit(sub1)
            if ss is None:
                if s1 == ':["':
                    out.append(Cypher.fix_quotes(sub1, ':"', '",'))
                else:
                    out.append(sub1)
            else:
                out.append(ss)

        return s1.join(out)

    def fix_cypher(self, record):
        rep = re.sub(r'({|, )(\S+)(: "|: \[)', r'\1"\2"\3',
                     self.fix_quotes(record.strip()).
                     split(']', 1)[1] .
                     replace(':"', ': "') .
                     replace(':[', ': [') .
                     replace('",', '", ') .
                     replace('"],', '"], ') .
                     replace('\n', '\\n') .
                     replace('xml:lang="en"', r'xml:lang=\"en\"')
                    )
        try:
            value = {self.qname(k):v for k, v in literal_eval(rep).items()}
        except (ValueError, SyntaxError) as e:
            print(repr(record))
            print(repr(rep))
            raise e

        return value

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._setCuries()

    def _setCuries(self):
        try:
            self._curies = self.getCuries()
        except ConnectionError:
            self._curies = {}

        self._inv = {v:k for k, v in self._curies.items()}

    api_key = restService.api_key

    @api_key.setter
    def api_key(self, value):
        old_key = self.api_key
        self._api_key = value
        if old_key is None and value is not None:
            self._setCuries()

    def qname(self, iri):
        for prefix, curie in self._inv.items():
            if iri.startswith(prefix):
                return iri.replace(prefix, curie + ':')
        else:
            return iri

    def execute(self, query, limit, output='text/plain'):
        if output == 'text/plain':
            out = super().execute(query, limit, output)
            rows = []
            if out:
                for raw in out.split('|')[3:-1]:
                    record = raw.strip()
                    if record:
                        d = self.fix_cypher(record)
                        rows.append(d)

            return rows

        else:
            return super().execute(query, limit, output)


class DynamicBase(restService):
    """ Dynamic Cypher resources """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def prod_sparc_artifactLabels_artifact_id(self, artifact_id, output='application/json'):
        """ Get the graph of all parcellation labels for a single artifact WARNING this can return no results from: /dynamic/prod/sparc/artifactLabels/{artifact-id}

            Arguments:
            artifact_id: ontology id of the parcellation artifact

            Query:
            MATCH path = (label)
            -[:subClassOf]->(root)
            -[:ilxtr:isDefinedBy]->(a)<-[:subClassOf*0..2]
            -(artifact:Class{iri: "${artifact-id}"})
            WHERE label.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if artifact_id and artifact_id.startswith('http:'):
            artifact_id = parse.quote(artifact_id, safe='')
        kwargs = {'artifact_id': artifact_id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/artifactLabels/{artifact_id}').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_artifactRoots_artifact_id(self, artifact_id, output='application/json'):
        """ Get the graph of all parcellation label roots for a single artifact WARNING this can return no results from: /dynamic/prod/sparc/artifactRoots/{artifact-id}

            Arguments:
            artifact_id: ontology id of the parcellation artifact

            Query:
            MATCH path = (root)
            -[:ilxtr:isDefinedBy]->(a)<-[:subClassOf*0..2]
            -(artifact:Class{iri: "${artifact-id}"})
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if artifact_id and artifact_id.startswith('http:'):
            artifact_id = parse.quote(artifact_id, safe='')
        kwargs = {'artifact_id': artifact_id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/artifactRoots/{artifact_id}').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_organList(self, output='application/json'):
        """ Get the list of all FMA organ identifiers relevant to SPARC from: /dynamic/prod/sparc/organList

            Arguments:


            Query:
            MATCH (n)
            WHERE n.iri IN [
                    "http://purl.org/sig/ont/fma/fma7195",
                    "http://purl.org/sig/ont/fma/fma7088",
                    "http://purl.org/sig/ont/fma/fma7197",
                    "http://purl.org/sig/ont/fma/fma7198",
                    "http://purl.org/sig/ont/fma/fma7203",
                    "http://purl.org/sig/ont/fma/fma7148",
                    "http://purl.org/sig/ont/fma/fma7196",
                    "http://purl.org/sig/ont/fma/fma14543",
                    "http://purl.org/sig/ont/fma/fma7201",
                    "http://purl.org/sig/ont/fma/fma7200",
                    "http://purl.org/sig/ont/fma/fma15900",
                    "http://purl.org/sig/ont/fma/fma45659",
                    "http://purl.org/sig/ont/fma/fma7647"]
            RETURN n
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/organList').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_organParts_id(self, id, output='application/json'):
        """ Get the parts list for an organ including nerves and blood vessles from: /dynamic/prod/sparc/organParts/{id}

            Arguments:
            id: ontology id of the organ

            Query:
            MATCH path = (start:Class{iri: "${id}"})
            -[:fma:regional_part|fma:constitutional_part|fma:related_part*0..40]->(part)
            -[:fma:arterial_supply|fma:nerve_supply*0..1]->(sup)
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        kwargs = {'id': id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/organParts/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_parcellationArtifacts(self, output='application/json'):
        """ Get the graph of all parcellation artifacts for all species from: /dynamic/prod/sparc/parcellationArtifacts

            Arguments:


            Query:
            MATCH path = (artifact)
            -[:subClassOf*0..2]->(parent)
            -[:ilxtr:isDefinedInTaxon]->(species)
            WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/parcellationArtifacts').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_parcellationArtifacts_species_id(self, species_id, output='application/json'):
        """ Get the graph of all parcellation artifacts for a single species from: /dynamic/prod/sparc/parcellationArtifacts/{species-id}

            Arguments:
            species_id: ontology id of the species

            Query:
            MATCH (parent)
            -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"})
            WITH parent
            MATCH path = (artifact)
            -[:subClassOf*0..2]->(parent)
            WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if species_id and species_id.startswith('http:'):
            species_id = parse.quote(species_id, safe='')
        kwargs = {'species_id': species_id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/parcellationArtifacts/{species_id}').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_parcellationGraph(self, output='application/json'):
        """ Get the graph of all parcellation labels for all species from: /dynamic/prod/sparc/parcellationGraph

            Arguments:


            Query:
            MATCH path = (artifact)
            -[:subClassOf*0..2]->(parent)
            -[:ilxtr:isDefinedInTaxon]->(species)
            WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            return path
            UNION
            MATCH path = (maybe)
            -[relation*0..1]-(label)
            -[:subClassOf]->(root)
            -[:ilxtr:isDefinedBy]->(artifact)
            -[:subClassOf*0..2]->(parent)
            -[:ilxtr:isDefinedInTaxon]->(species)
            WHERE NONE (r in relation WHERE type(r) IN ["isDefinedBy", "subClassOf", "filler"])
                  AND NOT (label.iri =~ ".*_:.*") AND NOT (maybe.iri =~ ".*_:.*")
                  AND label.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/parcellationGraph').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_parcellationRoots(self, output='application/json'):
        """ Get the graph of all parcellation label roots for all species from: /dynamic/prod/sparc/parcellationRoots

            Arguments:


            Query:
            MATCH path = (artifact)
            -[:subClassOf*0..2]->(parent)
            -[:ilxtr:isDefinedInTaxon]->(species)
            WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            return path
            UNION
            MATCH path = (root)
            -[:ilxtr:isDefinedBy]->(artifact)
            -[:subClassOf*0..2]->(parent)
            -[:ilxtr:isDefinedInTaxon]->(species)
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/parcellationRoots').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_parcellationRoots_species_id(self, species_id, output='application/json'):
        """ Get the graph of all parcellation label roots for a single species from: /dynamic/prod/sparc/parcellationRoots/{species-id}

            Arguments:
            species_id: ontology id of the species

            Query:
            MATCH (parent)
            -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"})
            WITH parent
            MATCH path = (artifact)
            -[:subClassOf*0..2]->(parent)
            WHERE artifact.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            return path
            UNION
            MATCH (parent)
            -[:ilxtr:isDefinedInTaxon]->(species:Class{iri: "${species-id}"})
            WITH parent
            MATCH path = (root)
            -[:ilxtr:isDefinedBy]->(artifact)
            -[:subClassOf*0..2]->(parent)
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if species_id and species_id.startswith('http:'):
            species_id = parse.quote(species_id, safe='')
        kwargs = {'species_id': species_id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/parcellationRoots/{species_id}').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_rootLabels_root_id(self, root_id, output='application/json'):
        """ Get the list of all parcellation labels for a single label root from: /dynamic/prod/sparc/rootLabels/{root-id}

            Arguments:
            root_id: ontology id of the parcellation label root

            Query:
            MATCH (label)-[:subClassOf]->(root:Class{iri: "${root-id}"})
            WITH label
            MATCH path = (label)-[relation*0..1]-(maybe)
            WHERE NONE (r in relation WHERE type(r) IN ["isDefinedBy", "subClassOf", "filler"])
                  AND NOT (label.iri =~ ".*_:.*") AND NOT (maybe.iri =~ ".*_:.*")
                  AND label.iri <> "http://www.w3.org/2002/07/owl#Nothing"
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if root_id and root_id.startswith('http:'):
            root_id = parse.quote(root_id, safe='')
        kwargs = {'root_id': root_id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/rootLabels/{root_id}').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def prod_sparc_speciesList(self, output='application/json'):
        """ Get the list of all NCBITaxon species identifiers relevant to SPARC from: /dynamic/prod/sparc/speciesList

            Arguments:


            Query:
            MATCH (n)
            WHERE n.iri IN [
                    "http://purl.obolibrary.org/obo/NCBITaxon_9378",
                    "http://purl.obolibrary.org/obo/NCBITaxon_9606",
                    "http://purl.obolibrary.org/obo/NCBITaxon_9685",
                    "http://purl.obolibrary.org/obo/NCBITaxon_9823",
                    "http://purl.obolibrary.org/obo/NCBITaxon_10090",
                    "http://purl.obolibrary.org/obo/NCBITaxon_10116"]
            RETURN n
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/prod/sparc/speciesList').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def shortestSimple(self, start_id=None, end_id=None, max_depth=None, relationship=None, output='application/json'):
        """ Get the shortest path between two IDs from: /dynamic/shortestSimple

            Arguments:
            start_id: The starting node (ex UBERON:0005751)
            end_id: The ending node (ex UBERON:0001255)
            max_depth: the maximum depth to traverse
            relationship: The property to traverse (ex subClassOf or subClassOf|partOf|isA)

            Query:
            MATCH (start:Class{iri: '${start_id}'})
            WITH start
            MATCH (end:Class{iri: '${end_id}'})
            WITH start, end
            MATCH path = shortestPath((start)-[:${relationship}*..${max_depth}]->(end))
            RETURN path
            
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if start_id and start_id.startswith('http:'):
            start_id = parse.quote(start_id, safe='')
        if end_id and end_id.startswith('http:'):
            end_id = parse.quote(end_id, safe='')
        if relationship and relationship.startswith('http:'):
            relationship = parse.quote(relationship, safe='')
        kwargs = {'start_id': start_id, 'end_id': end_id, 'max_depth': max_depth, 'relationship': relationship}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/dynamic/shortestSimple').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None


class Dynamic(DynamicBase):

    @staticmethod
    def _path_to_id(path):
        return (path.strip('/')
                .replace('dynamic/', '')
                .replace('{', '')
                .replace('}', '')
                .replace('/', '_')
                .replace('-', '_'))

    def _path_function_arg(self, path):
        if '?' in path:
            path, query = path.split('?', 1)

        if '.' in path:
            raise ValueError('extensions not supported directly please use output=mimetype')

        if ':' in path:  # curie FIXME way more potential arguments here ...
            path, arg = path.rsplit('/', 1)
            putative = self._path_to_id(path + '/{')
            cands = [p for p in dir(self) if p.startswith(putative)]
            fname = cands[0] if len(cands) == 1 else '___wat'
        else:
            arg = None
            fname = self._path_to_id(path)

        if not hasattr(self, fname):
            raise TypeError(f'{self._basePath} does not have endpoint {path} -> {fname!r}')

        return getattr(self, fname), arg

    def dispatch(self, path, output='application/json', **kwargs):
        f, a = self._path_function_arg(path)
        return f(a, output=output, **kwargs) if a else f(output=output, **kwargs)


class GraphBase(restService):
    """ Graph services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def getEdges(self, type, entail=None, limit=None, skip=None, callback=None, output='application/json'):
        """ Get nodes connected by an edge type from: /graph/edges/{type}

            Arguments:
            type: The type of the edge
            entail: Should subproperties and equivalent properties be included
            limit: The number of edges to be returned
            skip: The number of edges to skip
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if type and type.startswith('http:'):
            type = parse.quote(type, safe='')
        kwargs = {'type': type, 'entail': entail, 'limit': limit, 'skip': skip, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('type', **kwargs)
        url = self._basePath + ('/graph/edges/{type}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'type'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def getNeighborsFromMultipleRoots(self, id, depth=None, blankNodes=None, relationshipType=None, direction=None, entail=None, project=None, callback=None, output='application/json'):
        """ Get neighbors from: /graph/neighbors

            Arguments:
            id: This ID should be either a CURIE or an IRI
            depth: How far to traverse neighbors
            blankNodes: Traverse blank nodes
            relationshipType: Which relationship to traverse
            direction: Which direction to traverse: INCOMING, OUTGOING, BOTH (default).
                       Only used if relationshipType is specified.
            entail: Should subproperties and equivalent properties be included
            project: Which properties to project. Defaults to '*'.
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        if relationshipType and relationshipType.startswith('http:'):
            relationshipType = parse.quote(relationshipType, safe='')
        kwargs = {'id': id, 'depth': depth, 'blankNodes': blankNodes, 'relationshipType': relationshipType, 'direction': direction, 'entail': entail, 'project': project, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/graph/neighbors').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def getNeighbors(self, id, depth=None, blankNodes=None, relationshipType=None, direction=None, entail=None, project=None, callback=None, output='application/json'):
        """ Get neighbors from: /graph/neighbors/{id}

            Arguments:
            id: This ID should be either a CURIE or an IRI
            depth: How far to traverse neighbors
            blankNodes: Traverse blank nodes
            relationshipType: Which relationship to traverse
            direction: Which direction to traverse: INCOMING, OUTGOING, BOTH (default).
                       Only used if relationshipType is specified.
            entail: Should subproperties and equivalent properties be included
            project: Which properties to project. Defaults to '*'.
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        if relationshipType and relationshipType.startswith('http:'):
            relationshipType = parse.quote(relationshipType, safe='')
        kwargs = {'id': id, 'depth': depth, 'blankNodes': blankNodes, 'relationshipType': relationshipType, 'direction': direction, 'entail': entail, 'project': project, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/graph/neighbors/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def getProperties(self, callback=None, output='application/json'):
        """ Get all property keys from: /graph/properties

            Arguments:
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
        """

        kwargs = {'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/graph/properties').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def reachableFrom(self, id, hint=None, relationships=None, lbls=None, callback=None, output='application/json'):
        """ Get all the nodes reachable from a starting point, traversing the provided edges. from: /graph/reachablefrom/{id}

            Arguments:
            id: The type of the edge
            hint: A label hint to find the start node.
            relationships: A list of relationships to traverse, in order. Supports cypher
                           operations such as relA|relB or relA*.
            lbls: A list of node labels to filter.
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        if relationships and relationships.startswith('http:'):
            relationships = parse.quote(relationships, safe='')
        kwargs = {'id': id, 'hint': hint, 'relationships': relationships, 'lbls': lbls, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/graph/reachablefrom/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getRelationships(self, callback=None, output='application/json'):
        """ Get all relationship types from: /graph/relationship_types

            Arguments:
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
        """

        kwargs = {'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/graph/relationship_types').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getNode(self, id, project=None, callback=None, output='application/json'):
        """ Get all properties of a node from: /graph/{id}

            Arguments:
            id: This ID should be either a CURIE or an IRI
            project: Which properties to project. Defaults to '*'.
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/graphson
                application/xml
                application/graphml+xml
                application/xgmml
                text/gml
                text/csv
                text/tab-separated-values
                image/jpeg
                image/png
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        kwargs = {'id': id, 'project': project, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/graph/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None


class Graph(GraphBase):
    @staticmethod
    def ordered(start, edges, predicate=None, inverse=False):
        """ Depth first edges from a SciGraph response. """
        s, o = 'sub', 'obj'
        if inverse:
            s, o = o, s
        for edge in edges:
            if predicate is not None and edge['pred'] != predicate:
                print('scoop!')
                continue

            if edge[s] == start:
                yield edge
                yield from Graph.ordered(edge[o], edges, predicate=predicate)


class Lexical(restService):
    """ Lexical services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def getChunks(self, text, output='application/json'):
        """ Extract entities from text. from: /lexical/chunks

            Arguments:
            text: The text from which to extract chunks
            outputs:
                application/json
        """

        kwargs = {'text': text}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/lexical/chunks').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getEntities(self, text, output='application/json'):
        """ Extract entities from text. from: /lexical/entities

            Arguments:
            text: The text from which to extract entities
            outputs:
                application/json
        """

        kwargs = {'text': text}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/lexical/entities').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getPos(self, text, output='application/json'):
        """ Tag parts of speech. from: /lexical/pos

            Arguments:
            text: The text to tag
            outputs:
                application/json
        """

        kwargs = {'text': text}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/lexical/pos').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getSentences(self, text, output='application/json'):
        """ Split text into sentences. from: /lexical/sentences

            Arguments:
            text: The text to split
            outputs:
                application/json
        """

        kwargs = {'text': text}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/lexical/sentences').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []


class Refine(restService):
    """ OpenRefine Reconciliation Services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def getPreview(self, id, output='application/json'):
        """  from: /refine/preview/{id}

            Arguments:
            id:
            outputs:
                application/json
                application/javascript
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        kwargs = {'id': id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/refine/preview/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def suggestFromTerm(self, query=None, queries=None, callback=None, output='application/json'):
        """ Reconcile terms from: /refine/reconcile

            Arguments:
            query: A call to a reconciliation service API for a single query looks
                   like either of these:<ul><li>
                   http://foo.com/bar/reconcile?query=...string...</li>
                   <li>http://foo.com/bar/reconcile?query={...json object
                   literal...}</li></ul>If the query parameter is a
                   string, then it's an abbreviation of <em>
                   query={"query":...string...}</em>.<em>NOTE:</em>
                    We encourage all API consumers to consider the single query
                   mode <b>DEPRECATED</b>.Refine currently only uses the
                   multiple query mode, but other consumers of the API may use the
                   single query option since it was included in the spec.
            queries: A call to a standard reconciliation service API for multiple
                     queries looks like this:<ul><li>
                     http://foo.com/bar/reconcile?queries={...json object
                     literal...}</li></ul>The json object literal has zero
                     or more key/value pairs with arbitrary keys where the value is in
                     the same format as a single query, e.g.<ul><li>
                     http://foo.com/bar/reconcile?queries={ "q0" : { "query" : "foo"
                     }, "q1" : { "query" : "bar" } }</li></ul>"q0" and
                     "q1" can be arbitrary strings.
            callback: Name of the JSONP callback ('fn' by default). Supplying this
                      parameter or requesting a javascript media type will cause a
                      JSONP response to be rendered.
            outputs:
                application/json
                application/javascript
        """

        kwargs = {'query': query, 'queries': queries, 'callback': callback}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/refine/reconcile').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def suggestFromTerm_POST(self, query=None, queries=None, output='application/json'):
        """ Reconcile terms from: /refine/reconcile

            Arguments:
            query: A call to a reconciliation service API for a single query looks
                   like either of these:<ul><li>
                   http://foo.com/bar/reconcile?query=...string...</li>
                   <li>http://foo.com/bar/reconcile?query={...json object
                   literal...}</li></ul>If the query parameter is a
                   string, then it's an abbreviation of <em>
                   query={"query":...string...}</em>.<em>NOTE:</em>
                    We encourage all API consumers to consider the single query
                   mode <b>DEPRECATED</b>.Refine currently only uses the
                   multiple query mode, but other consumers of the API may use the
                   single query option since it was included in the spec.
            queries: A call to a standard reconciliation service API for multiple
                     queries looks like this:<ul><li>
                     http://foo.com/bar/reconcile?queries={...json object
                     literal...}</li></ul>The json object literal has zero
                     or more key/value pairs with arbitrary keys where the value is in
                     the same format as a single query, e.g.<ul><li>
                     http://foo.com/bar/reconcile?queries={ "q0" : { "query" : "foo"
                     }, "q1" : { "query" : "bar" } }</li></ul>"q0" and
                     "q1" can be arbitrary strings.
            outputs:
                application/json
                application/javascript
        """

        kwargs = {'query': query, 'queries': queries}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/refine/reconcile').format(**kwargs)
        requests_params = kwargs
        output = self._get('POST', url, requests_params, output)
        return output if output else None

    def getView(self, id, output='application/json'):
        """  from: /refine/view/{id}

            Arguments:
            id:
            outputs:
                application/json
                application/javascript
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        kwargs = {'id': id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/refine/view/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None


class Vocabulary(restService):
    """ Vocabulary services """

    def __init__(self, basePath=None, verbose=False, cache=False, key=None):
        if basePath is None:
            basePath = BASEPATH
        self._basePath = basePath
        self._verbose = verbose
        super().__init__(cache, key)

    def findByPrefix(self, term, limit=None, searchSynonyms=None, searchAbbreviations=None, searchAcronyms=None, includeDeprecated=None, category=None, prefix=None, output='application/json'):
        """ Find a concept by its prefix from: /vocabulary/autocomplete/{term}

            Arguments:
            term: Term prefix to find
            limit: Maximum result count
            searchSynonyms: Should synonyms be matched
            searchAbbreviations: Should abbreviations be matched
            searchAcronyms: Should acronyms be matched
            includeDeprecated: Should deprecated classes be included
            category: Categories to search (defaults to all)
            prefix: CURIE prefixes to search (defaults to all)
            outputs:
                application/json
        """

        kwargs = {'term': term, 'limit': limit, 'searchSynonyms': searchSynonyms, 'searchAbbreviations': searchAbbreviations, 'searchAcronyms': searchAcronyms, 'includeDeprecated': includeDeprecated, 'category': category, 'prefix': prefix}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('term', **kwargs)
        url = self._basePath + ('/vocabulary/autocomplete/{term}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'term'}
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def getCategories(self, output='application/json'):
        """ Get all categories from: /vocabulary/categories

            Arguments:

            outputs:
                application/json
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/vocabulary/categories').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def findById(self, id, output='application/json'):
        """ Find a concept by its ID from: /vocabulary/id/{id}

            Arguments:
            id: ID to find
            outputs:
                application/json
        """

        if id and id.startswith('http:'):
            id = parse.quote(id, safe='')
        kwargs = {'id': id}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('id', **kwargs)
        url = self._basePath + ('/vocabulary/id/{id}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'id'}
        output = self._get('GET', url, requests_params, output)
        return output if output else None

    def getCuriePrefixes(self, output='application/json'):
        """ Get all CURIE prefixes from: /vocabulary/prefixes

            Arguments:

            outputs:
                application/json
        """

        kwargs = {}
        
        param_rest = self._make_rest(None, **kwargs)
        url = self._basePath + ('/vocabulary/prefixes').format(**kwargs)
        requests_params = kwargs
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def searchByTerm(self, term, limit=None, searchSynonyms=None, searchAbbreviations=None, searchAcronyms=None, category=None, prefix=None, output='application/json'):
        """ Find a concept from a term fragment from: /vocabulary/search/{term}

            Arguments:
            term: Term to find
            limit: Maximum result count
            searchSynonyms: Should synonyms be matched
            searchAbbreviations: Should abbreviations be matched
            searchAcronyms: Should acronyms be matched
            category: Categories to search (defaults to all)
            prefix: CURIE prefixes to search (defaults to all)
            outputs:
                application/json
        """

        kwargs = {'term': term, 'limit': limit, 'searchSynonyms': searchSynonyms, 'searchAbbreviations': searchAbbreviations, 'searchAcronyms': searchAcronyms, 'category': category, 'prefix': prefix}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('term', **kwargs)
        url = self._basePath + ('/vocabulary/search/{term}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'term'}
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def suggestFromTerm(self, term, limit=None, output='application/json'):
        """ Suggest terms from: /vocabulary/suggestions/{term}

            Arguments:
            term: Mispelled term
            limit: Maximum result count
            outputs:
                application/json
        """

        kwargs = {'term': term, 'limit': limit}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('term', **kwargs)
        url = self._basePath + ('/vocabulary/suggestions/{term}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'term'}
        output = self._get('GET', url, requests_params, output)
        return output if output else []

    def findByTerm(self, term, limit=None, searchSynonyms=None, searchAbbreviations=None, searchAcronyms=None, category=None, prefix=None, output='application/json'):
        """ Find a concept from a term from: /vocabulary/term/{term}

            Arguments:
            term: Term to find
            limit: Maximum result count
            searchSynonyms: Should synonyms be matched
            searchAbbreviations: Should abbreviations be matched
            searchAcronyms: Should acronyms be matched
            category: Categories to search (defaults to all)
            prefix: CURIE prefixes to search (defaults to all)
            outputs:
                application/json
        """

        kwargs = {'term': term, 'limit': limit, 'searchSynonyms': searchSynonyms, 'searchAbbreviations': searchAbbreviations, 'searchAcronyms': searchAcronyms, 'category': category, 'prefix': prefix}
        kwargs = {k:dumps(v) if builtins.type(v) is dict else v for k, v in kwargs.items()}
        param_rest = self._make_rest('term', **kwargs)
        url = self._basePath + ('/vocabulary/term/{term}').format(**kwargs)
        requests_params = {k:v for k, v in kwargs.items() if k != 'term'}
        output = self._get('GET', url, requests_params, output)
        return output if output else []

