Skip to content

Commit

Permalink
Const updated: parameters reordered
Browse files Browse the repository at this point in the history
  • Loading branch information
arekbulski committed Jan 17, 2018
1 parent 3ea77e8 commit 561fede
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 21 deletions.
18 changes: 8 additions & 10 deletions construct/core.py
Expand Up @@ -1247,14 +1247,14 @@ def _sizeof(self, context, path):
#===============================================================================
class Const(Subconstruct):
r"""
Field enforcing a constant value. It is used for file signatures, to validate that the given pattern exists. When parsed, the value must match.
Field enforcing a constant value. It is used for file signatures, to validate that the given pattern exists. When parsed, the value must strictly match.
Usually a member of a Struct, where it can be anonymous (so it does not appear in parsed dictionary for simplicity).
Note that a variable length subcon may still provide positive verification. Const does not consume a precomputed amount of bytes (and hence does NOT require a fixed sized lenghtfield), but depends on the subcon to read the appropriate amount (eg. VarInt is acceptable).
:param subcon: the subcon used to build value from, or a bytes value
:param value: optional, the expected value
:param value: the expected value, or a bytes literal
:param subcon: optional, the subcon used to build value from, Bytes if value was a bytes literal
:raises ConstError: when parsed data does not match specified value, or building from wrong value
Expand All @@ -1266,23 +1266,21 @@ class Const(Subconstruct):
>>> d.parse(b"JPEG")
construct.core.ConstError: expected b'IHDR' but parsed b'JPEG'
>>> d = Const(Int32ul, 16)
>>> d = Const(16, Int32ul)
>>> d.build(None)
b'\x10\x00\x00\x00'
"""
__slots__ = ["value"]
def __init__(self, subcon, value=None):
if value is None:
subcon, value = Bytes(len(subcon)), subcon
if isinstance(subcon, str):
subcon, value = Bytes(len(value)), value
def __init__(self, value, subcon=None):
if subcon is None:
subcon = Bytes(len(value))
super(Const, self).__init__(subcon)
self.value = value
self.flagbuildnone = True
def _parse(self, stream, context, path):
obj = self.subcon._parse(stream, context, path)
if obj != self.value:
raise ConstError("parsing expected %r but got %r" % (self.value, obj))
raise ConstError("parsing expected %r but parsed %r" % (self.value, obj))
return obj
def _build(self, obj, stream, context, path):
if obj not in (None, self.value):
Expand Down
4 changes: 2 additions & 2 deletions construct/examples/formats/graphics/emf.py
Expand Up @@ -111,7 +111,7 @@
)

header_record = Struct(
Const(record_type, "HEADER"),
Const("HEADER", record_type),
"record_size" / Int32ul, # Size of the record in bytes
"bounds_left" / Int32sl, # Left inclusive bounds
"bounds_right" / Int32sl, # Right inclusive bounds
Expand All @@ -121,7 +121,7 @@
"frame_right" / Int32sl, # Right side of inclusive picture frame
"frame_top" / Int32sl, # Top side of inclusive picture frame
"frame_bottom" / Int32sl, # Bottom side of inclusive picture frame
"signature" / Const(Int32ul, 0x464D4520),
"signature" / Const(0x464D4520, Int32ul),
"version" / Int32ul, # Version of the metafile
"size" / Int32ul, # Size of the metafile in bytes
"num_of_records" / Int32ul, # Number of records in the metafile
Expand Down
6 changes: 3 additions & 3 deletions construct/examples/formats/graphics/gif.py
Expand Up @@ -38,7 +38,7 @@
)

application_extension = Struct(
"block_size" / Const(Int8ul, 11),
"block_size" / Const(11, Int8ul),
"application_identifier" / String(8),
"application_auth_code" / String(3),
"data_sub_block" / data_sub_block,
Expand All @@ -51,7 +51,7 @@
)

graphic_control_extension = Struct(
"block_size" / Const(Int8ul, 4),
"block_size" / Const(4, Int8ul),
"flags" / BitStruct(
"reserved" / BitsInteger(3),
"disposal_method" / BitsInteger(3),
Expand All @@ -64,7 +64,7 @@
)

plain_text_extension = Struct(
"block_size" / Const(Int8ul, 12),
"block_size" / Const(12, Int8ul),
"text_left" / Int16ul,
"text_top" / Int16ul,
"text_width" / Int16ul,
Expand Down
4 changes: 2 additions & 2 deletions construct/examples/formats/graphics/wmf.py
Expand Up @@ -98,7 +98,7 @@
)

wmf_placeable_header = Struct(
"key" / Const(Int32ul, 0x9AC6CDD7),
"key" / Const(0x9AC6CDD7, Int32ul),
"handle" / Int16ul,
"left" / Int16sl,
"top" / Int16sl,
Expand All @@ -118,7 +118,7 @@
InMemory = 0,
File = 1,
),
"header_size" / Const(Int16ul, 9),
"header_size" / Const(9, Int16ul),
"version" / Int16ul,
"size" / Int32ul, # file size is in words
"number_of_objects" / Int16ul,
Expand Down
2 changes: 1 addition & 1 deletion construct/examples/protocols/ipstack.py
Expand Up @@ -126,7 +126,7 @@

ipv4_header = Struct(
EmbeddedBitStruct(
"version" / Const(Nibble, 4),
"version" / Const(4, Nibble),
"header_length" / ExprAdapter(Nibble,
decoder = lambda obj, ctx: obj * 4,
encoder = lambda obj, ctx: obj // 4,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_all.py
Expand Up @@ -343,11 +343,11 @@ def test_pointer(self):

def test_const(self):
common(Const(b"MZ"), b"MZ", b"MZ", 2)
common(Const(Bytes(4), b"****"), b"****", b"****", 4)
common(Const(Int32ul, 255), b"\xff\x00\x00\x00", 255, 4)
common(Const(b"****", Bytes(4)), b"****", b"****", 4)
common(Const(255, Int32ul), b"\xff\x00\x00\x00", 255, 4)
assert raises(Const(b"MZ").parse, b"ELF") == ConstError
assert raises(Const(b"MZ").build, b"???") == ConstError
assert raises(Const(Int32ul, 255).parse, b"\x00\x00\x00\x00") == ConstError
assert raises(Const(255, Int32ul).parse, b"\x00\x00\x00\x00") == ConstError
common(Struct(sig=Const(b"MZ")), b"MZ", Container(sig=b"MZ"), 2)
assert Struct(sig=Const(b"MZ")).build({}) == b"MZ"

Expand Down

3 comments on commit 561fede

@rytilahti
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be really nice if such a breaking change would be accompanied with a deprecation period of a week or two (and yielding a warning when using the wrong method), which would allow downstream developers to update their code accordingly. This change broke python-miio and it will take a bit before the fix (rytilahti/python-miio#158) will be delivered to those who are not running it from git :-P

@arekbulski
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit-attached conversations are difficult to track. Please open an issue and just copy paste your post. I will reply there. :)

@rytilahti
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I created an RFC on the matter :-)

Please sign in to comment.