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

Release files for structed 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for structed 0.1.1
File Size Uploaded
structed-0.1.1.tar.gz 25.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for structed 0.1.1
File Interpreter ABI Platform
structed-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 50.2 kB

Release files / structed-0.1.1.tar.gz

Download URL structed-0.1.1.tar.gz
Size 25.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9501fc304acf5fa15316a6936961ad1ac9c0c230fd4f0ed1730dbb1cf68c0173
BLAKE2b-256 checksum
How to use checksums
fdb2321c65f9cd838f7cdf714eb48a8058983c0a51687205cfab314cab7f4b0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / structed-0.1.1-py3-none-any.whl

Download URL structed-0.1.1-py3-none-any.whl
Size 24.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd2d4c594f12d3723cbbb991bb30461fda53ee29000a01fe64b75ab2b63608cc
BLAKE2b-256 checksum
How to use checksums
8b4cf0aa396d8922221f1d7422e4a13a046d767e62f305efe75b4f5cb9b6f52f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page