Core API: Conditional

construct.Union(parsefrom, *subcons, **kw)

Treats the same data as multiple constructs (similar to C union statement) so you can look at the data in multiple views.

When parsing, all fields read the same data bytes, but stream remains at initial offset, unless parsefrom selects a subcon by index or name. When building, the first subcon that can find an entry in the dict (or builds from None, so it does not require an entry) is automatically selected.

Warning

If you skip the parsefrom parameter then stream will be left back at the starting offset. Many users fail to use this properly.

Parameters:
  • parsefrom – how to leave stream after parsing, can be integer index or string name selecting a subcon, None (leaves stream at initial offset, the default), a context lambda returning either of previously mentioned
  • subcons – subconstructs (order and name sensitive)

Example:

>>> d = Union(0, "raw"/Bytes(8), "ints"/Int32ub[2], "shorts"/Int16ub[4], "chars"/Byte[8])
>>> d.parse(b"12345678")
Container(raw=b'12345678')(ints=[825373492, 892745528])(shorts=[12594, 13108, 13622, 14136])(chars=[49, 50, 51, 52, 53, 54, 55, 56])
>>> d.build(dict(chars=range(8)))
b'\x00\x01\x02\x03\x04\x05\x06\x07'

Alternative syntax, note this works ONLY on python 3.6+:
>>> Union(0, raw=Bytes(8), ints=Int32ub[2], shorts=Int16ub[4], chars=Byte[8])
construct.Select(*subcons, **kw)

Selects the first matching subconstruct. It will literally try each of the subconstructs, until one matches.

Parameters:
  • subcons – the subcons to try (order sensitive)
  • includename – indicates whether to include the name of the selected subcon in the return value of parsing, default is False

Example:

>>> d = Select(Int32ub, CString(encoding="utf8"))
>>> d.build(1)
b'\x00\x00\x00\x01'
>>> d.build(u"Афон")
b'\xd0\x90\xd1\x84\xd0\xbe\xd0\xbd\x00'

Alternative syntax, note this works ONLY on python 3.6+:
>>> Select(num=Int32ub, text=CString(encoding="utf8"))
construct.Optional(subcon)

Makes an optional construct, that tries to parse the subcon. If parsing fails, returns None. If building fails, writes nothing.

Size cannot be computed, because whether bytes are consumed or produced depends on actual data and context.

Parameters:subcon – the subcon to optionally parse or build

Example:

>>> d = Optional(Int64ul)
>>> d.parse(b"12345678")
4050765991979987505
>>> d.parse(b"")
None
>>> d.build(1)
b'\x01\x00\x00\x00\x00\x00\x00\x00'
>>> d.build(None)
b''
construct.If(predicate, subcon)

An if-then conditional construct. If the context predicate indicates True, the subcon will be used for parsing and building, otherwise parsing returns None and building is no-op. Note that the predicate has no access to parsed value, it computes only on context.

Parameters:
  • predicate – a function taking context and returning a bool
  • subcon – the subcon that will be used if the predicate returns True

Example:

>>> d = If(this.x > 0, Byte)
>>> d.build(255, dict(x=1))
b'\xff'
>>> d.build(255, dict(x=0))
b''
construct.IfThenElse(predicate, thensubcon, elsesubcon)

An if-then-else conditional construct. One of the two subcons is used for parsing or building, depending whether the predicate returns a truthy or falsey value for given context. Constant truthy value can also be used.

Parameters:
  • predicate – a context function that returns a bool (or truthy value)
  • thensubcon – the subcon that will be used if the predicate indicates True
  • elsesubcon – the subcon that will be used if the predicate indicates False

Example:

>>> d = IfThenElse(this.x > 0, VarInt, Byte)
>>> d.build(255, dict(x=1))
b'\xff\x01'
>>> d.build(255, dict(x=0))
b'\xff'
construct.Switch(keyfunc, cases, default=<NoDefault: None>, includekey=False)

A conditional branch. Switch will choose the case to follow based on the return value of keyfunc. If no case is matched and no default value is given, SwitchError will be raised.

Warning

You can use Embedded(Switch(…)) but not Switch(Embedded(…)). Same applies to If and IfThenElse macros.

Parameters:
  • keyfunc – a context function that returns a key which will choose a case, or a constant
  • cases – a dictionary mapping keys to subcons
  • default – a default field to use when the key is not found in the cases. if not supplied, an exception will be raised when the key is not found. Pass can be used for do-nothing
  • includekey – whether to include the key in the return value of parsing, default is False
Raises:

SwitchError – when actual value is not in the dict nor a default is given

Example:

>>> d = Switch(this.n, { 1:Int8ub, 2:Int16ub, 4:Int32ub })
>>> d.build(5, dict(n=1))
b'\x05'
>>> d.build(5, dict(n=4))
b'\x00\x00\x00\x05'
construct.StopIf(condfunc)

Checks for a condition, and stops a Struct/Sequence/Range from parsing or building further.

Parameters:condfunc – a context function returning a bool (or truthy value)

Example:

>>> Struct('x'/Byte, StopIf(this.x == 0), 'y'/Byte)
>>> Sequence('x'/Byte, StopIf(this.x == 0), 'y'/Byte)
>>> GreedyRange(FocusedSeq(0, 'x'/Byte, StopIf(this.x == 0)))