4.5.2. Struct#

4.5.2.1. The Struct class#

class caterpillar.model.Struct(model: type[_ModelT], order: _EndianLike | None = None, arch: _ArchLike | None = None, options: Iterable[_OptionLike] | None = None, field_options: Iterable[_OptionLike] | None = None, kw_only: bool = False, hook_cls: type[UnionHook[_ModelT]] | None = None)[source]#

Represents a structured data model for serialization and deserialization.

Parameters:
  • model – The target class used as the base model.

  • order – Optional byte order for the fields in the structure.

  • arch – Global architecture definition (will be inferred on all fields).

  • options – Additional options specifying what to include in the final class.

4.5.2.2. Unions#

caterpillar.model.union(cls: None = None, /, *, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None, kw_only: bool = False, hook_cls: type[UnionHook[_ModelT]] | None = None) Callable[[type[_ModelT]], type[_ModelT]][source]#
caterpillar.model.union(cls: type[_ModelT], /, *, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None, kw_only: bool = False, hook_cls: type[UnionHook[_ModelT]] | None = None) type[_ModelT]

Decorator to create a Union class.

Parameters:
  • cls – The target class used as the base model.

  • options – Additional options specifying what to include in the final class.

  • order – Optional configuration value for the byte order of a field.

  • arch – Global architecture definition (will be inferred on all fields).

Returns:

The created Union class or a wrapper function if cls is not provided.

class caterpillar.model.UnionHook(struct_: Struct[_ModelT])[source]#

Implementation of a hook to simulate union types.

It will hook two methods of the target model type: __init__ and __setattr__. Because the constructor calls setattr for each attribute in the model, we have to intercept it before it gets called to set an internal status.

Internally, these two methods will be translated into __model_init__() and __model_setattr__(). Therefore, any class that implements these two methods can be used as a union hook.

struct: Struct[_ModelT]#

The struct reference

max_size: int#

The static (cached) maximum size of the union

4.5.2.3. Standard Interface#

caterpillar.model.struct(ty: type[_ModelT] | None = None, kw_only: bool = False, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None) type[_ModelT] | Callable[[_ModelT], type[_ModelT]]#

Decorator or direct constructor for creating a Struct model.

This method can be used either as:

  • A decorator: @struct(...)

  • A direct transformer: MyStruct = struct(MyClass, ...)

The method configures structure-wide options such as byte order, architecture, and field-level behaviors, and returns a fully initialized model class.

>>> @struct(order=LittleEndian)
... class Format:
...     field: f[int, uint32]
Parameters:
  • ty (type[_ModelT] | None, optional) – The target class to be transformed into a Struct model. If None, a decorator function is returned

  • kw_only (bool, optional) – Whether generated dataclass fields should be keyword-only, defaults to False

  • options (Iterable[_OptionLike] | None, optional) – Additional options controlling structure behavior, defaults to None

  • order (_EndianLike | None, optional) – Global byte order configuration applied to all fields, defaults to None

  • arch (_ArchLike | None, optional) – Global architecture configuration inferred by fields, defaults to None

  • field_options (Iterable[_OptionLike] | None, optional) – Additional options applied at the field level, defaults to None

Returns:

A transformed Struct model class, or a decorator if ty is None

Return type:

type[_ModelT] | Callable[[_ModelT], type[_ModelT]]

caterpillar.model.pack(obj: _ContainsStruct[_IT, _OT], struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwargs: Any) bytes[source]#
caterpillar.model.pack(obj: object, struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) bytes
caterpillar.model.pack(obj: _IT, struct: _SupportsPack[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwargs: Any) bytes
caterpillar.model.pack(obj: _IT, struct: type[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwargs: Any) bytes

Pack an object into a bytes buffer using the specified struct.

Parameters:
  • obj – The object to pack.

  • struct – The struct to use for packing.

  • use_tempfile – Whether to use a temporary file for packing (experimental).

  • as_field – Whether to wrap the struct in a Field before packing.

  • fill – pattern to use when filling up space (only applied when fields with offsets are used)

  • arch – architecture to apply to the struct

  • order – byte order to apply

  • kwargs – Additional keyword arguments to pass to the context.

Returns:

The packed bytes.

Changed in version 2.8.1: Added fill parameter.

caterpillar.model.pack_into(obj: _ContainsStruct[_IT, _OT], buffer: IOBase, struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None[source]#
caterpillar.model.pack_into(obj: object, buffer: IOBase, struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_into(obj: _IT, buffer: IOBase, struct: _SupportsPack[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_into(obj: _IT, buffer: IOBase, struct: type[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_into(obj: _IT, buffer: IOBase, struct: _ContainsStruct[_IT, _OT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None

Pack an object into the specified buffer using the specified struct.

This function serializes an object (obj) into a given buffer, using a struct to define how the object should be packed. Optionally, the function can handle temporary files for packing, use a Field wrapper around the struct, and support additional keyword arguments. The packed data is written to the buffer.

Example 1: Packing an object into a bytes buffer

>>> buffer = BytesIO()
>>> my_obj = SomeObject()  # Assume SomeObject is a valid object to be packed
>>> pack_into(my_obj, buffer, struct=SomeStruct())  # Using a specific struct
>>> buffer.getvalue()
b"..."

Example 2: Packing into a file-like stream (e.g., file)

>>> with open('packed_data.bin', 'wb') as f:
...     pack_into(my_obj, f, struct=SomeStruct())  # Pack into a file

Example 3: Using as_field to wrap the struct in a Field before packing

>>> buffer = BytesIO()
>>> pack_into(42, buffer, struct=uint8, as_field=True)
>>> buffer.getvalue()
b"\x2a"
Parameters:
  • obj – The object to pack (could be a plain object or a structure-like object).

  • buffer – The buffer to pack the object into (a writable stream such as BytesIO or a file).

  • struct – The struct to use for packing. If not specified, will infer from obj.

  • use_tempfile – Whether to use a temporary file for packing (experimental).

  • as_field – Whether to wrap the struct in a Field before packing.

  • fill – pattern to use when filling up space (only applied when fields with offsets are used)

  • arch – architecture to apply to the struct

  • order – byte order to apply

  • kwds – Additional keyword arguments to pass to the context.

Raises:

TypeError – If no struct is specified and cannot be inferred from the object.

Changed in version 2.8.1: Added fill parameter.

caterpillar.model.pack_file(obj: _ContainsStruct[_IT, _OT], filename: str, struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None[source]#
caterpillar.model.pack_file(obj: object, filename: str, struct: None = None, /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_file(obj: _IT, filename: str, struct: _SupportsPack[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_file(obj: _IT, filename: str, struct: type[_IT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None
caterpillar.model.pack_file(obj: _IT, filename: str, struct: _ContainsStruct[_IT, _OT], /, *, use_tempfile: bool = False, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, fill: int | bytes | str | None = None, **kwds: Any) None

Pack an object into a file using the specified struct.

Parameters:
  • obj – The object to pack.

  • filename – The name of the file to write to.

  • struct – The struct to use for packing.

  • use_tempfile – Whether to use a temporary file for packing (experimental).

  • as_field – Whether to wrap the struct in a Field before packing.

  • fill – pattern to use when filling up space (only applied when fields with offsets are used)

  • arch – architecture to apply to the struct

  • order – byte order to apply

  • kwds – Additional keyword arguments to pass to the context.

Returns:

None

Changed in version 2.8.1: Added fill parameter.

caterpillar.model.unpack(struct: _ContainsStruct[_IT, _OT], buffer: Buffer | IOBase, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT[source]#
caterpillar.model.unpack(struct: _SupportsUnpack[_OT], buffer: Buffer | IOBase, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT
caterpillar.model.unpack(struct: type[_OT], buffer: Buffer | IOBase, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT

Unpack an object from a bytes buffer or stream using the specified struct.

This function takes a struct that defines how data should be unpacked, a buffer (either bytes or a stream) containing the serialized data, and returns the unpacked object. If as_field is set to True, the struct is wrapped by a Field. Additional keyword arguments are passed to the root context as attributes.

Example:

>>> buffer = b'\x00\x01\x02\x03'
>>> struct = SomeStruct()
>>> unpack(struct, buffer)
...
Parameters:
  • struct – The struct to use for unpacking (could be a SupportsUnpack or ContainsStruct object).

  • buffer – The bytes buffer or stream to unpack from.

  • as_field – Whether to wrap the struct in a Field transformer before unpacking.

  • kwds – Additional keyword arguments to pass to the unpack function.

Returns:

The unpacked object, which is the result of calling struct.__unpack__(context).

Raises:

TypeError – If the struct is not a valid struct instance.

caterpillar.model.unpack_file(struct: _ContainsStruct[_IT, _OT], filename: str, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT[source]#
caterpillar.model.unpack_file(struct: _SupportsUnpack[_OT], filename: str, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT
caterpillar.model.unpack_file(struct: type[_OT], filename: str, /, *, as_field: bool = False, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwds: Any) _OT

Unpack an object from a file using the specified struct.

Parameters:
  • struct – The struct to use for unpacking.

  • filename – The name of the file to read from.

  • kwds – Additional keyword arguments to pass to the unpack function.

Returns:

The unpacked object.

caterpillar.model.sizeof(obj: _SupportsSize, **kwds: Any) int[source]#
caterpillar.model.sizeof(obj: _ContainsStruct, **kwds: Any) int
caterpillar.model.sizeof(obj: type, **kwds: Any) int

Changed in version 2.5.0: Now checks if the provided object implements the _SupportsSize protocol

4.5.2.4. Struct Mixins#

caterpillar.model.Invisible(*, init: bool = False, default: Any = None) Any[source]#

Create a dataclass field that is hidden from the generated constructor.

This helper returns a dataclasses.field configured so that the associated attribute is not exposed as a parameter in the dataclass __init__ method. It is primarily intended for use in @struct definitions where certain fields (e.g., padding, metadata, or internally managed values) should exist in the structure layout but must not be user-provided during instantiation.

When used, type checkers and IDEs will treat the field as non-existent from the constructor’s perspective, while the field still participates in the dataclass definition and underlying structure handling.

>>> @struct
... class Format:
...     a: uint32_t
...     b: f[bytes, b"const value"] = Invisible()

In this example, field b is part of the structure definition but is not visible as an argument when constructing Format.

Parameters:
  • init (bool, optional) – Whether the field should be included in the generated __init__ method. This is typically set to False to hide the field, defaults to False

  • default (Any, optional) – Default value assigned to the field if not explicitly set, defaults to None

Returns:

A configured dataclasses.field instance with kw_only=True and the specified visibility settings

Return type:

Any

class caterpillar.model.StructDefMixin[source]#

Mixin providing convenience methods and typing support for @struct models.

This mixin centralizes common wrapper functionality required by structure definitions so that individual model classes do not need to import or reference low-level packing and unpacking utilities directly.

It provides:

  • cls[...] support via __class_getitem__ for defining repeated fields using the indexing operator.

  • cls.from_bytes(...) for constructing instances from raw binary data.

  • cls.from_file(...) for constructing instances from files.

  • obj.to_bytes(...) for serializing instances back into binary form.

The primary purpose of this mixin is to improve ergonomics and satisfy static type checkers by exposing these behaviors directly on the model class rather than requiring explicit imports of pack/unpack helpers.

classmethod from_bytes(data: Buffer | IOBase, *, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwargs: Any) _ModelT[source]#

Construct an instance from raw binary data or a stream.

This is a convenience wrapper around the underlying unpack function, allowing models to be instantiated directly from bytes without importing parsing utilities.

Parameters:
  • data (Buffer | _StreamType) – Raw bytes or a readable stream containing serialized data

  • order (_EndianLike | None, optional) – Endianness override for parsing, defaults to None

  • arch (_ArchLike | None, optional) – Architecture override for parsing, defaults to None

Returns:

Parsed model instance

Return type:

_ModelT

classmethod from_file(filename: str, *, order: _EndianLike | None = None, arch: _ArchLike | None = None, **kwargs: Any) _ModelT[source]#

Construct an instance from a binary file on disk.

This is a convenience wrapper around unpack_file for reading and parsing structured data directly from a file path.

Parameters:
  • filename (str) – Path to the file containing serialized data

  • order (_EndianLike | None, optional) – Endianness override for parsing, defaults to None

  • arch (_ArchLike | None, optional) – Architecture override for parsing, defaults to None

Returns:

Parsed model instance

Return type:

_ModelT

to_bytes(*, fp: IOBase, order: _EndianLike | None = None, arch: _ArchLike | None = None, use_tempfile: bool = False, **kwargs: Any) None[source]#
to_bytes(*, fp: None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, use_tempfile: bool = False, **kwargs: Any) bytes

Serialize the instance into its binary representation.

If fp is provided, the binary data is written directly into the given stream using pack_into. Otherwise, the binary data is returned as a bytes object using pack.

Parameters:
  • fp (_StreamType | None, optional) – Writable stream to receive the serialized data. If None, the serialized bytes are returned, defaults to None

  • order (_EndianLike | None, optional) – Endianness override for serialization, defaults to None

  • arch (_ArchLike | None, optional) – Architecture override for serialization, defaults to None

  • use_tempfile (bool, optional) – Whether to use a temporary file during packing, defaults to False

Returns:

Serialized bytes if fp is None, otherwise None

Return type:

bytes | None

class caterpillar.model.struct_factory[source]#

Factory responsible for converting plain classes into @struct models.

This factory provides decorator-style and direct-call APIs for transforming a regular class definition into a fully configured Struct model. The resulting class gains dataclass semantics and structure metadata.

mixin#

alias of StructDefMixin

static new(ty: type[_ModelT], kw_only: Literal[False] = False, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None) type[_ModelT][source]#
static new(ty: type[_ModelT], kw_only: Literal[True] = True, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None) type[_ModelT]
static new(ty: None = None, kw_only: Literal[False] = False, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None) Callable[[_ModelT], type[_ModelT]]
static new(ty: None = None, kw_only: Literal[True] = True, options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None) Callable[[_ModelT], type[_ModelT]]

Decorator or direct constructor for creating a Struct model.

This method can be used either as:

  • A decorator: @struct(...)

  • A direct transformer: MyStruct = struct(MyClass, ...)

The method configures structure-wide options such as byte order, architecture, and field-level behaviors, and returns a fully initialized model class.

>>> @struct(order=LittleEndian)
... class Format:
...     field: f[int, uint32]
Parameters:
  • ty (type[_ModelT] | None, optional) – The target class to be transformed into a Struct model. If None, a decorator function is returned

  • kw_only (bool, optional) – Whether generated dataclass fields should be keyword-only, defaults to False

  • options (Iterable[_OptionLike] | None, optional) – Additional options controlling structure behavior, defaults to None

  • order (_EndianLike | None, optional) – Global byte order configuration applied to all fields, defaults to None

  • arch (_ArchLike | None, optional) – Global architecture configuration inferred by fields, defaults to None

  • field_options (Iterable[_OptionLike] | None, optional) – Additional options applied at the field level, defaults to None

Returns:

A transformed Struct model class, or a decorator if ty is None

Return type:

type[_ModelT] | Callable[[_ModelT], type[_ModelT]]

static make_struct(ty: type[_ModelT], options: Iterable[_OptionLike] | None = None, order: _EndianLike | None = None, arch: _ArchLike | None = None, field_options: Iterable[_OptionLike] | None = None, kw_only: bool = False, hook_cls: type[UnionHook[_ModelT]] | None = None) type[_ModelT][source]#

Internal helper that performs the actual Struct model creation.

This method instantiates a Struct object using the provided configuration and returns the generated model class.

Parameters:
  • ty (type[_ModelT]) – The base class to transform into a Struct model

  • options (Iterable[_OptionLike] | None, optional) – Additional options controlling structure behavior, defaults to None

  • order (_EndianLike | None, optional) – Global byte order configuration applied to all fields, defaults to None

  • arch (_ArchLike | None, optional) – Global architecture configuration inferred by fields, defaults to None

  • field_options (Iterable[_OptionLike] | None, optional) – Additional options applied at the field level, defaults to None

  • kw_only (bool, optional) – Whether generated dataclass fields should be keyword-only, defaults to False

  • hook_cls (type["UnionHook[_ModelT]"] | None, optional) – Optional hook class for union handling, defaults to None

Returns:

The generated Struct model class

Return type:

type[_ModelT]