cdataclass


Namecdataclass JSON
Version 0.1.2 PyPI version JSON
download
home_pagehttps://github.com/hajoks/cdata
SummaryIntegration of ctypes and dataclasses
upload_time2023-03-11 15:29:09
maintainer
docs_urlNone
authorhajoks
requires_python>=3.6
licenseMIT
keywords dataclasses ctypes
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # cdataclass - Python dataclass for C structure

## Overview

Integration of python dataclass and ctypes.Structure.

This library provides some API for encoding/decoding dataclasses into/from ctypes.Structure/ctypes.Union.

This library can be used for:

- handling packed binary data.
- bridging the C API and python application.

## Installation
```bash
$ pip install cdataclass
```

## Examples

```python

import ctypes
from dataclasses import dataclass, field
from typing import List

from cdataclass import BigEndianCDataMixIn, meta


# Simple big endian C structure
@dataclass
class Item(BigEndianCDataMixIn):
    f_item_number: int = field(metadata=meta(ctypes.c_uint32))
    f_item_bytes: bytes = field(metadata=meta(ctypes.c_char * 10))


# Use as normal dataclass
item = Item(1, b"test")
assert item.f_item_number == 1
assert item.f_item_bytes == b"test"


# Get corresponding ctypes.Structure class
c_item_class = Item.ctype()
assert issubclass(c_item_class, ctypes.BigEndianStructure)
assert hasattr(c_item_class, "_fields_")
assert hasattr(c_item_class, "_pack_")


# Get the size of corresponding ctypes.Structure class
assert Item.size() == 14  # uint32(4 bytes) + c_char * 10(10 bytes) = 14


# Convert to ctype.Structure instance
c_item = item.to_ctype()
assert isinstance(c_item, ctypes.BigEndianStructure)
assert c_item.f_item_number == 1
assert c_item.f_item_bytes == b"test"


# Serialize/Deserialize to/from buffer
hex_str_represents_uint32_100 = "00 00 00 64"
hex_str_represents_char_ABCDEFGHIJ = "41 42 43 44 45 46 47 48 49 4A"
buffer = bytearray.fromhex(hex_str_represents_uint32_100 + " " + hex_str_represents_char_ABCDEFGHIJ)
item = Item.from_buffer(buffer)
assert item.f_item_number == 100
assert item.f_item_bytes == b"ABCDEFGHIJ"
assert item.to_bytearray() == buffer


# Serialize/Deserialize to/from immutable buffer
immutable_buffer = bytes(buffer)
item = Item.from_buffer_copy(immutable_buffer)
assert item.f_item_number == 100
assert item.f_item_bytes == b"ABCDEFGHIJ"
assert item.to_bytes() == immutable_buffer


# Use custom ecoding/decoding functions for data conversion
@dataclass
class CustomItem(BigEndianCDataMixIn):
    f_number: int = field(
        metadata=meta(
            ctypes.c_char * 10,
            encoder=lambda v: str(v).rjust(10).encode("utf-8"),
            decoder=lambda v: int(v.decode("utf-8")),
        )
    )
    f_string: str = field(
        metadata=meta(
            ctypes.c_char * 10,
            encoder=lambda v: v.encode("utf-8"),
            decoder=lambda v: v.decode("utf-8"),
        )
    )


custom_item = CustomItem(100, "test")

# Encode as specified
c_custom_item = custom_item.to_ctype()
assert c_custom_item.f_number == b"       100"
assert c_custom_item.f_string == b"test"

# Decode as specified
custom_item = CustomItem.from_buffer_copy(custom_item.to_bytes())
assert custom_item.f_number == 100
assert custom_item.f_string == "test"


# Nested structure
@dataclass
class Data(BigEndianCDataMixIn):
    f_number: int = field(metadata=meta(ctypes.c_uint32))
    f_bytes: bytes = field(metadata=meta(ctypes.c_char * 20))
    # Use cls.ctype() to define a nested structure or array of structure or whatever customized
    f_item: Item = field(metadata=meta(Item.ctype()))
    f_items: List[Item] = field(metadata=meta(Item.ctype() * 5))
    f_int_array: List[int] = field(metadata=meta(ctypes.c_uint16 * 5))


data = Data(
    1,
    b"data",
    Item(100, b"item"),
    [Item(i, bytes(f"item{i}", "utf-8")) for i in range(5)],
    [i for i in range(5)],
)

# Access the nested field
c_data = data.to_ctype()
assert c_data.f_item.f_item_number == 100
assert c_data.f_item.f_item_bytes == b"item"

# Access the nested array
assert c_data.f_items[0].f_item_number == 0
assert c_data.f_items[0].f_item_bytes == b"item0"
assert c_data.f_items[4].f_item_number == 4
assert c_data.f_items[4].f_item_bytes == b"item4"

assert c_data.f_int_array[0] == 0
assert c_data.f_int_array[4] == 4

```



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/hajoks/cdata",
    "name": "cdataclass",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "dataclasses ctypes",
    "author": "hajoks",
    "author_email": "syari4369@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/4a/0a/c5c2cf2aca25cde06ccac1a40e29fcaef5e5805eae9af4e1320c7c38c36f/cdataclass-0.1.2.tar.gz",
    "platform": null,
    "description": "# cdataclass - Python dataclass for C structure\n\n## Overview\n\nIntegration of python dataclass and ctypes.Structure.\n\nThis library provides some API for encoding/decoding dataclasses into/from ctypes.Structure/ctypes.Union.\n\nThis library can be used for:\n\n- handling packed binary data.\n- bridging the C API and python application.\n\n## Installation\n```bash\n$ pip install cdataclass\n```\n\n## Examples\n\n```python\n\nimport ctypes\nfrom dataclasses import dataclass, field\nfrom typing import List\n\nfrom cdataclass import BigEndianCDataMixIn, meta\n\n\n# Simple big endian C structure\n@dataclass\nclass Item(BigEndianCDataMixIn):\n    f_item_number: int = field(metadata=meta(ctypes.c_uint32))\n    f_item_bytes: bytes = field(metadata=meta(ctypes.c_char * 10))\n\n\n# Use as normal dataclass\nitem = Item(1, b\"test\")\nassert item.f_item_number == 1\nassert item.f_item_bytes == b\"test\"\n\n\n# Get corresponding ctypes.Structure class\nc_item_class = Item.ctype()\nassert issubclass(c_item_class, ctypes.BigEndianStructure)\nassert hasattr(c_item_class, \"_fields_\")\nassert hasattr(c_item_class, \"_pack_\")\n\n\n# Get the size of corresponding ctypes.Structure class\nassert Item.size() == 14  # uint32(4 bytes) + c_char * 10(10 bytes) = 14\n\n\n# Convert to ctype.Structure instance\nc_item = item.to_ctype()\nassert isinstance(c_item, ctypes.BigEndianStructure)\nassert c_item.f_item_number == 1\nassert c_item.f_item_bytes == b\"test\"\n\n\n# Serialize/Deserialize to/from buffer\nhex_str_represents_uint32_100 = \"00 00 00 64\"\nhex_str_represents_char_ABCDEFGHIJ = \"41 42 43 44 45 46 47 48 49 4A\"\nbuffer = bytearray.fromhex(hex_str_represents_uint32_100 + \" \" + hex_str_represents_char_ABCDEFGHIJ)\nitem = Item.from_buffer(buffer)\nassert item.f_item_number == 100\nassert item.f_item_bytes == b\"ABCDEFGHIJ\"\nassert item.to_bytearray() == buffer\n\n\n# Serialize/Deserialize to/from immutable buffer\nimmutable_buffer = bytes(buffer)\nitem = Item.from_buffer_copy(immutable_buffer)\nassert item.f_item_number == 100\nassert item.f_item_bytes == b\"ABCDEFGHIJ\"\nassert item.to_bytes() == immutable_buffer\n\n\n# Use custom ecoding/decoding functions for data conversion\n@dataclass\nclass CustomItem(BigEndianCDataMixIn):\n    f_number: int = field(\n        metadata=meta(\n            ctypes.c_char * 10,\n            encoder=lambda v: str(v).rjust(10).encode(\"utf-8\"),\n            decoder=lambda v: int(v.decode(\"utf-8\")),\n        )\n    )\n    f_string: str = field(\n        metadata=meta(\n            ctypes.c_char * 10,\n            encoder=lambda v: v.encode(\"utf-8\"),\n            decoder=lambda v: v.decode(\"utf-8\"),\n        )\n    )\n\n\ncustom_item = CustomItem(100, \"test\")\n\n# Encode as specified\nc_custom_item = custom_item.to_ctype()\nassert c_custom_item.f_number == b\"       100\"\nassert c_custom_item.f_string == b\"test\"\n\n# Decode as specified\ncustom_item = CustomItem.from_buffer_copy(custom_item.to_bytes())\nassert custom_item.f_number == 100\nassert custom_item.f_string == \"test\"\n\n\n# Nested structure\n@dataclass\nclass Data(BigEndianCDataMixIn):\n    f_number: int = field(metadata=meta(ctypes.c_uint32))\n    f_bytes: bytes = field(metadata=meta(ctypes.c_char * 20))\n    # Use cls.ctype() to define a nested structure or array of structure or whatever customized\n    f_item: Item = field(metadata=meta(Item.ctype()))\n    f_items: List[Item] = field(metadata=meta(Item.ctype() * 5))\n    f_int_array: List[int] = field(metadata=meta(ctypes.c_uint16 * 5))\n\n\ndata = Data(\n    1,\n    b\"data\",\n    Item(100, b\"item\"),\n    [Item(i, bytes(f\"item{i}\", \"utf-8\")) for i in range(5)],\n    [i for i in range(5)],\n)\n\n# Access the nested field\nc_data = data.to_ctype()\nassert c_data.f_item.f_item_number == 100\nassert c_data.f_item.f_item_bytes == b\"item\"\n\n# Access the nested array\nassert c_data.f_items[0].f_item_number == 0\nassert c_data.f_items[0].f_item_bytes == b\"item0\"\nassert c_data.f_items[4].f_item_number == 4\nassert c_data.f_items[4].f_item_bytes == b\"item4\"\n\nassert c_data.f_int_array[0] == 0\nassert c_data.f_int_array[4] == 4\n\n```\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Integration of ctypes and dataclasses",
    "version": "0.1.2",
    "split_keywords": [
        "dataclasses",
        "ctypes"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d5d98fd79713fa0258bbc22f35e69df9bdb5951c17603ec4f27deb9fb8d9c93f",
                "md5": "c1951d893152006f105272c2acc55f17",
                "sha256": "22311fed1c298b8eed9987f8b2577e6c19b319365704d95b9333c360bd56256e"
            },
            "downloads": -1,
            "filename": "cdataclass-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c1951d893152006f105272c2acc55f17",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 7075,
            "upload_time": "2023-03-11T15:29:06",
            "upload_time_iso_8601": "2023-03-11T15:29:06.688594Z",
            "url": "https://files.pythonhosted.org/packages/d5/d9/8fd79713fa0258bbc22f35e69df9bdb5951c17603ec4f27deb9fb8d9c93f/cdataclass-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4a0ac5c2cf2aca25cde06ccac1a40e29fcaef5e5805eae9af4e1320c7c38c36f",
                "md5": "0dfbcbdc81bdca2223b92f2c5ff03cfa",
                "sha256": "8aa4ba8781d09dbdc6abeb479a2cc361bf179be6f71ca3b82437a1ac0c0423a2"
            },
            "downloads": -1,
            "filename": "cdataclass-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "0dfbcbdc81bdca2223b92f2c5ff03cfa",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 7100,
            "upload_time": "2023-03-11T15:29:09",
            "upload_time_iso_8601": "2023-03-11T15:29:09.002515Z",
            "url": "https://files.pythonhosted.org/packages/4a/0a/c5c2cf2aca25cde06ccac1a40e29fcaef5e5805eae9af4e1320c7c38c36f/cdataclass-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-03-11 15:29:09",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "hajoks",
    "github_project": "cdata",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "cdataclass"
}
        
Elapsed time: 0.04299s