Package Bio :: Module ParserSupport
[hide private]
[frames] | no frames]

Source Code for Module Bio.ParserSupport

  1  # Copyright 1999 by Jeffrey Chang.  All rights reserved. 
  2  # This code is part of the Biopython distribution and governed by its 
  3  # license.  Please see the LICENSE file that should have been included 
  4  # as part of this package. 
  5   
  6  """Code to support writing parsers (DEPRECATED). 
  7   
  8  Classes: 
  9   - AbstractParser         Base class for parsers. 
 10   - AbstractConsumer       Base class of all Consumers. 
 11   - TaggingConsumer        Consumer that tags output with its event.  For debugging 
 12   
 13  Functions: 
 14   - safe_readline          Read a line from a handle, with check for EOF. 
 15   - safe_peekline          Peek at next line, with check for EOF. 
 16   - read_and_call          Read a line from a handle and pass it to a method. 
 17   - read_and_call_while    Read many lines, as long as a condition is met. 
 18   - read_and_call_until    Read many lines, until a condition is met. 
 19   - attempt_read_and_call  Like read_and_call, but forgiving of errors. 
 20   - is_blank_line          Test whether a line is blank. 
 21   
 22  """ 
 23   
 24  import sys 
 25  from Bio._py3k import StringIO 
 26   
 27  from Bio import BiopythonDeprecationWarning 
 28  import warnings 
 29  warnings.warn("Bio.ParserSupport is now deprecated will be removed in a " 
 30                "future release of Biopython.", BiopythonDeprecationWarning) 
 31   
 32   
33 -class AbstractParser(object):
34 """Base class for other parsers.""" 35
36 - def parse(self, handle):
37 raise NotImplementedError("Please implement in a derived class")
38
39 - def parse_str(self, string):
40 return self.parse(StringIO(string))
41
42 - def parse_file(self, filename):
43 with open(filename) as h: 44 retval = self.parse(h) 45 return retval
46 47
48 -class AbstractConsumer(object):
49 """Base class for other Consumers. 50 51 Derive Consumers from this class and implement appropriate 52 methods for each event that you want to receive. 53 54 """ 55
56 - def _unhandled_section(self):
57 pass
58
59 - def _unhandled(self, data):
60 pass
61
62 - def __getattr__(self, attr):
63 if attr[:6] == 'start_' or attr[:4] == 'end_': 64 method = self._unhandled_section 65 else: 66 method = self._unhandled 67 return method
68 69
70 -class TaggingConsumer(AbstractConsumer):
71 """Debugging consumer which tags data with the event and logs it. 72 73 This is a Consumer that tags the data stream with the event and 74 prints it to a handle. Useful for debugging. 75 76 """ 77
78 - def __init__(self, handle=None, colwidth=15, maxwidth=80):
79 """Initialize. 80 81 Arguments: 82 - handle to log to, defaults to `sys.stdout` 83 - colwidth for logging to the handle 84 - maxwidth for truncation when logging 85 86 """ 87 # I can't assign sys.stdout to handle in the argument list. 88 # If I do that, handle will be assigned the value of sys.stdout 89 # the first time this function is called. This will fail if 90 # the user has assigned sys.stdout to some other file, which may 91 # be closed or invalid at a later time. 92 if handle is None: 93 handle = sys.stdout 94 self._handle = handle 95 self._colwidth = colwidth 96 self._maxwidth = maxwidth
97
98 - def unhandled_section(self):
99 self._print_name('unhandled_section')
100
101 - def unhandled(self, data):
102 self._print_name('unhandled', data)
103
104 - def _print_name(self, name, data=None):
105 if data is None: 106 # Write the name of a section. 107 self._handle.write("%s %s\n" % ("*" * self._colwidth, name)) 108 else: 109 # Write the tag and line. 110 self._handle.write("%-*s: %s\n" % ( 111 self._colwidth, name[:self._colwidth], 112 data[:self._maxwidth - self._colwidth - 2].rstrip()))
113
114 - def __getattr__(self, attr):
115 if attr[:6] == 'start_' or attr[:4] == 'end_': 116 method = lambda a=attr, s=self: s._print_name(a) 117 else: 118 method = lambda x, a=attr, s=self: s._print_name(a, x) 119 return method
120 121
122 -def read_and_call(uhandle, method, **keywds):
123 """Read line and pass it to the method. 124 125 Read a line from uhandle, check it, and pass it to the method. 126 Raises a ValueError if the line does not pass the checks. 127 128 start, end, contains, blank, and has_re specify optional conditions 129 that the line must pass. start and end specifies what the line must 130 begin or end with (not counting EOL characters). contains 131 specifies a substring that must be found in the line. If blank 132 is a true value, then the line must be blank. has_re should be 133 a regular expression object with a pattern that the line must match 134 somewhere. 135 136 """ 137 line = safe_readline(uhandle) 138 errmsg = _fails_conditions(*(line,), **keywds) 139 if errmsg is not None: 140 raise ValueError(errmsg) 141 method(line)
142 143
144 -def read_and_call_while(uhandle, method, **keywds):
145 """Read line and pass it to the method while condition is true. 146 147 Read a line from uhandle and pass it to the method as long as 148 some condition is true. Returns the number of lines that were read. 149 150 See the docstring for read_and_call for a description of the parameters. 151 152 """ 153 nlines = 0 154 while True: 155 line = safe_readline(uhandle) 156 # If I've failed the condition, then stop reading the line. 157 if _fails_conditions(*(line,), **keywds): 158 uhandle.saveline(line) 159 break 160 method(line) 161 nlines = nlines + 1 162 return nlines
163 164
165 -def read_and_call_until(uhandle, method, **keywds):
166 """Read line and pass it to the method until condition is true. 167 168 Read a line from uhandle and pass it to the method until 169 some condition is true. Returns the number of lines that were read. 170 171 See the docstring for read_and_call for a description of the parameters. 172 173 """ 174 nlines = 0 175 while True: 176 line = safe_readline(uhandle) 177 # If I've met the condition, then stop reading the line. 178 if not _fails_conditions(*(line,), **keywds): 179 uhandle.saveline(line) 180 break 181 method(line) 182 nlines = nlines + 1 183 return nlines
184 185
186 -def attempt_read_and_call(uhandle, method, **keywds):
187 """Attempt read line and call method. 188 189 Similar to read_and_call, but returns a boolean specifying 190 whether the line has passed the checks. Does not raise 191 exceptions. 192 193 See docs for read_and_call for a description of the function 194 arguments. 195 196 """ 197 line = safe_readline(uhandle) 198 passed = not _fails_conditions(*(line,), **keywds) 199 if passed: 200 method(line) 201 else: 202 uhandle.saveline(line) 203 return passed
204 205
206 -def _fails_conditions(line, start=None, end=None, contains=None, blank=None, 207 has_re=None):
208 if start is not None: 209 if line[:len(start)] != start: 210 return "Line does not start with '%s':\n%s" % (start, line) 211 if end is not None: 212 if line.rstrip()[-len(end):] != end: 213 return "Line does not end with '%s':\n%s" % (end, line) 214 if contains is not None: 215 if contains not in line: 216 return "Line does not contain '%s':\n%s" % (contains, line) 217 if blank is not None: 218 if blank: 219 if not is_blank_line(line): 220 return "Expected blank line, but got:\n%s" % line 221 else: 222 if is_blank_line(line): 223 return "Expected non-blank line, but got a blank one" 224 if has_re is not None: 225 if has_re.search(line) is None: 226 return "Line does not match regex '%s':\n%s" % ( 227 has_re.pattern, line) 228 return None
229 230
231 -def is_blank_line(line, allow_spaces=0):
232 """Check if a line is blank. 233 234 Return whether a line is blank. allow_spaces specifies whether to 235 allow whitespaces in a blank line. A true value signifies that a 236 line containing whitespaces as well as end-of-line characters 237 should be considered blank. 238 239 """ 240 if not line: 241 return 1 242 if allow_spaces: 243 return line.rstrip() == '' 244 return line[0] == '\n' or line[0] == '\r'
245 246
247 -def safe_readline(handle):
248 """Read a line, otherwise raises ValueError. 249 250 Read a line from an UndoHandle and return it. If there are no more 251 lines to read, I will raise a ValueError. 252 253 """ 254 line = handle.readline() 255 if not line: 256 raise ValueError("Unexpected end of stream.") 257 return line
258 259
260 -def safe_peekline(handle):
261 """Peek at the next line if present, otherwise raises ValueError. 262 263 Peek at the next line in an UndoHandle and return it. If there are no 264 more lines to peek, I will raise a ValueError. 265 266 """ 267 line = handle.peekline() 268 if not line: 269 raise ValueError("Unexpected end of stream.") 270 return line
271