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));Falseapplies natural C alignment.truncate: whenFalse(default) a value longer than itschar[N]/cstring[N]field raisesPackingError; whenTrueit is silently cut to fit (and still NUL-terminated forcstring).
The same options are available via the binary_struct(endian=..., packed=..., truncate=...) class decorator.
Struct methods
obj.pack()->bytesS.unpack(data)->S(consumes from the front)S.unpack_tail(data)->(S, tail)for stream framingS.unpack_from(data, offset)->SS.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
Metadata
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)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| structed-0.1.1.tar.gz | 25.9 kB | Without provenance | Details for structed-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| structed-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for structed-0.1.1-py3-none-any.whl |
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
|
Security for structed 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.