dataclasses-codec


Namedataclasses-codec JSON
Version 1.0.0 PyPI version JSON
download
home_pageNone
SummarySimple Python dataclass serialization package with no dependencies
upload_time2025-10-25 12:09:18
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords codec dataclass decoder encoder json serialization
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # StupidSimple Dataclasses Codec

[![PyPI version](https://img.shields.io/pypi/v/dataclasses-codec.svg)](https://pypi.org/project/dataclasses-codec/)
[![Python versions](https://img.shields.io/pypi/pyversions/dataclasses-codec.svg)](https://pypi.org/project/dataclasses-codec/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Tests](https://github.com/stupid-simple/dataclasses-codec/actions/workflows/test.yml/badge.svg)](https://github.com/stupid-simple/dataclasses-codec/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/stupid-simple/dataclasses-codec/branch/main/graph/badge.svg)](https://codecov.io/gh/stupid-simple/dataclasses-codec)

This native Python package allows to easily convert dataclasses into and from a serialized form. By default supports json.

## Installation

```bash
pip install dataclasses-codec
```

## Usage

The package provides functions to easily convert dataclasses into and from a serialized form. It uses by default the `json_codec` instance the package provides.

```python
from dataclasses import dataclass
from dataclasses_codec import encode, decode, to_json, from_json

@dataclass
class MyDataclass:
    first_name: str
    last_name: str

obj = MyDataclass("John", "Doe")

# Serializable Python dictionary
encoded = encode(obj)
print(encoded)
# Output: {'first_name': 'John', 'last_name': 'Doe'}

decoded = decode(MyDataclass, encoded)
print(decoded)
# Output: MyDataclass(first_name="John", last_name="Doe")

# Native JSON handling

raw_json = to_json(obj)
print(raw_json)
# Output: '{"first_name": "John", "last_name": "Doe"}'

restored = from_json(MyDataclass, raw_json)
print(restored)
# Output: MyDataclass(first_name="John", last_name="Doe")
```

### JSON codec

The JSON codec is a first class citizen of the package. It allows to easily convert dataclasses into and from JSON strings.

Serialization can be customized by using the `json_field` value. It supports native conversion of `date` and `datetime` fields. Dataclasses can be nested to form complex objects.

`json_field` extends the native dataclass `field` decorator to support custom serialization and deserialization.

```python
from dataclasses import dataclass
from dataclasses_codec import json_codec, JSONOptional, JSON_MISSING
from dataclasses_codec.codecs.json import json_field
import datetime as dt

# Still a dataclass, so we can use its features like slots, frozen, etc.
@dataclass(slots=True)
class MyMetadataDataclass:
    created_at: dt.datetime
    updated_at: dt.datetime = json_field(
        serializer=lambda d: d.isoformat(),
        deserializer=lambda s: dt.datetime.fromisoformat(s)
    )
    enabled: bool | JSONOptional = JSON_MISSING # Explicitly mark a field as optional
    description: str | None = None # None is intentionally serialized as null


@dataclass
class MyDataclass:
    first_name: str
    last_name: str
    age: int
    metadata: MyMetadataDataclass = json_field(
        json_name="meta"
    )

obj = MyDataclass("John", "Doe", 30, MyMetadataDataclass(dt.datetime.now(), dt.datetime.now()))

raw_json = json_codec.to_json(obj)
print(raw_json)
# Output: '{"first_name": "John", "last_name": "Doe", "age": 30, "meta": {"created_at": "2025-10-25T11:53:35.918899", "updated_at": "2025-10-25T11:53:35.918902", "description": null}}'
```

### JSON Mixins

The package provides JSON mixins to add the serialization and deserialization capabilities to a dataclass.

By default, the JSON codec is used. See: `dataclasses_codec.codecs.json` for more details.

```python
from dataclasses import dataclass
from dataclasses_codec import JSONSerializable, JSONDeserializable

@dataclass
class MyDataclass(JSONSerializable, JSONDeserializable):
    first_name: str
    last_name: str
    age: int

obj = MyDataclass("John", "Doe", 30)

encoded = obj.to_dict(to_camel_case=True)
print(encoded)
# Output: {'firstName': 'John', 'lastName': 'Doe', 'age': 30}

restored = MyDataclass.from_dict(encoded, to_snake_case=True)
print(restored)
# Output: MyDataclass(first_name="John", last_name="Doe", age=30)
```

### Extensibility

The package allows to extend the functionality of the codecs by implementing the `Codec` interface.

Each implementation should use `is_dataclass` to check if the object is a dataclass.

```python
from dataclasses import dataclass, is_dataclass
from dataclasses_codec import Codec, encode
from dataclasses_codec.errors import CodecError

class MyCodec(Codec):
    def encode(self, obj, **kwargs):
        if not is_dataclass(obj):
            raise CodecError(f"obj is not a dataclass, found: '{obj}'")
        return obj
    def decode(self, cls, data, **kwargs):
        # Implement the decoding logic here
        raise CodecError("Decoding is not implemented for this codec")

@dataclass
class MyDataclass:
    first_name: str
    last_name: str
    age: int

obj = MyDataclass("John", "Doe", 30)

encoded = encode(obj, codec=MyCodec())
print(encoded)
# Output: {'first_name': 'John', 'last_name': 'Doe', 'age': 30}
```

## Development

### Running the tests

```bash
python -m unittest
```
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dataclasses-codec",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "codec, dataclass, decoder, encoder, json, serialization",
    "author": null,
    "author_email": "i-segura <github@m.isu101.com>",
    "download_url": "https://files.pythonhosted.org/packages/00/44/36ab7ec8ad4806d8b1686c17899c718c247c07eb9eca1202b5a45bf38275/dataclasses_codec-1.0.0.tar.gz",
    "platform": null,
    "description": "# StupidSimple Dataclasses Codec\n\n[![PyPI version](https://img.shields.io/pypi/v/dataclasses-codec.svg)](https://pypi.org/project/dataclasses-codec/)\n[![Python versions](https://img.shields.io/pypi/pyversions/dataclasses-codec.svg)](https://pypi.org/project/dataclasses-codec/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Tests](https://github.com/stupid-simple/dataclasses-codec/actions/workflows/test.yml/badge.svg)](https://github.com/stupid-simple/dataclasses-codec/actions/workflows/test.yml)\n[![codecov](https://codecov.io/gh/stupid-simple/dataclasses-codec/branch/main/graph/badge.svg)](https://codecov.io/gh/stupid-simple/dataclasses-codec)\n\nThis native Python package allows to easily convert dataclasses into and from a serialized form. By default supports json.\n\n## Installation\n\n```bash\npip install dataclasses-codec\n```\n\n## Usage\n\nThe package provides functions to easily convert dataclasses into and from a serialized form. It uses by default the `json_codec` instance the package provides.\n\n```python\nfrom dataclasses import dataclass\nfrom dataclasses_codec import encode, decode, to_json, from_json\n\n@dataclass\nclass MyDataclass:\n    first_name: str\n    last_name: str\n\nobj = MyDataclass(\"John\", \"Doe\")\n\n# Serializable Python dictionary\nencoded = encode(obj)\nprint(encoded)\n# Output: {'first_name': 'John', 'last_name': 'Doe'}\n\ndecoded = decode(MyDataclass, encoded)\nprint(decoded)\n# Output: MyDataclass(first_name=\"John\", last_name=\"Doe\")\n\n# Native JSON handling\n\nraw_json = to_json(obj)\nprint(raw_json)\n# Output: '{\"first_name\": \"John\", \"last_name\": \"Doe\"}'\n\nrestored = from_json(MyDataclass, raw_json)\nprint(restored)\n# Output: MyDataclass(first_name=\"John\", last_name=\"Doe\")\n```\n\n### JSON codec\n\nThe JSON codec is a first class citizen of the package. It allows to easily convert dataclasses into and from JSON strings.\n\nSerialization can be customized by using the `json_field` value. It supports native conversion of `date` and `datetime` fields. Dataclasses can be nested to form complex objects.\n\n`json_field` extends the native dataclass `field` decorator to support custom serialization and deserialization.\n\n```python\nfrom dataclasses import dataclass\nfrom dataclasses_codec import json_codec, JSONOptional, JSON_MISSING\nfrom dataclasses_codec.codecs.json import json_field\nimport datetime as dt\n\n# Still a dataclass, so we can use its features like slots, frozen, etc.\n@dataclass(slots=True)\nclass MyMetadataDataclass:\n    created_at: dt.datetime\n    updated_at: dt.datetime = json_field(\n        serializer=lambda d: d.isoformat(),\n        deserializer=lambda s: dt.datetime.fromisoformat(s)\n    )\n    enabled: bool | JSONOptional = JSON_MISSING # Explicitly mark a field as optional\n    description: str | None = None # None is intentionally serialized as null\n\n\n@dataclass\nclass MyDataclass:\n    first_name: str\n    last_name: str\n    age: int\n    metadata: MyMetadataDataclass = json_field(\n        json_name=\"meta\"\n    )\n\nobj = MyDataclass(\"John\", \"Doe\", 30, MyMetadataDataclass(dt.datetime.now(), dt.datetime.now()))\n\nraw_json = json_codec.to_json(obj)\nprint(raw_json)\n# Output: '{\"first_name\": \"John\", \"last_name\": \"Doe\", \"age\": 30, \"meta\": {\"created_at\": \"2025-10-25T11:53:35.918899\", \"updated_at\": \"2025-10-25T11:53:35.918902\", \"description\": null}}'\n```\n\n### JSON Mixins\n\nThe package provides JSON mixins to add the serialization and deserialization capabilities to a dataclass.\n\nBy default, the JSON codec is used. See: `dataclasses_codec.codecs.json` for more details.\n\n```python\nfrom dataclasses import dataclass\nfrom dataclasses_codec import JSONSerializable, JSONDeserializable\n\n@dataclass\nclass MyDataclass(JSONSerializable, JSONDeserializable):\n    first_name: str\n    last_name: str\n    age: int\n\nobj = MyDataclass(\"John\", \"Doe\", 30)\n\nencoded = obj.to_dict(to_camel_case=True)\nprint(encoded)\n# Output: {'firstName': 'John', 'lastName': 'Doe', 'age': 30}\n\nrestored = MyDataclass.from_dict(encoded, to_snake_case=True)\nprint(restored)\n# Output: MyDataclass(first_name=\"John\", last_name=\"Doe\", age=30)\n```\n\n### Extensibility\n\nThe package allows to extend the functionality of the codecs by implementing the `Codec` interface.\n\nEach implementation should use `is_dataclass` to check if the object is a dataclass.\n\n```python\nfrom dataclasses import dataclass, is_dataclass\nfrom dataclasses_codec import Codec, encode\nfrom dataclasses_codec.errors import CodecError\n\nclass MyCodec(Codec):\n    def encode(self, obj, **kwargs):\n        if not is_dataclass(obj):\n            raise CodecError(f\"obj is not a dataclass, found: '{obj}'\")\n        return obj\n    def decode(self, cls, data, **kwargs):\n        # Implement the decoding logic here\n        raise CodecError(\"Decoding is not implemented for this codec\")\n\n@dataclass\nclass MyDataclass:\n    first_name: str\n    last_name: str\n    age: int\n\nobj = MyDataclass(\"John\", \"Doe\", 30)\n\nencoded = encode(obj, codec=MyCodec())\nprint(encoded)\n# Output: {'first_name': 'John', 'last_name': 'Doe', 'age': 30}\n```\n\n## Development\n\n### Running the tests\n\n```bash\npython -m unittest\n```",
    "bugtrack_url": null,
    "license": null,
    "summary": "Simple Python dataclass serialization package with no dependencies",
    "version": "1.0.0",
    "project_urls": {
        "Documentation": "https://github.com/stupid-simple/dataclasses-codec#readme",
        "Homepage": "https://github.com/stupid-simple/dataclasses-codec",
        "Issues": "https://github.com/stupid-simple/dataclasses-codec/issues",
        "Repository": "https://github.com/stupid-simple/dataclasses-codec"
    },
    "split_keywords": [
        "codec",
        " dataclass",
        " decoder",
        " encoder",
        " json",
        " serialization"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8307676cc4dcaebdc6ee3f560add70bf0ecb4c7132d4e141f03410a689727075",
                "md5": "5bd250abfe1542f1b9cf95e159b2ce2d",
                "sha256": "e1fd5264924f11b68ba59dadd2c9b4e761764685c0fd348c2b1e84eb9af6d5ec"
            },
            "downloads": -1,
            "filename": "dataclasses_codec-1.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5bd250abfe1542f1b9cf95e159b2ce2d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 8342,
            "upload_time": "2025-10-25T12:09:16",
            "upload_time_iso_8601": "2025-10-25T12:09:16.909757Z",
            "url": "https://files.pythonhosted.org/packages/83/07/676cc4dcaebdc6ee3f560add70bf0ecb4c7132d4e141f03410a689727075/dataclasses_codec-1.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "004436ab7ec8ad4806d8b1686c17899c718c247c07eb9eca1202b5a45bf38275",
                "md5": "ecfd6eb24bb9a1e4b5ea4928b865a8fa",
                "sha256": "cb258cee3e29827bbef2ca77d0cc09321e01cb5446c69a87edb95b502644333f"
            },
            "downloads": -1,
            "filename": "dataclasses_codec-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "ecfd6eb24bb9a1e4b5ea4928b865a8fa",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 11268,
            "upload_time": "2025-10-25T12:09:18",
            "upload_time_iso_8601": "2025-10-25T12:09:18.382556Z",
            "url": "https://files.pythonhosted.org/packages/00/44/36ab7ec8ad4806d8b1686c17899c718c247c07eb9eca1202b5a45bf38275/dataclasses_codec-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-25 12:09:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "stupid-simple",
    "github_project": "dataclasses-codec#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dataclasses-codec"
}
        
Elapsed time: 3.24338s