Changeset 1733:548d1187a29f in orange-bioinformatics for _bioinformatics/obiKEGG/api.py


Ignore:
Timestamp:
03/05/13 19:48:00 (14 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Porting obiKEGG to use the new REST KEGG API.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • _bioinformatics/obiKEGG/api.py

    r1716 r1733  
    55from __future__ import absolute_import 
    66 
     7from datetime import datetime 
    78from contextlib import closing 
     9from operator import itemgetter 
     10import warnings 
    811 
    912from .service import web_service 
    10 from .types import * 
     13from .types import OrganismSummary, Definition, BInfo, Link 
     14 
     15 
     16DATABASES = [ 
     17    ("KEGG Pathway", "pathway", "path", None), 
     18    ("KEGG Brite", "brite", "br", None), 
     19    ("KEGG Module", "module", "md", "M"), 
     20    ("KEGG Disease", "disease", "ds", "H"), 
     21    ("KEGG Drug", "drug", "dr", "D"), 
     22    ("KEGG Orthology", "orthology", "ko", "K"), 
     23    ("KEGG Genome", "genome", "genome", "T"), 
     24    ("KEGG Genomes", "genomes", "gn", "T"), 
     25    ("KEGG Genes", "genes", None, None), 
     26    ("KEGG Ligand", "ligand", "ligand", None), 
     27    ("KEGG Compound", "compound", "cpd", "C"), 
     28    ("KEGG Glycan", "glycan", "gl", "G"), 
     29    ("KEGG Reaction", "reaction", "rn", "R"), 
     30    ("KEGG RPair", "rpair", "rp", "RP"), 
     31    ("KEGG RClass", "rclass", "rc", "RC"), 
     32    ("KEGG Enzyme", "enzyme", "ec", "E") 
     33] 
     34 
     35 
     36def _link_targets(links): 
     37    return sorted(set(map(itemgetter(1), links))) 
     38 
    1139 
    1240class KeggApi(object): 
    13     """ KEGG API """ 
    14      
     41    """ 
     42    An abstraction of a kegg api. 
     43    """ 
     44 
    1545    def __init__(self): 
    1646        self.service = web_service() 
    17          
    18     ################## 
    19     # Meta information 
    20     ################## 
    21      
    22     def list_databases(self): 
    23         """ Returns a list of available databases. 
    24          
    25         >>> api.list_databases() 
    26         [Definition(entry_id='nt',... 
    27           
    28         """ 
    29         return map(Definition.from_items, self.service.list_databases()) 
    30      
     47 
    3148    def list_organisms(self): 
    32         """ Return a list of all available organisms 
    33          
     49        """ 
     50        Return a list of all available organisms 
     51 
    3452        >>> api.list_organisms() 
    3553        [Definition(entry_id='hsa',... 
    36          
    37         """ 
    38         return map(Definition.from_items, self.service.list_organisms()) 
    39      
     54 
     55        """ 
     56        return map(OrganismSummary.from_str, 
     57                   self.service.list.organism.get().splitlines()) 
     58 
    4059    def list_pathways(self, organism): 
    41         """ Return a list of all available pathways for `organism` 
    42          
     60        """ 
     61        Return a list of all available pathways for `organism` 
     62 
    4363        >>> api.list_pathways("hsa") 
    4464        [Definition(entry_id=',... 
    45          
    46         """ 
    47         return map(Definition.from_items, self.service.list_pathways(organism)) 
    48          
     65 
     66        """ 
     67        return map(Definition.from_str, 
     68                   self.service.list.pathway(organism).get().splitlines()) 
     69 
     70    def list(self, db): 
     71        """ 
     72        Return a list of all available entries in database `db`. 
     73        """ 
     74        return map(Definition.from_str, 
     75                   self.service.list(db).get().splitlines()) 
     76 
    4977    ####### 
    5078    # DBGET 
    5179    ####### 
    52       
    53     def binfo(self, db): 
    54         """ Return info for database `db` 
    55          
    56         >>> print api.dbinfo("gb") 
    57         genbank          GenBank nucleic acid sequence database 
    58         gb               Release 186.0, Oct 11 
    59                          National Center for Biotechnology Information 
    60                          144,458,648 entries, 132,067,413,372 bases 
    61                          Last update: 11/10/24 
    62                          <dbget> <fasta> <blast> 
    63                           
    64         """ 
    65         result = self.service.binfo(db) 
    66         if result is not None: 
    67             return BInfo.from_text(str(result)) 
    68         else: 
    69             return result 
    70      
    71     def bfind(self, db, keywords): 
    72         """ Search database 'db' for keywords 
    73         """ 
    74         result = self.service.bfind(" ".join([db, keywords])) 
    75         if result is not None: 
    76             return str(result) 
    77         else: 
    78             return result 
    79      
    80     def bget(self, ids): 
    81         """ 
     80 
     81    def info(self, db): 
     82        """ 
     83        Return info for database `db` 
     84 
     85        >>> print api.info("pathway") 
     86        BInfo(entry_id='path', definition='KEGG Pathway Database', ... 
     87 
     88        """ 
     89        result = self.service.info(db).get() 
     90        return BInfo.from_text(str(result)) 
     91 
     92    def find(self, db, keywords): 
     93        """ 
     94        Search database 'db' for keywords. 
     95        """ 
     96        if isinstance(keywords, basestring): 
     97            keywords = [keywords] 
     98 
     99        return self.service.find(db)("+".join(keywords)).get() 
     100 
     101    def get(self, ids): 
     102        """ 
     103        Retrieve database entries for `ids` list. 
    82104        """ 
    83105        if not isinstance(ids, basestring): 
    84106            # Sequence of ids 
    85             ids = " ".join(ids) 
    86         result = self.service.bget(ids) 
    87         if result is not None: 
    88             return str(result) 
     107            ids = "+".join(ids) 
     108 
     109        return self.service.get(ids).get() 
     110 
     111    def conv(self, ids): 
     112        raise NotImplementedError() 
     113 
     114    def link(self, target_db, source_db=None, ids=None): 
     115        if not (source_db or ids): 
     116            raise ValueError("One of 'source_db' or 'ids' must be supplied") 
     117        if source_db and ids: 
     118            raise ValueError("Only one 'source_db' or 'ids' must be supplied") 
     119 
     120        if source_db: 
     121            result = self.service.link(target_db)(source_db).get() 
    89122        else: 
    90             return result 
    91      
    92     def btit(self, ids): 
    93         """ 
    94         """ 
    95         if not isinstance(ids, basestring): 
    96             ids = " ".join(ids) 
    97              
    98         result = self.service.btit(ids) 
    99         if result is not None: 
    100             return str(result) 
    101         else: 
    102             return result 
    103      
    104     def bconv(self, ids): 
    105         if not isinstance(ids, basestring): 
    106             ids = " ".join(ids) 
    107              
    108         result = self.service.bconv(ids) 
    109         if result is not None: 
    110             return str(result) 
    111         else: 
    112             return result 
    113      
    114     ######## 
    115     # LinkDB 
    116     ######## 
    117      
    118     def get_linkdb_by_entry(self, entry_id, db, offset, limit): 
    119         links = self.service.get_linkdb_by_entry(entry_id, db, offset, limit) 
    120         return [LinkDBRelation(**d) for d in \ 
    121                 map(dict, links)] 
    122          
    123     def get_linkdb_between_databases(self, from_db, to_db, offset, limit): 
    124         links = self.service.get_linkdb_between_databases(from_db, to_db, offset, limit) 
    125         return [LinkDBRelation(**d) for d in \ 
    126                 map(dict, links)] 
    127          
     123            result = self.service.link(target_db)("+".join(ids)).get() 
     124 
     125        return map(Link._make, map(str.split, result.splitlines())) 
     126 
    128127    def get_genes_by_enzyme(self, enzyme_id, org): 
    129         return self.service.get_genes_by_enzyme(enzyme_id, org) 
    130      
    131     def get_enzymes_by_gene(self, genes_id): 
    132         return self.service.get_enzymes_by_gene(genes_id) 
    133      
     128        return _link_targets(self.link(org, ids=[enzyme_id])) 
     129 
     130    def get_enzymes_by_gene(self, gene_id): 
     131        return _link_targets(self.link("ec", ids=[gene_id])) 
     132 
    134133    def get_enzymes_by_compound(self, compound_id): 
    135         return self.service.get_enzymes_by_compound(compound_id) 
    136      
     134        return _link_targets(self.link("ec", ids=[compound_id])) 
     135 
    137136    def get_enzymes_by_glycan(self, glycan_id): 
    138         return self.service.get_enzymes_by_glycan(glycan_id) 
    139      
     137        return _link_targets(self.link("ec", ids=[glycan_id])) 
     138 
    140139    def get_enzymes_by_reaction(self, reaction_id): 
    141         return self.service.get_enzymes_by_reaction(reaction_id) 
    142      
     140        return _link_targets(self.link("ec", ids=[reaction_id])) 
     141 
    143142    def get_compounds_by_enzyme(self, enzyme_id): 
    144         return self.service.get_compounds_by_enzyme(enzyme_id) 
    145      
     143        return _link_targets(self.link("compound", ids=[enzyme_id])) 
     144 
    146145    def get_compounds_by_reaction(self, reaction_id): 
    147         return self.service.get_compounds_by_reaction(reaction_id) 
    148      
     146        return _link_targets(self.link("compound", ids=[reaction_id])) 
     147 
    149148    def get_glycans_by_enzyme(self, enzyme_id): 
    150         return self.service.get_glycans_by_enzyme(enzyme_id) 
    151      
     149        return _link_targets(self.link("gl", ids=[enzyme_id])) 
     150 
    152151    def get_glycans_by_reaction(self, reaction_id): 
    153         return self.service.get_glycans_by_reaction(reaction_id) 
    154      
     152        return _link_targets(self.link("gl", ids=[reaction_id])) 
     153 
    155154    def get_reactions_by_enzyme(self, enzyme_id): 
    156         return self.service.get_reactions_by_enzyme(enzyme_id) 
    157      
     155        return _link_targets(self.link("rn", ids=[enzyme_id])) 
     156 
    158157    def get_reactions_by_compound(self, compound_id): 
    159         return self.service.get_reactions_by_compound(compound_id) 
    160      
     158        return _link_targets(self.link("rn", ids=[compound_id])) 
     159 
    161160    def get_reactions_by_glycan(self, glycan_id): 
    162         return self.service.get_reactions_by_glycan(glycan_id) 
    163      
     161        return _link_targets(self.link("rn", ids=[glycan_id])) 
     162 
    164163    ###### 
    165164    # SSDB 
    166165    ###### 
    167      
     166 
     167    # No replacement api in the KEGG REST api. 
    168168    def get_best_best_neighbors_by_gene(self, genes_id, offset, limit): 
    169         ssr = self.service.get_best_best_neighbors_by_gene(genes_id, offset, limit) 
    170         return [SSDBRelation(**d) for d in \ 
    171                 map(dict, ssr)] 
    172      
     169        raise NotImplementedError 
     170 
    173171    def get_best_neighbors_by_gene(self, genes_id, offset, limit): 
    174         ssr = self.service.get_best_neighbors_by_gene(genes_id, offset, limit) 
    175         return [SSDBRelation(**d) for d in \ 
    176                 map(dict, ssr)] 
    177      
     172        raise NotImplementedError 
     173 
    178174    def get_reverse_best_neighbors_by_gene(self, genes_id, offset, limit): 
    179         ssr = self.service.get_reverse_best_neighbors_by_gene(genes_id, offset, limit) 
    180         return [SSDBRelation(**d) for d in \ 
    181                 map(dict, ssr)] 
    182      
     175        raise NotImplementedError 
     176 
    183177    def get_paralogs_by_gene(self, genes_id, offset, limit): 
    184         ssr =  self.service.get_paralogs_by_gene(genes_id, offset, limit) 
    185         return [SSDBRelation(**d) for d in \ 
    186                 map(dict, ssr)] 
    187      
     178        raise NotImplementedError 
     179 
    188180    ####### 
    189181    # Motif 
    190182    ####### 
    191      
     183 
     184    # No replacement api in KEGG REST api 
    192185    def get_motifs_by_gene(self, genes_id, db): 
    193         motif = self.service.get_motifs_by_gene(genes_id, db) 
    194         return [MotifResult(**d) for d in \ 
    195                 map(dict, motif)] 
    196      
     186        raise NotImplementedError 
     187 
    197188    def get_genes_by_motifs(self, motif_id_list, offset, limit): 
    198         genes = self.service.get_genes_by_motifs(motif_id_list, offset, limit) 
    199         return [Definition(**d) for d in \ 
    200                 map(dict, genes)] 
    201      
     189        raise NotImplementedError 
     190 
    202191    #### 
    203192    # KO 
    204193    #### 
    205      
     194 
    206195    def get_ko_by_gene(self, genes_id): 
    207         return self.service.get_ko_by_gene(genes_id) 
    208      
     196        raise NotImplementedError 
     197 
    209198    def get_ko_by_ko_class(self, ko_class_id): 
    210         return self.service.get_ko_by_ko_class(ko_class_id) 
    211      
     199        raise NotImplementedError 
     200 
    212201    def get_genes_by_ko_class(self, ko_class_id, org, offset, limit): 
    213         return self.service.get_genes_by_ko_class(ko_class_id, org, offset, limit) 
    214      
     202        raise NotImplementedError 
     203 
    215204    def get_genes_by_ko(self, ko_id, org): 
    216         return self.service.get_genes_by_ko(ko_id, org) 
    217      
     205        raise NotImplementedError 
     206 
    218207    ######### 
    219208    # Pathway 
    220209    ######### 
    221      
     210 
    222211    def mark_pathway_by_objects(self, pathway_id, object_id_list): 
    223         return self.service.mark_pathway_by_objects(pathway_id, object_id_list) 
    224      
    225     def color_pathway_by_objects(self, pathway_id, object_id_list, fg_color_list, bg_color_list): 
    226         return self.service.color_pathway_by_objects(pathway_id, object_id_list, fg_color_list, bg_color_list) 
    227      
    228     def color_pathway_by_elements(self, pathway_id, element_id_list, fg_color_list, bg_color_list): 
    229         return self.service.color_pathway_by_elements(pathway_id, element_id_list, fg_color_list, bg_color_list) 
    230      
    231     def get_html_of_marked_pathway_by_objects(self, pathway_id, object_id_list): 
    232         return self.service.get_html_of_marked_pathway_by_objects(pathway_id, object_id_list) 
    233      
    234     def get_html_of_colored_pathway_by_objects(self, pathway_id, object_id_list, fg_color_list, bg_color_list): 
    235         return self.service.get_html_of_colored_pathway_by_objects(pathway_id, object_id_list, fg_color_list, bg_color_list) 
    236      
    237     def get_html_of_colored_pathway_by_elements(self, pathway_id, element_id_list, fg_color_list, bg_color_list): 
    238         return self.service.get_html_of_colored_pathway_by_elements(pathway_id, element_id_list, fg_color_list, bg_color_list) 
    239      
     212        raise NotImplementedError 
     213 
     214    def color_pathway_by_objects(self, pathway_id, object_id_list, 
     215                                 fg_color_list, bg_color_list): 
     216        raise NotImplementedError 
     217 
     218    def color_pathway_by_elements(self, pathway_id, element_id_list, 
     219                                  fg_color_list, bg_color_list): 
     220        raise NotImplementedError 
     221 
     222    def get_html_of_marked_pathway_by_objects(self, pathway_id, 
     223                                              object_id_list): 
     224        raise NotImplementedError 
     225 
     226    def get_html_of_colored_pathway_by_objects(self, pathway_id, 
     227                                               object_id_list, fg_color_list, 
     228                                               bg_color_list): 
     229        raise NotImplementedError 
     230 
     231    def get_html_of_colored_pathway_by_elements(self, pathway_id, 
     232                                                element_id_list, fg_color_list, 
     233                                                bg_color_list): 
     234        raise NotImplementedError 
     235 
    240236    def get_references_by_pathway(self, pathway_id): 
    241237        return self.service.get_references_by_pathway(pathway_id) 
    242      
     238 
    243239    def get_element_relations_by_pathway(self, pathway_id): 
    244240        return self.service.get_element_relations_by_pathway(pathway_id) 
    245      
    246      
    247      
     241 
    248242    def get_genes_by_organism(self, organism, offset=None, limit=None): 
    249         if offset is None and limit is None: 
    250             offset = 0 
    251             limit = self.get_number_of_genes_by_organism(organism) 
    252              
    253         return self.service.get_genes_by_organism(organism, offset, limit) 
    254      
     243        if offset is not None: 
     244            raise NotImplementedError("offset is no longer supported") 
     245        if limit is not None: 
     246            raise NotImplementedError("limit is no longer supported.") 
     247 
     248        res = self.service.list(organism).get().splitlines() 
     249        return [r.split(None, 1)[0] for r in res] 
     250 
    255251    def get_number_of_genes_by_organism(self, organism): 
    256         return self.service.get_number_of_genes_by_organism(organism) 
    257      
     252        raise NotImplementedError 
     253 
    258254    #################### 
    259255    # Objects by pathway 
    260256    #################### 
    261      
     257 
    262258    def get_elements_by_pathway(self, pathway_id): 
    263         return self.service.get_elements_by_pathway(pathway_id) 
    264      
     259        raise NotImplementedError 
     260 
    265261    def get_genes_by_pathway(self, pathway_id): 
    266         return self.service.get_genes_by_pathway(pathway_id) 
    267      
     262        return _link_targets(self.link("genes", ids=[pathway_id])) 
     263 
    268264    def get_enzymes_by_pathway(self, pathway_id): 
    269         return self.service.get_enzymes_by_pathway(pathway_id) 
    270      
     265        return _link_targets(self.link("ec", ids=[pathway_id])) 
     266 
    271267    def get_compounds_by_pathway(self, pathway_id): 
    272         return self.service.get_compounds_by_pathway(pathway_id) 
    273      
     268        return _link_targets(self.link("compound", ids=[pathway_id])) 
     269 
    274270    def get_drugs_by_pathway(self, pathway_id): 
    275         return self.service.get_drugs_by_pathway(pathway_id) 
    276      
     271        return _link_targets(self.link("drug", ids=[pathway_id])) 
     272 
    277273    def get_glycans_by_pathway(self, pathway_id): 
    278         return self.service.get_glycans_by_pathway(pathway_id) 
    279      
     274        return _link_targets(self.link("gl", ids=[pathway_id])) 
     275 
    280276    def get_reactions_by_pathway(self, pathway_id): 
    281         return self.get_reactions_by_pathway(pathway_id) 
    282      
     277        return _link_targets(self.link("rn", ids=[pathway_id])) 
     278 
    283279    def get_kos_by_pathway(self, pathway_id): 
    284         return self.service.get_kos_by_pathway(pathway_id) 
    285      
     280        return _link_targets(self.link("ko", ids=[pathway_id])) 
     281 
    286282    ##################### 
    287283    # Pathways by objects 
    288284    ##################### 
    289      
     285 
     286    # These functions returned results intersections. 
    290287    def get_pathways_by_genes(self, gene_list): 
    291         return map(str, self.service.get_pathways_by_genes(gene_list)) 
    292      
     288        raise NotImplementedError 
     289 
    293290    def get_pathways_by_enzymes(self, enzyme_list): 
    294         return map(str, self.service.get_pathways_by_enzymes(enzyme_list)) 
    295      
     291        raise NotImplementedError 
     292 
    296293    def get_pathways_by_compounds(self, compound_list): 
    297         return map(str, self.service.get_pathways_by_compounds(compound_list)) 
    298      
     294        raise NotImplementedError 
     295 
    299296    def get_pathways_by_drugs(self, drug_list): 
    300         return map(str, self.service.get_pathways_by_drugs(drug_list)) 
    301      
     297        raise NotImplementedError 
     298 
    302299    def get_pathways_by_glycans(self, glycan_list): 
    303         return map(str, self.service.get_pathways_by_glycans(glycan_list)) 
    304      
     300        raise NotImplementedError 
     301 
    305302    def get_pathways_by_reactions(self, reaction_list): 
    306         return map(str, self.service.get_pathways_by_reactions(reaction_list)) 
    307      
     303        raise NotImplementedError 
     304 
    308305    def get_pathways_by_kos(self, ko_list): 
    309         return map(str, self.service.get_pathways_by_kos(ko_list)) 
    310      
     306        raise NotImplementedError 
     307 
    311308    ########################## 
    312309    # Relations among pathways 
    313310    ########################## 
    314      
     311 
    315312    def get_linked_pathways(self, pathway_id): 
    316313        if not pathway_id.startswith("path:"): 
    317314            pathway_id = "path:" + pathway_id 
    318         return map(str, self.service.get_linked_pathways(pathway_id)) 
    319      
    320      
     315        return _link_targets(self.link("pathway", ids=[pathway_id])) 
     316 
     317 
    321318""" 
    322319KEGG api with caching 
     
    355352    def set_default_release(self, release): 
    356353        self.default_release = release 
    357          
    358      
    359     ################## 
    360     # Meta information 
    361     ################## 
    362      
    363     @lru_cache() # not persistently cached 
    364     def list_databases(self): 
    365         return KeggApi.list_databases(self) 
    366      
     354 
    367355    @cached_method 
    368356    def list_organisms(self): 
     
    372360    def list_pathways(self, organism): 
    373361        return KeggApi.list_pathways(self, organism) 
    374      
    375     ####### 
    376     # DBGET 
    377     ####### 
    378      
    379     @lru_cache() # not persistently cached 
    380     def binfo(self, db): 
    381         return KeggApi.binfo(self, db) 
    382      
    383     @cached_method 
    384     def bfind(self, db, keywords): 
    385         return KeggApi.bfind(self, db, keywords) 
    386      
    387     @cached_method 
    388     def bget(self, ids): 
    389         rval = KeggApi.bget(self, ids) 
    390         return rval 
    391      
    392     @cached_method 
    393     def bget(self, ids): 
     362 
     363    @cached_method 
     364    def list(self, db): 
     365        return KeggApi.list(self, db) 
     366 
     367    @lru_cache()  # not persistently cached 
     368    def info(self, db): 
     369        return KeggApi.info(self, db) 
     370 
     371    @cached_method 
     372    def find(self, db, keywords): 
     373        return KeggApi.find(self, db, keywords) 
     374 
     375    @cached_method 
     376    def get(self, ids): 
    394377        if not isinstance(ids, basestring): 
    395             return self._batch_bget(ids) 
     378            return self._batch_get(ids) 
    396379        else: 
    397             return KeggApi.bget(self, ids) 
    398          
    399     def _batch_bget(self, ids): 
    400         if len(ids) > 100: 
    401             raise ValueError("Can batch at most 100 ids at a time.") 
    402          
    403         bget = self.bget 
     380            return KeggApi.get(self, ids) 
     381 
     382    def _batch_get(self, ids): 
     383        if len(ids) > 10: 
     384            raise ValueError("Can batch at most 10 ids at a time.") 
     385 
     386        get = self.get 
    404387        uncached = [] 
    405         with closing(bget.cache_store()) as store: 
     388        unmatched = set() 
     389 
     390        with closing(get.cache_store()) as store: 
    406391            # Which ids are already cached 
    407392            # TODO: Invalidate entries by release string. 
    408393            for id in ids: 
    409                 key = bget.key_from_args((id,)) 
     394                key = get.key_from_args((id,)) 
    410395                if key not in store: 
    411396                    uncached.append(id) 
    412                  
     397 
    413398        if uncached: 
    414399            # in case there are duplicate ids 
    415400            uncached = sorted(set(uncached)) 
    416             rval = KeggApi.bget(self, uncached) 
     401            rval = KeggApi.get(self, uncached) 
     402 
    417403            if rval is not None: 
    418                 entrys = rval.split("///\n") 
     404                entries = rval.split("///\n") 
    419405            else: 
    420                 entrys = [] 
    421                  
    422             if entrys and not entrys[-1].strip(): 
    423                 # Delete the last newline if present 
    424                 del entrys[-1] 
    425              
    426             if len(entrys) == len(uncached): 
    427                 with closing(bget.cache_store()) as store: 
    428                     for id, entry in zip(uncached, entrys): 
    429                         key = bget.key_from_args((id,)) 
    430                         if entry is not None: 
    431                             entry = entry + "///\n" 
    432                         store[key] = cache_entry(entry, mtime=datetime.now()) 
    433                          
    434             else: 
    435                 # Try to bisect the uncached list 
    436                 if len(uncached) > 1 and len(uncached) - len(entrys) < 4: 
    437                     split = len(uncached) / 2 
    438                     self._batch_bget(uncached[:split]) 
    439                     self._batch_bget(uncached[split:]) 
    440                 else: 
    441                     import warnings 
    442                     warnings.warn("Batch contains invalid ids", UserWarning) 
    443          
     406                entries = [] 
     407 
     408            if entries and not entries[-1].strip(): 
     409                # Delete the last single newline entry if present 
     410                del entries[-1] 
     411 
     412            if len(entries) != len(uncached): 
     413                new_uncached, entries = match_by_ids(uncached, entries) 
     414                unmatched = set(uncached) - set(new_uncached) 
     415                uncached = new_uncached 
     416                warnings.warn("Unable to match entries for keys: %s." % 
     417                              ", ".join(map(repr, unmatched))) 
     418 
     419            with closing(get.cache_store()) as store: 
     420                for id, entry in zip(uncached, entries): 
     421                    key = get.key_from_args((id,)) 
     422                    if entry is not None: 
     423                        entry = entry + "///\n" 
     424                    store[key] = cache_entry(entry, mtime=datetime.now()) 
     425 
    444426        # Finally join all the results, but drop all None objects 
    445         entries = filter(lambda e: e is not None, map(bget, ids)) 
    446          
     427        entries = filter(lambda e: e is not None, map(get, ids)) 
     428 
    447429        rval = "".join(entries) 
    448430        return rval 
    449      
    450     @cached_method 
    451     def btit(self, ids): 
    452         return KeggApi.btit(self, ids) 
    453      
    454     @cached_method 
    455     def bconv(self, ids): 
    456         return KeggApi.bconv(self, ids) 
    457      
     431 
     432    @cached_method 
     433    def conv(self, ids): 
     434        return KeggApi.conv(self, ids) 
     435 
    458436    ######## 
    459437    # LinkDB 
    460438    ######## 
    461      
    462     @cached_method 
    463     def get_linkdb_by_entry(self, entry_id, db, offset, limit): 
    464        return KeggApi.get_linkdb_by_entry(self, entry_id, db, offset, limit) 
    465          
    466     @cached_method 
    467     def get_linkdb_between_databases(self, from_db, to_db, offset, limit): 
    468         return KeggApi.get_linkdb_between_databases(self, from_db, to_db, offset, limit) 
    469              
     439 
    470440    @cached_method 
    471441    def get_genes_by_enzyme(self, enzyme_id, org): 
    472442        return KeggApi.get_genes_by_enzyme(self, enzyme_id, org) 
    473      
     443 
    474444    @cached_method 
    475445    def get_enzymes_by_gene(self, genes_id): 
    476446        return KeggApi.get_enzymes_by_gene(self, genes_id) 
    477      
     447 
    478448    @cached_method 
    479449    def get_enzymes_by_compound(self, compound_id): 
    480450        return KeggApi.get_enzymes_by_compound(self, compound_id) 
    481      
     451 
    482452    @cached_method 
    483453    def get_enzymes_by_glycan(self, glycan_id): 
    484454        return KeggApi.get_enzymes_by_glycan(self, glycan_id) 
    485      
     455 
    486456    @cached_method 
    487457    def get_enzymes_by_reaction(self, reaction_id): 
    488458        return KeggApi.get_enzymes_by_reaction(self, reaction_id) 
    489      
     459 
    490460    @cached_method 
    491461    def get_compounds_by_enzyme(self, enzyme_id): 
    492462        return KeggApi.get_compounds_by_enzyme(self, enzyme_id) 
    493      
     463 
    494464    @cached_method 
    495465    def get_compounds_by_reaction(self, reaction_id): 
    496466        return KeggApi.get_compounds_by_reaction(self, reaction_id) 
    497      
     467 
    498468    @cached_method 
    499469    def get_glycans_by_enzyme(self, enzyme_id): 
    500470        return KeggApi.get_glycans_by_enzyme(self, enzyme_id) 
    501      
     471 
    502472    @cached_method 
    503473    def get_glycans_by_reaction(self, reaction_id): 
    504474        return KeggApi.get_glycans_by_reaction(self, reaction_id) 
    505      
     475 
    506476    @cached_method 
    507477    def get_reactions_by_enzyme(self, enzyme_id): 
    508478        return KeggApi.get_reactions_by_enzyme(self, enzyme_id) 
    509      
     479 
    510480    @cached_method 
    511481    def get_reactions_by_compound(self, compound_id): 
    512482        return KeggApi.get_reactions_by_compound(self, compound_id) 
    513      
     483 
    514484    @cached_method 
    515485    def get_reactions_by_glycan(self, glycan_id): 
    516486        return KeggApi.get_reactions_by_glycan(self, glycan_id) 
    517      
     487 
    518488    ###### 
    519489    # SSDB 
     
    571541    # Pathway 
    572542    ######### 
    573      
    574     # TODO 
    575      
    576      
    577      
     543 
    578544    @cached_method 
    579545    def get_genes_by_organism(self, organism, offset=None, limit=None): 
     
    643609    def get_kos_by_pathway(self, pathway_id): 
    644610        return KeggApi.get_kos_by_pathway(self, pathway_id) 
    645      
     611 
     612 
     613def match_by_ids(ids, entries): 
     614    """ 
     615 
     616    """ 
     617 
     618    unmatched_ids = set(ids) 
     619    unmatched_entries = set(entries) 
     620 
     621    matched_ids = [] 
     622    matched_entries = [] 
     623 
     624    def match_add(search_id, entry): 
     625        """ 
     626        Move search_id and entry to the matched lists. 
     627        """ 
     628        matched_ids.append(search_id) 
     629        matched_entries.append(entry) 
     630 
     631        # Remove from the unmatched set 
     632        unmatched_ids.remove(search_id) 
     633        unmatched_entries.remove(entry) 
     634 
     635    def entry_split(entry_text): 
     636        line, _ = entry_text.split("\n", 1) 
     637        return line.split(None, 2) 
     638 
     639    entries_by_id = {} 
     640 
     641    for entry in entries: 
     642        _, eid, _ = entry_split(entry) 
     643        entries_by_id[eid] = entry 
     644 
     645    # First match full search ids 
     646    for search_id in list(unmatched_ids): 
     647        if search_id in entries_by_id: 
     648            entry = entries_by_id.pop(search_id) 
     649            match_add(search_id, entry) 
     650 
     651    # Second pass, split the search ids by ':' to db and identifier part, 
     652    # match by identifier 
     653    for search_id in list(unmatched_ids): 
     654        if ":" in search_id: 
     655            db_id, rest = search_id.split(":", 1) 
     656            if rest in entries_by_id: 
     657                entry = entries_by_id.pop(rest) 
     658                match_add(search_id, entry) 
     659 
     660    return matched_ids, matched_entries 
Note: See TracChangeset for help on using the changeset viewer.