Permalink
Browse files

Store fields in an OrderedDict to better support Structure subclassing

  • Loading branch information...
1 parent fad92ca commit 5bc193bc2d9c936b26a9e91693e1c6e35c7da4a7 @gulopine committed Jul 23, 2011
View
@@ -31,11 +31,11 @@ def get_raw_bytes(self):
output = bytearray()
bits_read = 0
byte = 0
- for field in self.__class__._fields:
- if field.name not in self._raw_values:
- setattr(self, field.name, getattr(self, field.name))
+ for name, field in self.__class__._fields.items():
+ if name not in self._raw_values:
+ setattr(self, name, getattr(self, name))
bits_read += field.size
- bits = self._raw_values[field.name]
+ bits = self._raw_values[name]
byte = (byte << field.size) + bits
while bits_read >= 8:
byte >>= 8
View
@@ -34,17 +34,17 @@ def write(self, data):
raise IOError("not writable")
file = EOFBytesIO(self._write_buffer + data)
last_position = 0
- for field in self.__class__._fields:
- if field.name not in self.__dict__:
+ for name, field in self.__class__._fields.items():
+ if name not in self.__dict__:
try:
try:
bytes = field.read(file)
value = field.decode(bytes)
except fields.FullyDecoded as obj:
bytes = obj.bytes
value = obj.value
- self._raw_values[field.name] = bytes
- self.__dict__[field.name] = value
+ self._raw_values[name] = bytes
+ self.__dict__[name] = value
last_position = file.tell()
except EOFError:
file.seek(last_position)
@@ -58,26 +58,26 @@ def tell(self):
def _extract(self, field):
if field.name not in self._raw_values:
- for other_field in self._fields:
- if other_field.name not in self._raw_values:
+ for name, other_field in self._fields.items():
+ if name not in self._raw_values:
with other_field.for_instance(self):
try:
bytes = other_field.read(self)
except fields.FullyDecoded as obj:
bytes = obj.bytes
- self.__dict__[other_field.name] = obj.value
- self._raw_values[other_field.name] = bytes
- if other_field.name == field.name:
+ self.__dict__[name] = obj.value
+ self._raw_values[name] = bytes
+ if name == field.name:
break
return self._raw_values[field.name]
def get_raw_bytes(self):
output = b''
- for field in self.__class__._fields:
- value = getattr(self, field.name)
- if field.name not in self._raw_values:
- setattr(self, field.name, getattr(self, field.name))
- output += self._raw_values[field.name]
+ for name, field in self.__class__._fields.items():
+ value = getattr(self, name)
+ if name not in self._raw_values:
+ setattr(self, name, getattr(self, name))
+ output += self._raw_values[name]
return output
def get_parent(self):
@@ -90,9 +90,9 @@ def save(self, file):
def validate(self):
errors = []
- for field in self._fields:
+ for name, field in self._fields.items():
try:
- field.validate(self, getattr(self, field.name))
+ field.validate(self, getattr(self, name))
except ValueError as error:
errors.append(str(error))
return errors
@@ -125,8 +125,8 @@ def parse(self, file):
position = file.tell()
try:
value = self.structure(file)
- for field in self.structure._fields:
- getattr(value, field.name)
+ for name, field in self.structure._fields.items():
+ getattr(value, name)
except Exception as e:
if file.tell() == position:
# The file didn't move, so it must be at the end
@@ -24,8 +24,8 @@ def __init__(self, *args, decompress=True, **kwargs):
if process_chunk:
super(ChunkMixin, self).__init__(chunk.payload)
payload = self._compressor.compress(data)
- for field in chunk._fields:
- getattr(chunk, field.name)
+ for name in chunk._fields:
+ getattr(chunk, name)
id = chunk.id
id = self._chunk.id
if chunk.id != self._chunk.id:
@@ -21,7 +21,7 @@ def attach_to_class(self, cls):
self.fields = []
in_range = False
- for field in cls._fields:
+ for field in cls._fields.values():
if field is self:
# Can't go beyond the integrity field itself
break
View
@@ -33,9 +33,9 @@ def read(cls, file):
# Force the evaluation of the entire structure in
# order to make sure other fields work properly
value_bytes = b''
- for field in cls.structure._fields:
- getattr(value, field.name)
- value_bytes += value._raw_values[field.name]
+ for name in cls.structure._fields:
+ getattr(value, name)
+ value_bytes += value._raw_values[name]
return value_bytes, value
@@ -47,8 +47,8 @@ class ChunkMixin:
def __init__(self, *args, process_chunk=True, **kwargs):
if process_chunk:
chunk = self._chunk.structure(*args, **kwargs)
- for field in chunk._fields:
- getattr(chunk, field.name)
+ for name in chunk._fields:
+ getattr(chunk, name)
id = chunk.id
id = self._chunk.id
if chunk.id != self._chunk.id:
@@ -123,16 +123,16 @@ def parse(self, file):
while 1:
chunk = self.base_chunk.structure(file)
if chunk.id in self.parsers:
- for field in chunk._fields:
- getattr(chunk, field.name)
+ for name in chunk._fields:
+ getattr(chunk, name)
value = self.parsers[chunk.id](chunk.payload, process_chunk=False)
if self.terminator and isinstance(chunk, self.terminator):
break
yield value
elif chunk.id:
# This is a valid chunk, just not a recognized type
- for field in chunk._fields:
- getattr(chunk, field.name)
+ for name in chunk._fields:
+ getattr(chunk, name)
yield chunk
else:
# This is not a valid chunk, which is probably the end of the file
View
@@ -117,7 +117,7 @@ def set_name(self, name):
self.label = label.title()
def attach_to_class(self, cls):
- cls._fields.append(self)
+ cls._fields[self.name] = self
def validate(self, obj, value):
# This should raise a ValueError if the value is invalid
@@ -217,7 +217,7 @@ def encode(self, value):
def __getattr__(self, name):
if 'structure' in self.__dict__:
field = getattr(self.structure, name)
- if field in self.structure._fields:
+ if field in self.structure._fields.values():
field = copy.copy(field)
field._parent = self
return field
View
@@ -33,10 +33,21 @@ def __new__(cls, name, bases, attrs, **options):
return type.__new__(cls, name, bases, attrs)
def __init__(cls, name, bases, attrs, **options):
- cls._fields = []
+ cls._fields = collections.OrderedDict()
+ # Go backwards so that the left-most classes take priority
+ print('%s: %s (%s)' % (name, ', '.join(b.__name__ for b in bases), cls))
+ for base in bases:
+ if hasattr(base, '_fields'):
+ print('%s %s' % (base, base._fields))
+ cls._fields.update(base._fields)
+
for name, attr in attrs.items():
+ if name in cls._fields and attr is None:
+ del cls._fields[name]
if hasattr(attr, 'attach_to_class'):
attr.attach_to_class(cls)
+
+ print('%s %s' % (cls, cls._fields))
data.field_options = {}
data.field_stack = [[]]

0 comments on commit 5bc193b

Please sign in to comment.