Skip to content

Commit 2a8a86c

Browse files
Paul OsbornePaul Osborne
authored andcommitted
fields: use polymorphism for effective substructure determination
This code is functionally equivalent to the previous version for ConditionalField, but we now properly consider other fields that could wrap SubstructureField to be SubstructureField to be such (e.g. LengthField, TypeField). This change also adds **kwargs to unpack() on all fields for consistency and expansion as needed in the future. Signed-off-by: Paul Osborne <Paul.Osborne@digi.com>
1 parent 936a6b3 commit 2a8a86c

File tree

2 files changed

+39
-27
lines changed

2 files changed

+39
-27
lines changed

suitcase/fields.py

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ def _ph2f(self, placeholder):
8282
def __repr__(self):
8383
return repr(self.getval())
8484

85+
def is_substructure(self):
86+
"""Return True if this field is (effectively) a SubstructureField"""
87+
return False
88+
8589
def getval(self):
8690
return self._value
8791

@@ -175,8 +179,8 @@ def pack(self, stream):
175179
# write placeholder during the first pass
176180
stream.write(b'\x00' * self.field.bytes_required)
177181

178-
def unpack(self, data):
179-
self.field.unpack(data)
182+
def unpack(self, data, **kwargs):
183+
self.field.unpack(data, **kwargs)
180184

181185

182186
class Magic(BaseField):
@@ -196,7 +200,7 @@ def setval(self, *args):
196200
def pack(self, stream):
197201
stream.write(self.expected_sequence)
198202

199-
def unpack(self, data):
203+
def unpack(self, data, **kwargs):
200204
if not data == self.expected_sequence:
201205
raise SuitcaseParseError(
202206
"Expected sequence %r for magic field but got %r on "
@@ -270,7 +274,7 @@ def setval(self, value):
270274

271275
self.field.setval(onset(value))
272276

273-
def unpack(self, data):
277+
def unpack(self, data, **kwargs):
274278
pass
275279

276280
def pack(self, stream):
@@ -317,7 +321,7 @@ def __repr__(self):
317321
def pack(self, stream):
318322
return self.field.pack(stream)
319323

320-
def unpack(self, data):
324+
def unpack(self, data, **kwargs):
321325
assert len(data) == self.bytes_required
322326
return self.field.unpack(data)
323327

@@ -392,7 +396,7 @@ def setval(self, value):
392396
def pack(self, stream):
393397
return self._value._packer.write(stream)
394398

395-
def unpack(self, data):
399+
def unpack(self, data, **kwargs):
396400
target_msg_type = self._lookup_msg_type()
397401
if target_msg_type is None:
398402
target_msg_type = self.dispatch_mapping.get(None)
@@ -446,6 +450,9 @@ def _default_get_length(self, field):
446450
def _default_set_length(self, field, length):
447451
field._value = length # TODO: use setval() [problem with DependentField tests]?
448452

453+
def is_substructure(self):
454+
return self.length_field.is_substructure()
455+
449456
@property
450457
def bytes_required(self):
451458
return self.length_field.bytes_required
@@ -474,9 +481,9 @@ def pack(self, stream):
474481
self.set_length(self.length_field, self.length_value_provider())
475482
self.length_field.pack(stream)
476483

477-
def unpack(self, data):
484+
def unpack(self, data, **kwargs):
478485
assert len(data) == self.bytes_required
479-
return self.length_field.unpack(data)
486+
return self.length_field.unpack(data, **kwargs)
480487

481488
def get_adjusted_length(self):
482489
return self.get_length(self.length_field) * self.multiplier
@@ -532,6 +539,9 @@ def _lookup_msg_length(self):
532539
def __repr__(self):
533540
return repr(self.type_field)
534541

542+
def is_substructure(self):
543+
return self.type_field.is_substructure()
544+
535545
@property
536546
def bytes_required(self):
537547
return self.type_field.bytes_required
@@ -563,9 +573,9 @@ def pack(self, stream):
563573

564574
self.type_field.pack(stream)
565575

566-
def unpack(self, data):
576+
def unpack(self, data, **kwargs):
567577
assert len(data) == self.bytes_required
568-
return self.type_field.unpack(data)
578+
return self.type_field.unpack(data, **kwargs)
569579

570580
def get_adjusted_length(self):
571581
return self._lookup_msg_length()
@@ -601,6 +611,9 @@ def __repr__(self):
601611
else:
602612
return "<ConditionalField: not included>"
603613

614+
def is_substructure(self):
615+
return self.field.is_substructure()
616+
604617
@property
605618
def bytes_required(self):
606619
if self.condition(self._parent):
@@ -666,7 +679,7 @@ def bytes_required(self):
666679
def pack(self, stream):
667680
stream.write(self._value)
668681

669-
def unpack(self, data):
682+
def unpack(self, data, **kwargs):
670683
self._value = data
671684

672685

@@ -693,7 +706,7 @@ def pack(self, stream):
693706
except struct.error as e:
694707
raise SuitcasePackStructException(e)
695708

696-
def unpack(self, data):
709+
def unpack(self, data, **kwargs):
697710
assert len(data) == self.bytes_required
698711

699712
length = self.bytes_required
@@ -752,7 +765,7 @@ def __getattr__(self, attr):
752765
def pack(self, stream):
753766
pass
754767

755-
def unpack(self, data):
768+
def unpack(self, data, **kwargs):
756769
pass
757770

758771
def getval(self):
@@ -803,6 +816,9 @@ def __init__(self, substructure, **kwargs):
803816
self.substructure = substructure
804817
self._value = substructure()
805818

819+
def is_substructure(self):
820+
return True
821+
806822
@property
807823
def bytes_required(self):
808824
# We return None but do not count as a greedy field to the packer
@@ -811,9 +827,9 @@ def bytes_required(self):
811827
def pack(self, stream):
812828
stream.write(self._value.pack())
813829

814-
def unpack(self, data, trailing):
830+
def unpack(self, data, **kwargs):
815831
self._value = self.substructure()
816-
return self._value.unpack(data, trailing)
832+
return self._value.unpack(data, **kwargs)
817833

818834

819835
class FieldArray(BaseField):
@@ -868,10 +884,11 @@ def pack(self, stream):
868884
for structure in self._value:
869885
stream.write(structure.pack())
870886

871-
def unpack(self, data):
887+
def unpack(self, data, **kwargs):
888+
kwargs['trailing'] = True
872889
while True:
873890
structure = self.substructure()
874-
data = structure.unpack(data, trailing=True).read()
891+
data = structure.unpack(data, **kwargs).read()
875892
self._value.append(structure)
876893
if data == b"":
877894
break
@@ -891,7 +908,7 @@ def pack(self, stream):
891908
except struct.error as e:
892909
raise SuitcasePackStructException(e)
893910

894-
def unpack(self, data):
911+
def unpack(self, data, **kwargs):
895912
try:
896913
self._value = struct.unpack(self.format, data)
897914
except struct.error as e:
@@ -950,7 +967,7 @@ def pack(self, stream):
950967
raise SuitcasePackStructException(e)
951968
stream.write(to_write)
952969

953-
def unpack(self, data):
970+
def unpack(self, data, **kwargs):
954971
value = 0
955972
if self.UNPACK_FORMAT[0] == b">"[0]: # The element access makes this compatible with Python 2 and 3
956973
for i, byte in enumerate(reversed(struct.unpack(self.UNPACK_FORMAT, data))):
@@ -1366,8 +1383,8 @@ def pack(self, stream):
13661383
out = sio.getvalue()[-self.number_bytes:]
13671384
stream.write(out)
13681385

1369-
def unpack(self, data):
1370-
self._field.unpack(data)
1386+
def unpack(self, data, **kwargs):
1387+
self._field.unpack(data, **kwargs)
13711388
value = self._field.getval()
13721389
shift = self.number_bits
13731390
for _key, field in self._ordered_bitfields:

suitcase/structure.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,6 @@ def unpack_stream(self, stream):
8686
logic present for dealing with checksum fields.
8787
8888
"""
89-
def is_substructure(field):
90-
return isinstance(field, SubstructureField) or \
91-
isinstance(field, ConditionalField) and \
92-
isinstance(field.field, SubstructureField)
93-
9489
crc_fields = []
9590
greedy_field = None
9691
# go through the fields from first to last. If we hit a greedy
@@ -99,7 +94,7 @@ def is_substructure(field):
9994
if isinstance(field, CRCField):
10095
crc_fields.append((field, stream.tell()))
10196
length = field.bytes_required
102-
if is_substructure(field):
97+
if field.is_substructure():
10398
remaining_data = stream.getvalue()[stream.tell():]
10499
returned_stream = field.unpack(remaining_data, trailing=True)
105100
if returned_stream is not None:

0 commit comments

Comments
 (0)