1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
from __future__ import unicode_literals
from . import nmea
__all__ = ['NMEAStreamReader']
ERRORS = ('raise', 'yield', 'ignore')
class NMEAStreamReader(object):
'''
Reads NMEA sentences from a stream.
'''
def __init__(self, stream=None, errors='raise'):
'''
Create NMEAStreamReader object.
`stream`: file-like object to read from, can be omitted to
pass data to `next` manually.
must support `.readline()` which returns a string
`errors`: behaviour when a parse error is encountered. can be one of:
`'raise'` (default) raise an exception immediately
`'yield'` yield the ParseError as an element in the
stream, and continue reading at the next line
`'ignore'` completely ignore and suppress the error, and
continue reading at the next line
'''
if errors not in ERRORS:
raise ValueError('errors must be one of {!r} (was: {!r})'
.format(ERRORS, errors))
self.errors = errors
self.stream = stream
self.buffer = ''
def next(self, data=None):
'''
consume `data` (if given, or calls `stream.read()` if `stream` was given
in the constructor) and yield a list of `NMEASentence` objects parsed
from the stream (may be empty)
'''
if data is None:
if self.stream:
data = self.stream.readline()
else:
return
lines = (self.buffer + data).split('\n')
self.buffer = lines.pop()
for line in lines:
try:
msg = nmea.NMEASentence.parse(line)
yield msg
except nmea.ParseError as e:
if self.errors == 'raise':
raise e
if self.errors == 'yield':
yield e
if self.errors == 'ignore':
pass
__next__ = next
def __iter__(self):
'''
Support the iterator protocol.
This allows NMEAStreamReader object to be used in a for loop.
for batch in NMEAStreamReader(stream):
for msg in batch:
print msg
'''
return self
|