Source code for orangecontrib.bioinformatics.kegg.entry

"""
DBGET entry
"""
from __future__ import absolute_import

import warnings
from collections import defaultdict

from . import fields
from .parser import DBGETEntryParser

__all__ = ["parser", "fields"]

# TODO: Remove the use of entry_decorate decorator
# for constructing a DBEntry subclass, make fields
# properties with __get__ method, and explicit assignment
# and meaningful docstrings


def entry_decorate(cls):
    """
    Decorate the DBEntry subclass with properties for accessing
    the fields through the 'DBField._convert' interface

    """
    reserved_names_map = {"class": "class_", "def": "def_"}

    def construct_one(name):
        def get(self):
            field = getattr(self, name, None)
            if field is not None:
                return field._convert()
            else:
                return None

        return property(get, doc=name)

    def construct_multiple(name):
        def get(self):
            field = getattr(self, name, None)
            if field is not None:
                return [f._convert() for f in field]
            else:
                return None

        return property(get, doc=name)

    for name, field in cls.FIELDS:
        name_lower = name.lower()
        if not hasattr(cls, name_lower):
            if name in cls.MULTIPLE_FIELDS:
                prop = construct_multiple(name)
            else:
                prop = construct_one(name)
            setattr(cls, reserved_names_map.get(name_lower, name_lower), prop)

    return cls


[docs]class DBEntry(object): """ A DBGET entry object. """ FIELDS = [("ENTRY", fields.DBEntryField)] MULTIPLE_FIELDS = [] def __init__(self, text=None): self._sections = {} self.fields = [] if text is not None: self.parse(text) @property def entry_key(self): """ Primary entry key used for identifying the entry. """ return self.entry.split(" ", 1)[0]
[docs] def parse(self, text): """ Parse `text` string containing a formated DBGET entry. """ parser = DBGETEntryParser() gen = parser.parse_string(text) field_constructors = dict(self.FIELDS) current = None current_subfield = None entry_fields = [] for (event, title, text) in gen: if event == DBGETEntryParser.SECTION_START: if title in field_constructors: ftype = field_constructors[title] else: ftype = fields.DBSimpleField current = ftype(text) if current.TITLE is None: current.TITLE = title elif event == DBGETEntryParser.SECTION_END: entry_fields.append(current) current = None elif event == DBGETEntryParser.SUBSECTION_START: current_subfield = fields.DBSimpleField(text) current_subfield.TITLE = title if not isinstance(current, fields.DBFieldWithSubsections): # Upgrade simple fields to FieldWithSubsection new = fields.DBFieldWithSubsections(current.text) new.TITLE = current.TITLE current = new elif event == DBGETEntryParser.SUBSECTION_END: current.subsections.append(current_subfield) current_subfield = None elif event == DBGETEntryParser.TEXT: if current_subfield is not None: current_subfield.text += text elif current is not None: current.text += text elif event == DBGETEntryParser.ENTRY_END: break self.fields = entry_fields self._consolidate()
def _consolidate(self): """ Update mapping to field entries. """ registered_fields = dict(self.FIELDS) multiple_fields = set(self.MULTIPLE_FIELDS) for field in self.fields: title = field.TITLE if title not in registered_fields: import warnings warnings.warn("Nonregisterd field %r in %r" % (title, type(self))) if title in multiple_fields: if not hasattr(self, title): setattr(self, title, []) getattr(self, title).append(field) else: setattr(self, title, field) def __str__(self): return self.format()
[docs] def format(self, section_indent=12): """ Return a DBGET formated string representation. """ return "".join(f.format(section_indent) for f in self.fields)
def get(self, key, default=None): raise NotImplementedError f = getattr(self, key, None) if f is not None: if key in self.MULTIPLE_FIELDS: return [f.text for f in f] else: return f.text else: return None