binobj v0.11.0 ## Expected Behavior Calculation of `len` of the structure with variable-sized substructure in a container field, when a substructure passed as an instance. ## Current Behavior It calculates the correct length if a substructure defined as a dictionary and raises an exception if a substructure passed as an instance. In both cases `.to_bytes()` works correctly. The same problem occurs with other container fields. ## Steps to Reproduce 1. Setup ```python class SubStruct(binobj.Struct): length = fields.UInt16(endian="big") value = fields.String(size="length", pad_byte=b"\x00") class MainStruct(binobj.Struct): nested = fields.Nested(SubStruct) ``` 2. Correct behavior ```python data = MainStruct(nested={"length": 10, "value": "HllWrld"}) print(data.to_bytes()) # b'\x00\nHllWrld\x00\x00\x00' print(len(data)) # 12 ``` 3. Exception ```python data = MainStruct(nested=SubStruct(length=10, value="HllWrld")) print(data.to_bytes()) # b'\x00\nHllWrld\x00\x00\x00' print(len(data)) # Exception ``` 4. Traceback ``` Traceback (most recent call last): File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\structures.py:665 in __len__ size += field.get_expected_size(current_fields) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\fields\base.py:612 in get_expected_size return self.__get_expected_possibly_undefined_size(field_values) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\fields\base.py:673 in __get_expected_possibly_undefined_size raise errors.UndefinedSizeError(field=self) UndefinedSizeError: Size of field Nested(name='nested') couldn't be determined. The field might not have had its `size` set, or a variable-sized field has a bug. During handling of the above exception, another exception occurred: Traceback (most recent call last): Cell In[93], line 5 print(len(data)) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\structures.py:668 in __len__ size += len(field.to_bytes(field_value)) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\fields\base.py:901 in to_bytes self.to_stream(stream, data, context=context, all_fields=all_fields) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\fields\base.py:855 in to_stream self._do_dump(buf, data, context=context, all_fields=all_fields) File ~\AppData\Local\Programs\Python\Python311\Lib\site-packages\binobj\fields\containers.py:337 in _do_dump instance = self.struct_class(**typing.cast(StrDict, data)) TypeError: __main__.SubStruct() argument after ** must be a mapping, not SubStruct ``` ## Possible Solution Since in this case the length is determined by dumping and taking the resulting real size, passing creation of the new instance could help. Something like this: ```python class Nested(Field[TStruct]): def _do_dump( self, stream: BinaryIO, data: _Union[StrDict, TStruct] context: Any, all_fields: StrDict, ) -> None: if isinstance(data, Struct): instance = data else: instance = self.struct_class(**typing.cast(StrDict, data)) return instance.to_stream(stream, context) ```
This issue appears to be discussing a feature request or bug report related to the repository. Based on the content, it seems to be resolved. The issue was opened by kirill-varchenko and has received 2 comments.