construct
construct copied to clipboard
MetaFiled requires length attribute to be present on build
This is more like a question rather an issue. I'd expect MEtaField's related length fiekd to be autopopulated on building a structure, however this does not happen:
>>> from construct import *
>>> foo = Struct("foo",
... Byte("length"),
... MetaField("data", lambda ctx: ctx["length"])
... )
>>> foo.build(Container(data="test"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/pymodules/python2.6/construct/core.py", line 206, in build
self.build_stream(obj, stream)
File "/usr/lib/pymodules/python2.6/construct/core.py", line 214, in build_stream
self._build(obj, stream, Container())
File "/usr/lib/pymodules/python2.6/construct/core.py", line 662, in _build
subobj = getattr(obj, sc.name)
AttributeError: 'Container' object has no attribute 'length'
Could you explain correct behavior?
Part of me wants to say "use a PascalString
," but that's not a good long-term solution, is it? The problem is mostly that there's no indication of the dependency of length
on data
in this Struct
, so Construct is a bit bamboozled about how to build this. PascalString
gets it right though.
Interesting question, I haven't looked at PascalString yet to see how that works. Haven't really had to do any serious 'building' yet, all parsing
In a library I created (not open sourced, unfortunately, as it is for my employer), I ended up doing the following. Unlike construct, the syntax for the DSL we ended up creating is more heavily metaclass based:
class PascalString(BaseMessage):
length = LengthField(UBInt8())
payload = VariableRawPayload(length)
Variable length fields require either a static length or a length_field parameter. These two are couple on message instances and I can pack a message with the correct length automatically:
>>> m = PascalString()
>>> m.payload = "Hello, world"
>>> m.pack()
"\x0cHello, World"
The invariant in our system is that when unpacking the length of the next field being unpacked must always be known immediately before it will be unpacked. In most cases this is the case. In other cases (for instance, a delimiter in a chunk) we currently just handle that outside of our library or create a special construct.