source: orange-bioinformatics/obiKEGG2/databases.py @ 1532:14a377419a09

Revision 1532:14a377419a09, 11.2 KB checked in by ales_erjavec, 2 years ago (diff)

Added KEGG interface using web services

Line 
1"""
2DBGET database
3"""
4
5from . import entry
6from .entry import fields
7from . import api
8
9class DBDataBase(object):
10    """ A wrapper for DBGET database.
11    """
12    # ENTRY_TYPE constructor (type)
13    ENTRY_TYPE = entry.DBEntry
14   
15    # Needs to be set in a subclass or object instance
16    DB = None
17   
18    def __init__(self, **kwargs):
19        if not self.DB:
20            raise TypeError("Cannot make an instance of abstract base class %r." \
21                            % type(self).__name__)
22           
23        self.api = api.CachedKeggApi()
24        self.info = self.api.binfo(self.DB)
25        release = self.info.release
26        self.api.set_default_release(release)
27        self._keys = []
28       
29    def keys(self):
30        return list(self._keys)
31   
32    def iterkeys(self):
33        return iter(self._keys)
34   
35    def items(self):
36        return [(key, self.__getitem__(key)) for key in self.keys()]
37   
38    def iteritems(self):
39        return ((key, self.__getitem__(key)) for key in self.iterkeys())
40   
41    def values(self):
42        return [self.__getitem__(key) for key in self.keys()]
43   
44    def itervalues(self):
45        return (self.__getitem__(key) for key in self.iterkeys())
46   
47    def get(self, key, default=None):
48        if key in self:
49            return self.__getitem__(key)
50        else:
51            return default
52       
53    def has_key(self, key):
54        return self.__contains__(key)
55   
56    def __getitem__(self, key):
57        e = self.get_entry(key)
58        if e is None:
59            raise KeyError(key)
60        else:
61            return e
62   
63    def __contains__(self, key):
64        return key in set(self.keys())
65   
66    def __len__(self):
67        return len(self.keys())
68   
69    def __iter__(self):
70        return iter(self.keys())
71   
72    def get_text(self, key):
73        if not key.startswith(self.DB + ":"):
74            key = self.DB + ":" + key
75        return self.api.bget([key])
76   
77    def get_entry(self, key):
78        text = self.get_text(key)
79        if not text or text == "None":
80            return None
81        else:
82            return self.ENTRY_TYPE(text)
83       
84    def find(self, name):
85        """ Find ``name`` using BFIND.
86        """
87        res = self.api.bfind(self.DB, name).splitlines()
88        return [r.split(" ", 1)[0] for r in res]   
89       
90    def pre_cache(self, keys=None, batch_size=100, progress_callback=None):
91        """ Retrive all the entries and cache them locally.
92        """
93        # TODO do this in multiple threads
94   
95        if not isinstance(self.api, api.CachedKeggApi):
96            raise TypeError("Not an an instance of api.CachedKeggApi")
97       
98        if batch_size > 100 or batch_size < 1:
99            raise ValueError("Invalid batch_size")
100       
101        if keys is None:
102            keys = self.keys()
103           
104        start = 0
105        key_count = len(keys)
106        while start < len(keys):
107            batch = keys[start: start + batch_size]
108            batch = map(self._add_db, batch)
109           
110            self.api.bget(batch)
111           
112            if progress_callback:
113                progress_callback(100.0 * start / len(keys))
114               
115            start += batch_size
116           
117    def _add_db(self, key):
118        """ Prefix the key with 'DB:' string if not already
119        prefixed.
120        """
121        if not key.startswith(self.DB + ":"):
122            return self.DB + ":" + key
123        else:
124            return key
125       
126    @property
127    def entries(self):
128        return self.values()
129   
130@entry.entry_decorate
131class GenomeEntry(entry.DBEntry):
132    FIELDS = [("ENTRY", fields.DBEntryField),
133              ("NAME", fields.DBNameField),
134              ("DEFINITION", fields.DBDefinitionField),
135              ("ANNOTATION", fields.DBSimpleField),
136              ("TAXONOMY", fields.DBTaxonomyField),
137              ("DATA_SOURCE", fields.DBSimpleField),
138              ("ORIGINAL_DB", fields.DBSimpleField),
139              ("CHROMOSOME", fields.DBFieldWithSubsections),
140              ("STATISTICS", fields.DBSimpleField),
141              ("REFERENCE", fields.DBReference)]
142   
143    MULTIPLE_FIELDS = ["REFERENCE"]
144   
145    def __init__(self, text):
146        entry.DBEntry.__init__(self, text)
147       
148    @property
149    def entry_key(self):
150        """ Primary entry key used for querying.
151       
152        .. note:: Unlike most of the other entry types this is the
153            first listed 'NAME'.
154           
155        """
156       
157        return self.name.split(",", 1)[0]
158
159    @property
160    def taxid(self):
161        return self.TAXONOMY.taxid
162           
163    def org_code(self):
164        if self.name is not None:
165            return self.name.split(",")[0]
166        else:
167            return self.entry.split(" ")[0]
168       
169
170class Genome(DBDataBase):
171    DB = "genome"
172    ENTRY_TYPE = GenomeEntry
173   
174    # For obiTaxonomy.common_taxids mapping
175    TAXID_MAP = {"562": "511145",   # Escherichia coli K-12 MG1655
176                 "2104": "272634",  # Mycoplasma pneumoniae M129
177                 "4530": "39947",   # Oryza sativa ssp. japonica cultivar Nipponbare (Japanese rice)
178                 "4932" : "559292", # Saccharomyces cerevisiae S288C
179                 "4896": "284812",  # Schizosaccharomyces pombe 972h-
180                 }
181   
182    def __init__(self):
183        DBDataBase.__init__(self)
184        self._keys = [org.entry_id for org in self.api.list_organisms()]
185   
186    def _key_to_gn_entry_id(self, key):
187        res = self.find(key)
188        if len(res) == 0:
189            raise KeyError("Unknown key")
190        elif len(res) > 1:
191            raise ValueError("Not a unique key")
192        else:
193            return res[0]
194   
195    @classmethod
196    def common_organisms(cls):
197        return ['ath', 'bta', 'cel', 'cre', 'dre', 'ddi',
198                'dme', 'eco', 'hsa', 'mmu', 'mpn', 'osa',
199                'pfa', 'rno', 'sce', 'spo', 'zma', 'xla']
200       
201    @classmethod
202    def essential_organisms(cls):
203        return ['ddi', 'dme', 'hsa', 'mmu', 'sce']
204   
205    def search(self, string, relevance=False):
206        if relevance:
207            raise NotImplementedError("relevance is no longer supported")
208        if string in self.TAXID_MAP:
209            string = self.TAXID_MAP[string]
210           
211        res = self.api.bfind(self.DB, string)
212        if not res:
213            return []
214       
215        res = res.splitlines()
216        res = [r.split(",", 1)[0] for r in res]
217        res = [r.split(" ", 1)[1] for r in res]
218        return res
219   
220@entry.entry_decorate
221class GeneEntry(entry.DBEntry):
222    FIELDS = [("ENTRY", fields.DBEntryField),
223              ("NAME", fields.DBNameField),
224              ("DEFINITION", fields.DBDefinitionField),
225              ("ORTHOLOGY", fields.DBSimpleField),
226              ("DRUG_TARGET", fields.DBSimpleField),
227              ("PATHWAY", fields.DBPathway),
228              ("MODULE", fields.DBSimpleField),
229              ("DISEASE", fields.DBSimpleField),
230              ("CLASS", fields.DBSimpleField),
231              ("POSITION", fields.DBSimpleField),
232              ("MOTIF", fields.DBSimpleField),
233              ("DBLINKS", fields.DBDBLinks),
234              ("STRUCTURE", fields.DBSimpleField),
235              ("AASEQ", fields.DBAASeq),
236              ("NTSEQ", fields.DBNTSeq)]
237   
238    def aliases(self):
239        return [self.entry_key] + (self.name.split(",") if self.name else []) + [link[1][0] for link in self.dblinks.items() if self.dblinks]
240
241    @property
242    def alt_names(self):
243        """ For backwards compatibility.
244        """
245        return self.aliases()
246 
247class Genes(DBDataBase):
248    DB = None # Needs to be set in __init__
249    ENTRY_TYPE = GeneEntry
250   
251    def __init__(self, org_code):
252        self.DB = org_code
253        self.org_code = org_code
254        DBDataBase.__init__(self)
255        self._keys = self.api.get_genes_by_organism(org_code)
256       
257    def gene_aliases(self):
258        aliases = {}
259        for entry in self.itervalues():
260            aliases.update(dict.fromkeys(entry.aliases(), self.org_code + ":" + entry.entry_key()))
261        return aliases
262   
263
264@entry.entry_decorate
265class CompoundEntry(entry.DBEntry):
266    FIELDS = [("ENTRY", fields.DBEntryField),
267              ("NAME", fields.DBNameField),
268              ("FORMULA", fields.DBSimpleField),
269              ("MASS", fields.DBSimpleField),
270              ("REMARK", fields.DBSimpleField),
271              ("REACTION", fields.DBSimpleField),
272              ("PATHWAY", fields.DBPathway),
273              ("ENZYME", fields.DBSimpleField),
274              ("DBLINKS", fields.DBDBLinks),
275              ("ATOM", fields.DBSimpleField),
276              ("BOND", fields.DBSimpleField)
277              ]
278   
279   
280class Compounds(DBDataBase):
281    DB = "cpd"
282    ENTRY_TYPE = CompoundEntry
283   
284    def __init__(self):
285        DBDataBase.__init__(self)
286        self._keys = [] # All keys are not available
287
288KEGGCompounds = Compounds
289
290@entry.entry_decorate   
291class ReactionEntry(entry.DBEntry):
292    FIELDS = [("ENTRY", fields.DBEntryField),
293              ("NAME", fields.DBNameField),
294              ("DEFINITION", fields.DBDefinitionField),
295              ("EQUATION", fields.DBSimpleField),
296              ("ENZYME", fields.DBSimpleField)
297              ]
298   
299class Reactions(DBDataBase):
300    DB = "rn"
301    ENTRY_TYPE = ReactionEntry
302   
303    def __init__(self):
304        DBDataBase.__init__(self)
305        self._keys = [] # All keys are not available
306         
307class Brite(DBDataBase):
308    DB = "br"
309   
310class Disease(DBDataBase):
311    DB = "ds"
312       
313class Drug(DBDataBase):
314    DB = "dr"
315   
316class Enzymes(DBDataBase):
317    DB = "ec"
318   
319@entry.entry_decorate
320class OrthologyEntry(entry.DBEntry):
321    FIELDS = [("ENTRY", fields.DBEntryField),
322              ("NAME", fields.DBNameField),
323              ("CLASS", fields.DBSimpleField),
324              ("DBLINKS", fields.DBDBLinks),
325              ("GENES", fields.DBSimpleField),
326              ]
327   
328class Orthology(DBDataBase):
329    DB = "ko"
330    ENTRY_TYPE = OrthologyEntry
331   
332@entry.entry_decorate
333class PathwayEntry(entry.DBEntry):
334    FIELDS = [("ENTRY", fields.DBEntryField),
335              ("NAME", fields.DBNameField),
336              ("DESCRIPTION", fields.DBSimpleField),
337              ("CLASS", fields.DBSimpleField),
338              ("PATHWAY_MAP", fields.DBPathwayMapField),
339              ("DISEASE", fields.DBSimpleField),
340              ("DRUG", fields.DBSimpleField),
341              ("DBLINKS", fields.DBDBLinks),
342              ("ORGANISM", fields.DBSimpleField),
343              ("GENE", fields.DBGeneField),
344              ("ENZYME", fields.DBSimpleField),
345              ("COMPOUND", fields.DBSimpleField),
346              ("REFERENCE", fields.DBReference),
347              ("REL_PATHWAY", fields.DBSimpleField),
348              ("KO_PATHWAY", fields.DBSimpleField),
349              ]
350   
351    MULTIPLE_FIELDS = ["REFERENCE"]
352   
353    @property
354    def gene(self):
355        if hasattr(self, "GENE"):
356            genes = self.GENE._convert()
357        else:
358            return None
359       
360        org = self.organism
361        org_prefix = ""
362        if org:
363            match = re.findall(r"\[GN:([a-z]+)\]", org)
364            if match:
365                org_prefix = match[0] + ":"
366        genes = [org_prefix + g for g in genes]
367        return genes
368   
369class Pathways(DBDataBase):
370    DB = "path"
371    ENTRY_TYPE = PathwayEntry
372   
373    def __init__(self):
374        DBDataBase.__init__(self)
375   
Note: See TracBrowser for help on using the repository browser.