A file-ish object that can have new data loaded into it. You can also push and pop line-matching predicates onto a stack. When the current predicate matches the current line, a false EOF response (i.e. empty string) is returned instead. This lets the parser adhere to a simple abst
| 44 | |
| 45 | |
| 46 | class BufferedSubFile(object): |
| 47 | """A file-ish object that can have new data loaded into it. |
| 48 | |
| 49 | You can also push and pop line-matching predicates onto a stack. When the |
| 50 | current predicate matches the current line, a false EOF response |
| 51 | (i.e. empty string) is returned instead. This lets the parser adhere to a |
| 52 | simple abstraction -- it parses until EOF closes the current message. |
| 53 | """ |
| 54 | def __init__(self): |
| 55 | # Text stream of the last partial line pushed into this object. |
| 56 | # See issue 22233 for why this is a text stream and not a list. |
| 57 | self._partial = StringIO(newline='') |
| 58 | # A deque of full, pushed lines |
| 59 | self._lines = deque() |
| 60 | # The stack of false-EOF checking predicates. |
| 61 | self._eofstack = [] |
| 62 | # A flag indicating whether the file has been closed or not. |
| 63 | self._closed = False |
| 64 | |
| 65 | def push_eof_matcher(self, pred): |
| 66 | self._eofstack.append(pred) |
| 67 | |
| 68 | def pop_eof_matcher(self): |
| 69 | return self._eofstack.pop() |
| 70 | |
| 71 | def close(self): |
| 72 | # Don't forget any trailing partial line. |
| 73 | self._partial.seek(0) |
| 74 | self.pushlines(self._partial.readlines()) |
| 75 | self._partial.seek(0) |
| 76 | self._partial.truncate() |
| 77 | self._closed = True |
| 78 | |
| 79 | def readline(self): |
| 80 | if not self._lines: |
| 81 | if self._closed: |
| 82 | return '' |
| 83 | return NeedMoreData |
| 84 | # Pop the line off the stack and see if it matches the current |
| 85 | # false-EOF predicate. |
| 86 | line = self._lines.popleft() |
| 87 | # RFC 2046, section 5.1.2 requires us to recognize outer level |
| 88 | # boundaries at any level of inner nesting. Do this, but be sure it's |
| 89 | # in the order of most to least nested. |
| 90 | for ateof in reversed(self._eofstack): |
| 91 | if ateof(line): |
| 92 | # We're at the false EOF. But push the last line back first. |
| 93 | self._lines.appendleft(line) |
| 94 | return '' |
| 95 | return line |
| 96 | |
| 97 | def unreadline(self, line): |
| 98 | # Let the consumer push a line back into the buffer. |
| 99 | assert line is not NeedMoreData |
| 100 | self._lines.appendleft(line) |
| 101 | |
| 102 | def push(self, data): |
| 103 | """Push some new data into this object.""" |
no outgoing calls
searching dependent graphs…