Source code for fixedrec.record

from .utils import n_, pset


[docs]class Record(object): """Record base class, providing attribute access and pretty printing. Usage:: @register_record class StatusRecord(Record): RECTYPE = 'ver' layout = Layout( '=4sQ10sH12xHcc', 'rectype', 'timestamp', 'version', 'reclen', 'pad' 'chksum', 'cr', 'nl', name="StatusRecord" ) def __init__(self, data=None, **kw): super(StatusRecord, self).__init__( StatusRecord.layout, data, **kw ) if data is None: self.rectype = StatusRecord.RECTYPE self.version = '1.0.0' self.reclen = len(StatusRecord.layout) self.cr = b'\\r' self.nl = b'\\n' self.set_checksum() def set_checksum(self): # checksum of all preceeding fields. cksm_field = self._layout['chksum'] cksm = utils.bsd_checksum(self._data[:cksm_field.position]) cksm_field.set_value(self._data, cksm) """ def __init__(self, layout, data=None, **kw): """`layout` should be a :class:`Layout` object. `data` should be raw data read from file. `**kw` can be used to set field values directly. """ self._layout = layout self._data = bytearray(data if data is not None else len(self._layout)) # set individual fields for k, v in kw.items(): setattr(self, k, v) def __len__(self): """The record length is defined by the length of its layout. """ return len(self._layout) def __getattr__(self, attr): """Get an attribute (note: attributes of Record, or its sub classes takes precedence over field names. """ try: return super(Record, self).__getattr__(attr) except AttributeError: return self._layout[attr].get_value(self._data) def __setattr__(self, attr, val): """All instance variables of Record start with an underscore soas not to conflict with any field names. """ if attr.startswith('_') or attr not in self._layout: return super(Record, self).__setattr__(attr, val) self._layout[attr].set_value(self._data, val) return val
[docs] def parts(self): """Return data for each field of the layout. """ return self._layout.split(str(self._data))
[docs] def pretty_parts(self): """Make binary data more readable by converting padding bytes in string fields to underscore (`_`) and padding fields to star (`*`). """ res = [] for i, p in enumerate(self.parts()): if self._layout[i].format == 's': res.append(n_(p)) elif self._layout[i].format == 'x': res.append(n_(p, '*')) else: res.append(p) return res
def __repr__(self): return str(self.pretty_parts())
[docs] def as_dict(self): """Or at least as close to a dict as we can get and still preserve field order. """ parts = self._layout.split(str(self._data)) return pset(zip(self._layout.names, self.pretty_parts()))