[plum] Tutorial: Byte Breakdown Summaries

Variants to the pack() and unpack() utility functions exist for obtaining a byte by byte summary of the transformation:

>>> from plum.littleendian import uint8
>>> from plum.structure import Structure, member
>>> from plum.utilities import pack_and_dump, unpack_and_dump
>>>
>>> class MyStruct(Structure):
...     m1: int = member(fmt=uint8)
...     m2: int = member(fmt=uint8)
...
>>> buffer, dump = pack_and_dump(MyStruct(m1=1, m2=2))
>>> print(dump)
+--------+--------+-------+-------+----------------------+
| Offset | Access | Value | Bytes | Format               |
+--------+--------+-------+-------+----------------------+
|        |        |       |       | MyStruct (Structure) |
| 0      | m1     | 1     | 01    | uint8                |
| 1      | m2     | 2     | 02    | uint8                |
+--------+--------+-------+-------+----------------------+
>>> items, dump = unpack_and_dump(MyStruct, buffer)
>>> print(dump)
+--------+--------+-------+-------+----------------------+
| Offset | Access | Value | Bytes | Format               |
+--------+--------+-------+-------+----------------------+
|        |        |       |       | MyStruct (Structure) |
| 0      | m1     | 1     | 01    | uint8                |
| 1      | m2     | 2     | 02    | uint8                |
+--------+--------+-------+-------+----------------------+

The “Offset” column shows the byte offset in the overall byte structure for each entry. The “Access” column shows the syntax to use to access the entry. The “Value” column shows the representation of the entries’s unpacked bytes. The “Memory” column contains hexidecimal representation of the member’s bytes.

When an exception occurs while packing or unpacking (regardless if the utility function is a dump variant), the exception message includes a dump to show the successful progress made and the point at which the failure occurred. In the following example, the structure requires one more byte than what was provided:

>>> from plum.utilities import unpack
>>>
>>> x = unpack(MyStruct, b'\x02')
Traceback (most recent call last):
    ...
plum.exceptions.UnpackError:
<BLANKLINE>
+--------+--------+----------------------+-------+----------------------+
| Offset | Access | Value                | Bytes | Format               |
+--------+--------+----------------------+-------+----------------------+
|        |        |                      |       | MyStruct (Structure) |
| 0      | m1     | 2                    | 02    | uint8                |
|        | m2     | <insufficient bytes> |       | uint8                |
+--------+--------+----------------------+-------+----------------------+
<BLANKLINE>
InsufficientMemoryError occurred during unpack operation:
<BLANKLINE>
1 too few bytes to unpack uint8, 1 needed, only 0 available

Data store types offer a dump property to obtain the dump:

>>> struct = MyStruct(m1=1, m2=2)
>>> print(struct.dump)
+--------+--------+-------+-------+----------------------+
| Offset | Access | Value | Bytes | Format               |
+--------+--------+-------+-------+----------------------+
|        |        |       |       | MyStruct (Structure) |
| 0      | m1     | 1     | 01    | uint8                |
| 1      | m2     | 2     | 02    | uint8                |
+--------+--------+-------+-------+----------------------+

Returned dumps support being called to print themselves to standard output:

>>> struct.dump()
+--------+--------+-------+-------+----------------------+
| Offset | Access | Value | Bytes | Format               |
+--------+--------+-------+-------+----------------------+
|        |        |       |       | MyStruct (Structure) |
| 0      | m1     | 1     | 01    | uint8                |
| 1      | m2     | 2     | 02    | uint8                |
+--------+--------+-------+-------+----------------------+

Tip

For speed critical operations, don’t use the dump property or the dump function and method alternatives since they add substantial speed costs.