construct-typing
construct-typing copied to clipboard
!!! EXPERIMENTAL VERSION !!!
The README section for construct_typed
has this big !!! EXPERIMENTAL VERSION !!!
health warning on it, and I'm curious what that entails. For example, is it saying it might not work? Or perhaps that it might change a lot?
The warning refers mostly to the fact that there may still be conceptual changes to DataclassStruct
, DataclassBitStruct
, TEnum
and TFlagsEnum
. But I also can't rule out bugs in principle, because this library is not tested well enough yet. Currently I am testing the following two changes. If you have other suggestions/tips they are welcome.
1. Combine dataclass and construct-format What still bothers me in my current implementation is that the dataclass and the construct-format are two independent objects. I am currently experimenting how to combine the two like this:
Current usage (dataclass and the construct-format are independent):
@dataclasses.dataclass
class Image(DataclassMixin):
width: int = csfield(Int8ub)
height: int = csfield(Int8ub)
pixels: t.List[int] = csfield(Array(this.width * this.height, Byte))
format = DataclassStruct(Image)
print(format.parse(b"BMP\x01\x03\x02\x07\x08\t\x0b\x0c\r"))
My prefered usage (dataclass and the construct-format are combined in one object):
@construct_typed.struct
class Image:
width: int = csfield(Int8ub)
height: int = csfield(Int8ub)
pixels: t.List[int] = csfield(Array(this.width * this.height, Byte))
print(Image.parse(b"BMP\x01\x03\x02\x07\x08\t\x0b\x0c\r"))
But my prefered usage is tricky together with static type checkers like pyright/pylance which I use the most of the time.
2. Change dataclasses to attrs
Also I am experimenting if it makes sense to switch from dataclasses
to attrs
, because attrs offers a few more features.
What I am missing the most in dataclasses
is kw_only
which maybe helps with Default
or Const
constructs. This is only available from Python 3.10. But in attrs it is available for a longer time.
Wouldn't something like this work? (of course I totally did not think about typing issues here :))
class EnhancedDataclassMixin(DataclassMixin):
@classmethod
def _get_format(cls):
return DataclassStruct(cls)
@classmethod
def build(cls, obj):
return cls._get_format().build(obj)
@classmethod
def parse(cls, data):
return cls._get_format().parse(data)
@dataclasses.dataclass
class Image(EnhancedDataclassMixin):
width: int = csfield(Int8ub)
height: int = csfield(Int8ub)
pixels: t.List[int] = csfield(Array(this.width * this.height, Byte))
raw = b'\x01\x03\x01\x02\x03'
obj = Image.parse(raw)
assert Image.build(obj) == raw
Yes, I had also tried out something like that. The problem is that if you want to embed Image
in another structure you always have to write Image._get_format()
. I would prefer that you only have to write Image
.
That's why I already tried to make the metaclass of EnhancedDataclassMixin
derived from the class Construct
, so that the class type itself is a Construct. But unfortunately I didn't manage to do that as I had imagined...
Embedding would work as well, I have implemented a small mod for example for this on a branch: https://github.com/waszil/construct-typing/commit/479b51344bfd95149596a75ee574ac2e63c032df
In your particular case your implementation works. But this is not a general solution for the problem. If you embed e.g. SubStruct
from your test into another construct like Array
then it doesn't work like that anymore:
@dataclasses.dataclass
class MainStruct(EnhancedDataclassMixin):
a: int = csfield(Int8ub)
b: int = csfield(Int8ub)
# here, we can simply use `SubStruct`, as csfield will recognize it and get the DataclassStruct(...) format.
sub_struct: List[SubStruct] = csfield(Array(2, SubStruct))