Skip to main content

A Pydantic extension for struct-compatible serialization

Project description

PDC Struct

Tests codecov PyPI version Python Version License: MIT

PDC Struct is a Pydantic extension that enables binary serialization of Pydantic models for efficient data exchange and C-compatible binary protocols. It combines Pydantic's powerful validation capabilities with Python's struct module to create a seamless bridge between high-level Python data models and low-level binary formats.

Features

  • 🔄 Two Operating Modes:
    • C-Compatible mode for direct interop with C structs
    • Dynamic mode for flexible Python-to-Python communication
  • 🛡️ Type Safety: Full Pydantic validation combined with struct packing rules
  • 🌍 Cross-Platform: Configurable endianness and alignment
  • 📦 Rich Type Support: Integers, floats, strings, enums, UUIDs, IP addresses and more
  • 🔍 Validation: Strong type checking and boundary validation
  • 🧪 Well-Tested: Comprehensive test suite covering edge cases

Installation

pip install pdc-struct

Or install from source:

pip install git+https://github.com/boxcake/pdc_struct.git

Requirements:

  • Python 3.11+
  • Pydantic 2.0+

Quick Start

Here's an example using PDC Struct to implement ARP (Address Resolution Protocol) packet handling:

from enum import IntEnum
from ipaddress import IPv4Address  
from pydantic import Field
from pdc_struct import StructModel, StructConfig, StructMode, ByteOrder
from pdc_struct.c_types import UInt8, UInt16

class HardwareType(IntEnum):
    """ARP Hardware Types"""
    ETHERNET = 1
    IEEE802 = 6
    ARCNET = 7 
    FRAME_RELAY = 15
    ATM = 16

class Operation(IntEnum):
    """ARP Operation Codes"""  
    REQUEST = 1
    REPLY = 2

class ARPPacket(StructModel):
    """ARP Packet Structure (RFC 826)"""
    
    hardware_type: HardwareType = Field(
        description="Hardware type"
    )
    
    protocol_type: UInt16 = Field(
        default=0x0800,  # IPv4
        description="Protocol type (0x0800 for IPv4)" 
    )
    
    hw_addr_len: UInt8 = Field(
        default=6,  # MAC address length
        description="Hardware address length"
    )
    proto_addr_len: UInt8 = Field(  
        default=4,  # IPv4 address length
        description="Protocol address length"
    )
    
    operation: Operation = Field(
        description="Operation code"
    )
    
    sender_hw_addr: bytes = Field(
        struct_length=6, 
        description="Sender hardware address (MAC)"
    )
    sender_proto_addr: IPv4Address = Field(
        description="Sender protocol address (IPv4)"
    )
    target_hw_addr: bytes = Field(
        struct_length=6,
        description="Target hardware address (MAC)"  
    )
    target_proto_addr: IPv4Address = Field(
        description="Target protocol address (IPv4)"
    )
    
    struct_config = StructConfig(
        mode=StructMode.C_COMPATIBLE,  # Fixed size for network protocol  
        byte_order=ByteOrder.BIG_ENDIAN  # Network byte order
    )

# Example usage
packet = ARPPacket(
    hardware_type=HardwareType.ETHERNET,
    operation=Operation.REQUEST,  
    sender_hw_addr=b'\x00\x11"3DUf',
    sender_proto_addr=IPv4Address('192.168.1.100'),
    target_hw_addr=b'\x00\x00\x00\x00\x00\x00', 
    target_proto_addr=IPv4Address('192.168.1.1')
)
binary_data = packet.to_bytes()

# Decode received data
received = ARPPacket.from_bytes(binary_data)
print(received.dict())

Core Classes

StructModel

Base class for binary-serializable models. Define fields and configuration:

class MyModel(StructModel):
    field1: int
    field2: str = Field(max_length=10)

    struct_config = StructConfig(...)

Class Methods:

  • struct_format_string() -> str: Returns the struct format string
  • struct_size() -> int: Returns the size in bytes of the packed structure
  • from_bytes(data: bytes) -> StructModel: Creates a model instance from bytes

Instance Methods:

  • to_bytes() -> bytes: Converts the model instance to bytes

StructConfig

Configuration for struct packing/unpacking behavior.

StructConfig(
    mode: StructMode = StructMode.DYNAMIC,  
    version: StructVersion = StructVersion.V1,
    byte_order: ByteOrder = ByteOrder.LITTLE_ENDIAN,
)

Parameters:

  • mode: Determines packing mode (C_COMPATIBLE or DYNAMIC)
  • version: Protocol version for future compatibility
  • byte_order: Byte ordering for numeric values

Operating Modes

C_COMPATIBLE Mode

Designed for interoperability with C structs:

  • Fixed struct size
  • Optional fields require defaults
  • Null-terminated strings
  • No headers or metadata

DYNAMIC Mode

Optimized for Python-to-Python communication:

  • Variable-length structures
    • Truly optional fields (no defaults required)
    • Efficient bitmap field tracking
    • Version headers for compatibility

Type System

PDC Struct supports key Python types:

Python Type Struct Format Size
int 'i' 4 bytes
float 'd' 8 bytes
bool '?' 1 byte
str 's' Varies
bytes 's' Varies
Enum 'i' 4 bytes
IPv4Address '4s' 4 bytes
IPv6Address '16s' 16 bytes
UUID '16s' 16 bytes

Fixed-width integer types are also available:

  • Int8, UInt8, Int16, UInt16

Error Handling

PDC Struct provides specific exceptions:

  • StructPackError: Serialization errors
    • StructUnpackError: Deserialization errors

Contributing

Contributions are welcome! Please submit issues and pull requests on GitHub.

License

PDC Struct is open source, licensed under the MIT License.

Project details


Download files

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

Source Distribution

pdc_struct-1.0.0.tar.gz (90.6 kB view details)

Uploaded Source

Built Distribution

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

pdc_struct-1.0.0-py3-none-any.whl (33.8 kB view details)

Uploaded Python 3

File details

Details for the file pdc_struct-1.0.0.tar.gz.

File metadata

  • Download URL: pdc_struct-1.0.0.tar.gz
  • Upload date:
  • Size: 90.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pdc_struct-1.0.0.tar.gz
Algorithm Hash digest
SHA256 e3c6370ccbd9c9c2bc8397fbbd3c397680f6c2df7dec0c40c85367312b0f45b6
MD5 764e4c1605f5c0e4cfe0086ff768366a
BLAKE2b-256 ff3af701999cfa7f9a937a6d54f33e468a66ac6d88389e252ecf2e4ad7e1568f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pdc_struct-1.0.0.tar.gz:

Publisher: publish.yml on boxcake/pdc_struct

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pdc_struct-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pdc_struct-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 33.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pdc_struct-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b9d9960027d09e18c484f02eb48058932b2475bc819f932136708065aad23795
MD5 bf890facf3b82785af4adfb25ad9138d
BLAKE2b-256 813048b8e54a9fa878350ce088f1bdb9fe5b9f47da8a9255effbcc267b4881d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pdc_struct-1.0.0-py3-none-any.whl:

Publisher: publish.yml on boxcake/pdc_struct

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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