Skip to main content

structed

C-style packed binary structs for Python, declared with type annotations. Zero runtime dependencies, byte-for-byte compatible with C struct layouts (including __attribute__((packed))), and friendly to cross-language interop and network protocols.

Install

pip install structed

Quick start

from typing import Annotated
from structed import Endian, Struct, uint8_t, uint32_t, char, cstring, cppstring

class Header(Struct, endian=Endian.LITTLE):
    magic  : Annotated[bytes, char[4]]        # fixed-width, NUL-padded
    version: Annotated[int, uint8_t]
    count  : Annotated[int, uint32_t]
    note   : Annotated[str, cstring[16]]      # NUL-terminated C string
    data   : Annotated[str, cppstring]        # length-prefixed string

binary = Header(magic=b"PROT", version=1, count=3, note="hi", data="x").pack()
header = Header.unpack(binary)
obj, rest = Header.unpack_tail(binary + b"more")  # stream framing

Field types

Marker Wire type Python type Notes
uint8_t .. uint64_t, int8_t .. int64_t fixed-width int int byte order follows the struct's endian
float32, float64 IEEE-754 float
char[N] char buf[N] bytes or str fixed width; pads with NULs
char[N] + keep_nulls as above str Annotated[str, char[N], keep_nulls]; keeps embedded NULs on unpack
cstring[N] C string str or bytes N includes the NUL terminator; unpack stops at the first NUL
cppstring u32 length + payload str or bytes length-prefixed; variable-length
Array(N, T), list[T], or scalar * N T arr[N] list fixed-size array of primitives or structs
nested struct class struct T {...} instance a Struct subclass used bare as an annotation

Annotations use typing.Annotated: Annotated[int, uint16_t], Annotated[str, cstring[16]], Annotated[str, cppstring].

Nested structs are declared as a bare annotation (inner: Point); each keeps its own endian regardless of the parent struct's byte order.

Arrays

An array packs N elements back-to-back and round-trips as a list. The element type is given explicitly, inferred from a list[T] annotation, or repeated with *:

class S(Struct, endian=Endian.LITTLE):
    flags: Annotated[list[int], Array(4, uint16_t)]   # explicit
    ages : Annotated[list[int], uint8_t * 2]          # shorthand for Array(2, uint8_t)
    pts  : Annotated[list[Point], Array(3)]           # array of nested structs

s = S(flags=[1, 2, 3, 4], ages=[12, 13], pts=[...])
assert s.flags == [1, 2, 3, 4] and s.ages == [12, 13]

The value must have exactly N elements, otherwise packing raises PackingError. Arrays cannot hold variable-length (cppstring) elements.

Struct options

class Packet(Struct, endian=Endian.BIG, packed=True, truncate=False):
    ...
  • endian: Endian.LITTLE, Endian.BIG, Endian.NATIVE, Endian.NETWORK.
  • packed: True (default) lays fields back-to-back like C __attribute__((packed)); False applies natural C alignment.
  • truncate: when False (default) a value longer than its char[N] / cstring[N] field raises PackingError; when True it is silently cut to fit (and still NUL-terminated for cstring).

The same options are available via the binary_struct(endian=..., packed=..., truncate=...) class decorator.

Struct methods

  • obj.pack() -> bytes
  • S.unpack(data) -> S (consumes from the front)
  • S.unpack_tail(data) -> (S, tail) for stream framing
  • S.unpack_from(data, offset) -> S
  • S.sizeof() -> int (fixed minimum for variable-length structs)

Variable-length fields

cppstring fields are length-prefixed and may be followed by fixed-size fields; parsing always resumes right after the payload. Only one variable field is allowed per struct, packed=True is required, and a struct with a variable field cannot be nested or used as an array element.

Development

make venv          # create .venv and install editable + deps
make check         # run tests + syntax + type checks
make example       # run examples/
make build-release # verify, then build sdist + wheel

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

structed-0.1.1.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

structed-0.1.1-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file structed-0.1.1.tar.gz.

File metadata

  • Download URL: structed-0.1.1.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for structed-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9501fc304acf5fa15316a6936961ad1ac9c0c230fd4f0ed1730dbb1cf68c0173
MD5 a29926a5f3b2e2a32df8ed31c63e57ed
BLAKE2b-256 fdb2321c65f9cd838f7cdf714eb48a8058983c0a51687205cfab314cab7f4b0b

See more details on using hashes here.

File details

Details for the file structed-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: structed-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 24.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for structed-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fd2d4c594f12d3723cbbb991bb30461fda53ee29000a01fe64b75ab2b63608cc
MD5 ef7cb3b06a50b56f8570f4fbd3e27333
BLAKE2b-256 8b4cf0aa396d8922221f1d7422e4a13a046d767e62f305efe75b4f5cb9b6f52f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page