Skip to main content

cstructpy is a Python package designed for binary serialization and deserialization of structured data using custom primitive types.

Project description

cstructpy

Testing workflow PyPI version Python versions

cstructpy is a light-weight Python package designed for binary serialization and deserialization of structured data using c like primitive types. It provides a simple interface for packing and unpacking binary data based on field definitions using Python's struct module. The motivation for this package is to have a data validation using type annotations, similar to pydantic but for binary data. Therefore this package is best when used alongside pydantic.BaseModel or dataclasses.dataclass since it allows a similar class structure and object creation

Features

  • Custom primitive types for integers, floating points, characters, and arrays.
  • Dynamically create structured classes with flexible field definitions.
  • Provides an interface for primitive type annotations
  • Supports validation for all the primitive types
  • Supports Array creation for all primitive types (apart for CHAR type) and validation of size
  • Serialize/deserialize data to/from binary formats easily.
  • Support for alignment padding and fixed-length character arrays.

Installation

Install the package via pip:

pip install cstructpy

Usage

Here's a quick guide to using cstructpy to create your own structured binary data:

Defining a Structured Class

You can define a new class that extends GenericStruct and define the fields using the custom primitive types from primitives.py.

from cstructpy import GenericStruct
from cstructpy.primitives import INT8, UINT16, FLOAT, UINT64


class MyDataStructure(GenericStruct):
    field1: INT8
    field2: UINT16
    field3: FLOAT
    array_uint64: UINT64[3]  # an array of UINT64 of size 3 


# Create an instance with field values
data_instance = MyDataStructure(field1=-128, field2=65535, field3=3.14, array_uint64=[312, 2345, 234212])

# Pack the instance into binary format
binary_data = data_instance.pack()
print(binary_data)
# Output: b'\x80\xff\xff\xc3\xf5H@8\x01\x00\x00\x00\x00\x00\x00)\t\x00\x00\x00\x00\x00\x00\xe4\x92\x03\x00\x00\x00\x00\x00'

# Unpack the binary data back into a structured instance
new_instance = MyDataStructure.unpack(binary_data)
print(new_instance.to_dict())
# Output: {'field1': -128, 'field2': 65535, 'field3': 3.140000104904175, 'array_uint64': (312, 2345, 234212)}

Using defaults

You can now use defaults for all types, including collections

from cstructpy import GenericStruct
from cstructpy.primitives import INT8, UINT16, FLOAT, UINT64


class MyDataStructure(GenericStruct):
    field1: INT8 = 16  # Setting default
    field2: UINT16 = 256  # Setting default 
    field3: FLOAT = 3.0  # Setting default
    array_uint64: UINT64[3]  # Not setting


data_instance = MyDataStructure(array_uint64=[312, 2345, 234212])  # Valid call

Primitive Types

The package provides the following primitive types for defining fields:

  • INT8: 8-bit signed integer.
  • U_INT8: 8-bit unsigned integer.
  • INT16: 16-bit signed integer.
  • U_INT16: 16-bit unsigned integer.
  • INT32: 32-bit signed integer.
  • U_INT32: 32-bit unsigned integer.
  • INT64: 64-bit signed integer.
  • U_INT64: 64-bit unsigned integer.
  • FLOAT: 32-bit floating point number.
  • DOUBLE: 64-bit floating point number.
  • CHAR: Single character.
  • CHAR_ARRAY: Fixed-length character array.
  • BOOL: Boolean value.
  • PADDING: Padding type used for alignment.

All types, apart from CHAR and PADDING can be invoked as an array with square brackets

Example: Packing and Unpacking

from cstructpy import GenericStruct
from cstructpy.primitives import INT16, CHAR_ARRAY


class AnotherStruct(GenericStruct):
    number: INT16
    message: CHAR_ARRAY(10)


# Create an instance
example = AnotherStruct(number=42, message="hello")

# Pack it to binary
binary_data = example.pack()

# Unpack binary data back into an instance
unpacked_example = AnotherStruct.unpack(binary_data)

# Convert to dictionary
print(unpacked_example.to_dict())  # Output: {'number': 42, 'message': 'hello'}

Validation

Each field type has its own validation rules. For example, INT8 will only accept values between -128 and 127. If you try to set a value outside this range, a ValueError will be raised.

from cstructpy.primitives import INT8

int_field = INT8()
int_field.validate(-128)  # Valid
int_field.validate(128)  # Raises ValueError: Value 128 is greater than maximum 127

Running Tests

The package includes unit tests, which you can run using pytest:

pytest unit_tests

GitHub Actions

This repository uses GitHub Actions to automatically run linting, type checking, and tests. The pipeline includes:

  • flake8 for linting.
  • mypy for type checking.
  • pytest for running tests.

Contributing

Feel free to open issues and submit pull requests. Make sure to run all tests before submitting your changes.

License

This project is 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

cstructpy-0.2.2.tar.gz (9.7 kB view details)

Uploaded Source

Built Distribution

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

cstructpy-0.2.2-py3-none-any.whl (8.6 kB view details)

Uploaded Python 3

File details

Details for the file cstructpy-0.2.2.tar.gz.

File metadata

  • Download URL: cstructpy-0.2.2.tar.gz
  • Upload date:
  • Size: 9.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for cstructpy-0.2.2.tar.gz
Algorithm Hash digest
SHA256 971e27396588dbe6d062af71e3c656bb6f56f882b94ac1f1b93f059b41c28147
MD5 bd00f6b7f447fe9a43af8a7fdb93dcd4
BLAKE2b-256 a38121bd5e50e84b65ede2bcc48e39720740421095e39af23249b97fcf8ea058

See more details on using hashes here.

File details

Details for the file cstructpy-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: cstructpy-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 8.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for cstructpy-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 05cdce03a01205bdcf52a24387b0349a66f058be4d0d6941b5982d2b65ccef2a
MD5 fd2dbb9dd7be2c89d0fe0896d239e0c3
BLAKE2b-256 a020e00453b768b985ac71fb5ec058080e6274db75dd7ec0298b0dff75c61a52

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