source: orange-bioinformatics/_bioinformatics/obiKEGG/entry/parser.py @ 1737:729925f75820

Revision 1737:729925f75820, 4.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 13 months ago (diff)

KEGG bug fixes.

Line 
1"""
2A parser for DBGET database entries
3
4"""
5from StringIO import StringIO
6
7
8class DBGETEntryParser(object):
9    r"""
10    A DBGET entry parser (inspired by ``xml.dom.pulldom``).
11
12    ::
13
14        >>> stream = StringIO("ENTRY foo\n"
15        ...                   "NAME  foo's name\n"
16        ...                   "  BAR A subsection of 'NAME'\n")
17        ...
18        >>> parser = DBGETEntryParser()
19        >>> for event, title, contents_part in parser.parse(stream):
20        ...    print parser.EVENTS[event], title, repr(contents_part)
21        ...
22        ENTRY_START None None
23        SECTION_START ENTRY 'foo\n'
24        SECTION_END ENTRY None
25        SECTION_START NAME "foo's name\n"
26        SUBSECTION_START BAR "A subsection of 'NAME'\n"
27        SUBSECTION_END BAR None
28        SECTION_END NAME None
29        ENTRY_END None None
30
31    """
32    #: Entry start events
33    ENTRY_START = 0
34
35    #: Entry end event
36    ENTRY_END = 1
37
38    #: Section start event
39    SECTION_START = 2
40
41    #: Section end event
42    SECTION_END = 3
43
44    #: Subsection start event
45    SUBSECTION_START = 4
46
47    #: Subsection end event
48    SUBSECTION_END = 5
49
50    #: Text element event
51    TEXT = 6
52
53    EVENTS = ["ENTRY_START", "ENTRY_END", 'SECTION_START',
54              'SECTION_END', 'SUBSECTION_START', 'SUBSECTION_END',
55              'TEXT']
56
57    def __init__(self):
58        pass
59
60    def parse(self, stream):
61        entry_offset = None
62        section_title = None
63        subsection_title = None
64        textline_start = None
65
66        for line in stream:
67            startswith = line.startswith
68            # TODO: Reorder by frequency (for faster fallthrough)
69            if startswith("ENTRY"):
70                # Start parsing new entry
71                yield (self.ENTRY_START, None, None)
72                title, rest = self._partition_section_title(line)
73                entry_offset = len(line) - len(rest)
74                textline_start = " " * entry_offset
75                yield (self.SECTION_START, title, rest)
76                yield (self.SECTION_END, title, None)
77
78            elif startswith("///"):
79                # End entry
80                if subsection_title is not None:
81                    # End current subsection if any
82                    yield (self.SUBSECTION_END, subsection_title, None)
83                    subsection_title = None
84
85                if section_title is not None:
86                    # End current section if any
87                    yield (self.SECTION_END, section_title, None)
88                    section_title = None
89
90                yield (self.ENTRY_END, None, None)
91                entry_offset = None
92                textline_start = None
93
94            elif not startswith(" "):
95                # Start new section
96                if subsection_title is not None:
97                    # End current subsection if any
98                    yield (self.SUBSECTION_END, subsection_title, None)
99                    subsection_title = None
100
101                if section_title is not None:
102                    # End current section if any
103                    yield (self.SECTION_END, section_title, None)
104                    section_title = None
105
106                title, rest = self._partition_section_title(line)
107                section_title = title
108                yield (self.SECTION_START, section_title, rest)
109
110            elif startswith(textline_start):
111                # A line of text
112                # TODO: pass the current subsection/section title
113                yield (self.TEXT, None, line[entry_offset:])
114
115            elif startswith(" "):
116                # Start a new subsection
117                if subsection_title is not None:
118                    # End current subsection
119                    yield (self.SUBSECTION_END, subsection_title, None)
120                title, rest = self._partition_subsection_title(line)
121                subsection_title = title
122                yield (self.SUBSECTION_START, subsection_title, rest)
123
124        # Close any remaining sections/entries
125        if subsection_title is not None:
126            yield (self.SUBSECTION_END, subsection_title, None)
127        if section_title is not None:
128            yield (self.SECTION_END, section_title, None)
129        if entry_offset is not None:
130            yield (self.ENTRY_END, None, None)
131
132    def parse_string(self, string):
133        return self.parse(StringIO(string))
134
135    def _partition_section_title(self, line):
136        """
137        Split the section title from the rest of the line
138        """
139        try:
140            title, rest = line.split(" ", 1)
141        except ValueError:
142            # no contents, only section title
143            title = line.rstrip()
144            rest = ""
145        rest = rest.lstrip(" ")
146        return title, rest
147
148    def _partition_subsection_title(self, line):
149        """
150        Split the subsection title from the rest of the line
151        """
152        line = line.lstrip(" ")
153        return self._partition_section_title(line)
Note: See TracBrowser for help on using the repository browser.