Usage

Encode values

Every type in x690.types wraps a Python value. Call bytes on an instance to get its encoding, type and length header included:

>>> from x690.types import Boolean, Integer, Null
>>> from x690.types import ObjectIdentifier
>>> bytes(Integer(12))
b'\x02\x01\x0c'
>>> bytes(Boolean(True))
b'\x01\x01\x01'
>>> bytes(ObjectIdentifier("1.3.6.1.2.1.1.1.0"))
b'\x06\x08+\x06\x01\x02\x01\x01\x01\x00'
>>> bytes(Null())
b'\x05\x00'

A Sequence takes a list of values and encodes them in order. Sequences nest:

>>> from x690.types import OctetString, Sequence
>>> nested = Sequence([
...     Integer(1),
...     Sequence([OctetString(b"a")]),
... ])
>>> bytes(nested)
b'0\x08\x02\x01\x010\x03\x04\x01a'

Decode a value

x690.decode() reads one value and returns it with the index of the next value in the data:

>>> from x690 import decode
>>> value, next_index = decode(b"\x02\x01\x0c")
>>> value
Integer(12)
>>> next_index
3

value.value holds the Python value of a single item. pythonize() converts nested sequences as well:

Note

On a Sequence, value is a list of x690 objects. pythonize() converts each of them to its Python value.

>>> value.value
12
>>> decode(bytes(nested))[0].pythonize()
[1, [b'a']]

Decode a stream

Pass the index of the next value back to decode() to walk through data that holds several values:

>>> data = b"\x02\x01\x01\x02\x01\x02\x02\x01\x03"
>>> index = 0
>>> while index < len(data):
...     value, index = decode(data, index)
...     print(value)
Integer(1)
Integer(2)
Integer(3)

The same start index reads a value from the middle of a larger buffer. x690 does not copy the buffer: values keep a reference to it and convert their bytes when first read.

>>> decode(b"header\x02\x01\x05trailer", 6)
(Integer(5), 9)

Check the type

When the type of the value is known in advance, pass it as enforce_type. The result is then typed for type checkers, and a mismatch raises UnexpectedType:

>>> data = b"\x02\x01\x0c"
>>> decode(data, enforce_type=Integer)
(Integer(12), 3)
>>> decode(data, enforce_type=OctetString)
Traceback (most recent call last):
  ...
x690.exc.UnexpectedType: Unexpected decode result. Expected instance of type <class 'x690.types.OctetString'> but got <class 'x690.types.Integer'> instead

Reject trailing data

With strict=True, data left after the value raises IncompleteDecoding. Its remainder attribute holds the extra bytes:

>>> from x690.exc import IncompleteDecoding
>>> try:
...     decode(b"\x02\x01\x0cjunk", strict=True)
... except IncompleteDecoding as exc:
...     print(exc.remainder)
b'junk'

Inspect unknown data

pretty() prints a value and everything inside it. Values x690 has no type for decode to UnknownType, which shows their class, nature and tag. This SNMP request contains such a value:

>>> data = (
...     b"0'\x02\x01\x01\x04\x06public"
...     b"\xa0\x1a\x02\x02\x04\xd2\x02\x01\x00"
...     b"\x02\x01\x000\x0e0\x0c\x06\x08+\x06"
...     b"\x01\x02\x01\x01\x01\x00\x05\x00"
... )
>>> print(decode(data)[0].pretty())
Sequence with 3 items:
⁃ Integer(1)
⁃ ┌───────────────────────────────────────────────────────────┐
  │ <class 'x690.types.OctetString'>                          │
  ├───────────────────────────────────────────────────────────┤
  │ 70 75 62 6c 69 63                                  public │
  └───────────────────────────────────────────────────────────┘
⁃ Unknown X690Type
    │ Tag:       160
    │ X690Type Info:
    │  │ Class: TypeClass.CONTEXT
    │  │ Nature: TypeNature.CONSTRUCTED
    │  │ Tag: 0
  ┌─────────────────────────────────────────────────────────────────────┐
  │ <class 'x690.types.UnknownType'>                                    │
  ├─────────────────────────────────────────────────────────────────────┤
  │ 02 02 04 d2 02 01 00 02  01 00 30 0e 30 0c 06 08   ..........0.0... │
  │ 2b 06 01 02 01 01 01 00  05 00                     +.........       │
  └─────────────────────────────────────────────────────────────────────┘

The third item is a constructed value of the context class with tag 0: the SNMP GetRequest PDU. Custom types shows how to teach x690 that type, so the dump shows its contents.