pystructs
pystructs is a Django-like declarative binary parsing library for Python. Define binary data structures as classes and parse/serialize them with ease.
Features
- Declarative syntax - Define structs like Django models
- Bidirectional - Parse binary data and serialize back to bytes
- Rich field types - Integers, floats, bytes, strings, arrays, and more
- Bit-level parsing -
BitStructfor parsing individual bits - Conditional fields - Fields that exist based on runtime conditions
- Validation system - Built-in and custom validators
- Zero runtime dependencies - Pure Python implementation
Installation
pip install pystructs
uv add pystructs
Quick Start
from pystructs import Struct, UInt8, UInt16, UInt32, Bytes, Ref, SyncRule
class Packet(Struct):
class Meta:
endian = "big"
sync_rules = [
SyncRule("length", from_field="payload", compute=len),
]
magic = UInt32(default=0xDEADBEEF)
version = UInt8(default=1)
length = UInt16()
payload = Bytes(size=Ref("length"))
# Parse from bytes
data = b"\xde\xad\xbe\xef\x01\x00\x05Hello"
packet = Packet.parse(data)
print(packet.magic) # 3735928559 (0xDEADBEEF)
print(packet.version) # 1
print(packet.payload) # b'Hello'
# Create and serialize
new_packet = Packet(payload=b"World")
new_packet.sync() # Auto-calculate length
print(new_packet.to_bytes())
More Examples
Variable-Length Arrays
from pystructs import Struct, UInt8, UInt16, Array, Ref, SyncRule
class ScoreBoard(Struct):
class Meta:
sync_rules = [
SyncRule("count", from_field="scores", compute=len),
]
player_id = UInt16()
count = UInt8()
scores = Array(UInt16(), count=Ref("count"))
board = ScoreBoard(player_id=1234, scores=[100, 250, 180])
board.sync()
print(board.to_bytes()) # Serializes with count=3
Bit-Level Parsing
from pystructs import Struct, UInt16, BitStruct, Bit, Bits, EmbeddedBitStruct
class TCPFlags(BitStruct):
class Meta:
size = 1
fin = Bit()
syn = Bit()
rst = Bit()
psh = Bit()
ack = Bit()
urg = Bit()
reserved = Bits(2)
class TCPHeader(Struct):
class Meta:
endian = "big"
src_port = UInt16()
dst_port = UInt16()
flags = EmbeddedBitStruct(TCPFlags)
header = TCPHeader.parse(b"\x00\x50\x1f\x90\x12")
print(header.src_port) # 80
print(header.flags.syn) # True
Conditional Fields
from pystructs import Struct, UInt8, UInt32, Conditional, Ref
class VersionedPacket(Struct):
version = UInt8()
# Only present in version 2+
extended_header = Conditional(
UInt32(),
when=Ref("version") >= 2,
)
data = UInt8()
# Version 1: no extended header
v1 = VersionedPacket.parse(b"\x01\x42")
print(v1.extended_header) # None
# Version 2: with extended header
v2 = VersionedPacket.parse(b"\x02\x00\x00\x00\x01\x42")
print(v2.extended_header) # 1
Tagged Unions (Switch)
from pystructs import Struct, UInt8, UInt16, UInt32, Switch, Ref
class TextPayload(Struct):
length = UInt8()
# text would use Bytes(size=Ref("length"))
class BinaryPayload(Struct):
size = UInt16()
# data would use Bytes(size=Ref("size"))
class Message(Struct):
msg_type = UInt8()
payload = Switch(
discriminator=Ref("msg_type"),
cases={
1: TextPayload,
2: BinaryPayload,
},
)
Field Types
| Category | Fields |
|---|---|
| Integers | Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64 |
| Floats | Float32, Float64 |
| Bytes | FixedBytes, Bytes |
| Strings | FixedString, String, NullTerminatedString |
| Composite | Array, EmbeddedStruct, Conditional, Switch |
| Special | Bool, Padding, Flags, Enum |
| Bit-level | BitStruct, Bit, Bits, EmbeddedBitStruct |
Documentation
Full documentation is available at Read the Docs.
Contributing
See CONTRIBUTING.md for development setup and contribution guidelines.
License
MIT License
Metadata
Release files for pystructs 0.4.0
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 |
|---|---|---|---|---|
| pystructs-0.4.0.tar.gz | 103.6 kB | Without provenance | Details for pystructs-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pystructs-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for pystructs-0.4.0-py3-none-any.whl |
Total release size: 136.1 kB
Release files / pystructs-0.4.0.tar.gz
| Download URL | pystructs-0.4.0.tar.gz |
|---|---|
| Size | 103.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6918ffafea0c9f5c9dc9fba31423e9eb4ee4342363dc39800664c6c70ce4f268
|
|
BLAKE2b-256 checksum How to use checksums |
01751b5baf9bc866d6b694843a229c82621fb8d9876864a2b41e5cb8d7030608
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.20 {"installer":{"name":"uv","version":"0.9.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pystructs-0.4.0-py3-none-any.whl
| Download URL | pystructs-0.4.0-py3-none-any.whl |
|---|---|
| Size | 32.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
838e4f616160600e8be846106178a70f0beb6659c8dc257dcb3598cbc973fc06
|
|
BLAKE2b-256 checksum How to use checksums |
d0d80b0a897332d5446e4c72b3a5f1f026acc016d931bba85f505280a34181da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.20 {"installer":{"name":"uv","version":"0.9.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for pystructs 0.4.0
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.