Core API: Debugging

Debugging utilities for constructs

class construct.debug.Debugger(subcon)

A pdb-based debugger. When an exception occurs in the subcon, a debugger will appear and allow you to debug the error (and even fix it on-the-fly).

Parameters:subcon – the subcon to debug

Example:

>>> Debugger(Byte[3]).build([])
================================================================================
Debugging exception of <Range: None>:
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/debug.py", line 116, in _build
    obj.stack.append(a)
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py", line 1069, in _build
    raise RangeError("expected from %d to %d elements, found %d" % (self.min, self.max, len(obj)))
construct.core.RangeError: expected from 3 to 3 elements, found 0

> /home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py(1069)_build()
-> raise RangeError("expected from %d to %d elements, found %d" % (self.min, self.max, len(obj)))
(Pdb) 
================================================================================

>>> format = Struct(
...     "spam" / Debugger(Enum(Byte, A=1, B=2, C=3)),
... )
>>> format.parse(b"\xff")
================================================================================
Debugging exception of <Mapping: None>:
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py", line 2578, in _decode
    return self.decoding[obj]
KeyError: 255

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/debug.py", line 127, in _parse
    return self.subcon._parse(stream, context)
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py", line 308, in _parse
    return self._decode(self.subcon._parse(stream, context), context)
  File "/home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py", line 2583, in _decode
    raise MappingError("no decoding mapping for %r" % (obj,))
construct.core.MappingError: no decoding mapping for 255

(you can set the value of 'self.retval', which will be returned)
> /home/arkadiusz/Dokumenty/GitHub/construct/construct/core.py(2583)_decode()
-> raise MappingError("no decoding mapping for %r" % (obj,))
(Pdb) self.retval = "???"
(Pdb) q
class construct.debug.Probe(name=None, show_stream=True, show_context=True, show_stack=True, stream_lookahead=128, func=None)

A probe: dumps the context, stack frames, and stream content to the screen to aid the debugging process.

Parameters:
  • name – the display name
  • show_stream – whether or not to show stream contents. default is True. the stream must be seekable.
  • show_context – whether or not to show the context. default is True.
  • show_stack – whether or not to show the upper stack frames. default is True.
  • stream_lookahead – the number of bytes to dump when show_stack is set. default is 100.

Example:

>>> Struct("count"/Byte, "items"/Byte[this.count], Probe()).parse(b"\x05abcde")
================================================================================
Probe <unnamed 3>
EOF reached
Container: 
    count = 5
    items = ListContainer: 
        97
        98
        99
        100
        101
================================================================================
Container(count=5)(items=[97, 98, 99, 100, 101])

>>> (Byte >> Probe()).parse(b"?")
================================================================================
Probe <unnamed 1>
EOF reached
Container: 
    0 = 63
================================================================================
[63, None]
construct.debug.ProbeInto(func)

ProbeInto looks inside the context and extracts a part of it using a lambda instead of printing the entire context.

Example:

>>> st = "junk"/RepeatUntil(obj_ == 0,Byte) + "num"/Byte + Probe()
>>> st.parse(b"xcnzxmbjskahuiwerhquiehnsdjk\x00\xff")
================================================================================
Probe <unnamed 5>
path is parsing
EOF reached
Container: 
    junk = ListContainer: 
        120
        99
        110
        122
        120
        109
        98
        106
        115
        107
        97
        104
        117
        105
        119
        101
        114
        104
        113
        117
        105
        101
        104
        110
        115
        100
        106
        107
        0
    num = 255
================================================================================
Container(junk=[120, 99, 110, 122, 120, 109, 98, 106, 115, 107, 97, 104, 117, 105, 119, 101, 114, 104, 113, 117, 105, 101, 104, 110, 115, 100, 106, 107, 0])(num=255)

>>> st = "junk"/RepeatUntil(obj_ == 0,Byte) + "num"/Byte + ProbeInto(this.num)
>>> st.parse(b"xcnzxmbjskahuiwerhquiehnsdjk\x00\xff")
================================================================================
Probe <unnamed 6>
path is parsing
EOF reached
255
================================================================================
Container(junk=[120, 99, 110, 122, 120, 109, 98, 106, 115, 107, 97, 104, 117, 105, 119, 101, 114, 104, 113, 117, 105, 101, 104, 110, 115, 100, 106, 107, 0])(num=255)
construct.Error()

Raises an exception when triggered by parse or build. Can be used as a sentinel that blows a whistle when a conditional branch goes the wrong way, or to raise an error explicitly the declarative way.

Example:

>>> d = "x"/Int8sb >> IfThenElse(this.x > 0, Int8sb, Error)
>>> d.parse(b"\xff\x05")
construct.core.ExplicitError: Error field was activated during parsing