serious


Nameserious JSON
Version 1.6.2 PyPI version JSON
download
home_pagehttps://github.com/mdrachuk/serious
SummaryEasily serialize dataclasses to and from JSON
upload_time2024-12-15 21:40:55
maintainerNone
docs_urlNone
authormdrachuk
requires_python>=3.10
licenseMIT
keywords dataclasses json serialization
VCS
bugtrack_url
requirements coveralls cv mkdocs mypy pytest pytest-cov twine wheel sqlalchemy pydantic
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # serious
[![PyPI](https://img.shields.io/pypi/v/serious)][pypi]
[![Build Status](https://img.shields.io/azure-devops/build/misha-drachuk/serious/2)](https://dev.azure.com/misha-drachuk/serious/_build/latest?definitionId=1&branchName=master)
[![Test Coverage](https://img.shields.io/coveralls/github/mdrachuk/serious/master)](https://coveralls.io/github/mdrachuk/serious)
[![Supported Python](https://img.shields.io/pypi/pyversions/serious)][pypi]
[![Documentation](https://img.shields.io/readthedocs/serious)][docs]

A dataclass model toolkit: serialization, validation, and more.

[Documentation][docs]


## Features
- Model definitions in pure Python.
- Validation showing up in code coverage.
- Type annotations for all public-facing APIs.
- (Optionally) ensures immutability.
- Easily extensible.
- Made for people.
- Documented rigorously.

## Basics
### Installation
Available from [PyPI][pypi]:
```shell
pip install serious
```

### Quick Example

Central part of Serious API are different [Models][doc-models].

Given a regular dataclass:
```python
from dataclasses import dataclass

@dataclass
class Person:
    name: str
```

Let’s create a `JsonModel`:  
```python
from serious.json import JsonModel
    
model = JsonModel(Person)
```

And use its [dump/load methods][doc-serialization]:
```python
person = Person('Albert Einstein')

model.dump(person) # {"name": "Albert Einstein"}
```

### Validation
To add validation to the example above all we need is to add `__validate__` method to person:
```python
from dataclasses import dataclass
from typing import Optional
from serious import ValidationError, Email

@dataclass
class Person:
    name: str
    email: Optional[Email]
    phone: Optional[str]

    def __validate__(self):
        if len(self.name) == 0:
            raise ValidationError('Every person needs a name')
        if self.phone is None and self.email is None:
            raise ValidationError('At least some contact should be present')
```

[More on validation.][doc-validation]


### Supported formats:
- [x] [JSON][doc-json-model]
- [x] [Python Dictionaries][doc-dict-model]
- [ ] YAML
- [ ] Form data


### Supported field types
[More in docs.][doc-types]

- Other dataclasses
- Primitives: `str`, `int`, `float`, `bool`
- Dictionaries: only with string keys: `Dict[str, Any]`  
- Lists, [sets][set], [deques][deque]: python collections of any serializable type
- [Tuples][tuple] both with and without ellipsis:
    - tuples as set of independent elements (e.g. `Tuple[str, int, date]`) 
    - with ellipses, acting as a frozen list (`Tuple[str, ...]`)
- [Enumerations][enum] by value:
    - of primitives (e.g. `OperatingSystem(Enum)`) 
    - typed enums (`Color(str, Enum)` and `FilePermission(IntFlag)`)
- [Decimal][decimal]: encoded to JSON as string 
- [Datetime][datetime], [date][date] and [time][time]: encoded to the [ISO 8601][iso8601] formatted string
- [UUID][uuid]
- `serious.types.Timestamp`: a UTC timestamp since [UNIX epoch][epoch] as float ms value 
- `serious.types.Email`: a string Tiny Type that supports validation and contains additional properties 
- custom immutable alternatives to native python types in `serious.types`: `FrozenList`, `FrozenDict`

## A bigger example

```python
from dataclasses import dataclass
from serious import JsonModel, ValidationError
from typing import List
from enum import Enum

class Specialty(Enum):
    Worker = 1
    Fool = 2


@dataclass(frozen=True)
class Minion:
    name: str
    type: Specialty


@dataclass(frozen=True)
class Boss:
    name: str
    minions: List[Minion]
    
    def __validate__(self):
        if len(self.minions) < 2:
            raise ValidationError('What kind of boss are you?')


boss = Boss("me", [Minion('evil minion', Specialty.Fool), Minion('very evil minion', Specialty.Worker)])
boss_json = """{
    "name": "me",
    "minions": [
        {
            "name": "evil minion",
            "type": "Fool"
        },
        {
            "name": "very evil minion",
            "type": "Worker"
        }
    ]
}"""

model = JsonModel(Boss, indent=4)

assert model.dump(boss) == boss_json
assert model.load(boss_json) == boss
```


## Acknowledgements
Initially, a fork of [@lidatong/dataclasses-json](https://github.com/lidatong/dataclasses-json).

[pypi]: https://pypi.org/project/serious/
[dataclass]: https://docs.python.org/3/library/dataclasses.html
[iso8601]: https://en.wikipedia.org/wiki/ISO_8601
[epoch]: https://en.wikipedia.org/wiki/Unix_time
[enum]: https://docs.python.org/3/library/enum.html
[decimal]: https://docs.python.org/3/library/decimal.html
[tuple]: https://docs.python.org/3/library/stdtypes.html#tuple
[list]: https://docs.python.org/3/library/stdtypes.html#list
[set]: https://docs.python.org/3/library/stdtypes.html#set
[deque]: https://docs.python.org/3.7/library/collections.html#collections.deque
[datetime]: https://docs.python.org/3.7/library/datetime.html#datetime.datetime
[date]: https://docs.python.org/3.7/library/datetime.html#datetime.date
[time]: https://docs.python.org/3.7/library/datetime.html#datetime.time
[uuid]: https://docs.python.org/3.7/library/uuid.html?highlight=uuid#uuid.UUID
[doc-types]: https://serious.readthedocs.io/en/latest/types/
[doc-models]: https://serious.readthedocs.io/en/latest/models/
[doc-json-model]: https://serious.readthedocs.io/en/latest/models/#jsonmodel
[doc-dict-model]: https://serious.readthedocs.io/en/latest/models/#dictmodel
[doc-serialization]: https://serious.readthedocs.io/en/latest/serialization/ (Serialization documentation)
[doc-validation]: https://serious.readthedocs.io/en/latest/validation/ (Validation documentation)
[docs]: https://serious.readthedocs.io/en/latest/ 

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/mdrachuk/serious",
    "name": "serious",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "dataclasses json serialization",
    "author": "mdrachuk",
    "author_email": "misha@drach.uk",
    "download_url": "https://files.pythonhosted.org/packages/c2/0d/4521c2b0c8ed477414bd1f53f3b4fcd6d2a28c2a7a001221dd589cc9322a/serious-1.6.2.tar.gz",
    "platform": null,
    "description": "# serious\n[![PyPI](https://img.shields.io/pypi/v/serious)][pypi]\n[![Build Status](https://img.shields.io/azure-devops/build/misha-drachuk/serious/2)](https://dev.azure.com/misha-drachuk/serious/_build/latest?definitionId=1&branchName=master)\n[![Test Coverage](https://img.shields.io/coveralls/github/mdrachuk/serious/master)](https://coveralls.io/github/mdrachuk/serious)\n[![Supported Python](https://img.shields.io/pypi/pyversions/serious)][pypi]\n[![Documentation](https://img.shields.io/readthedocs/serious)][docs]\n\nA dataclass model toolkit: serialization, validation, and more.\n\n[Documentation][docs]\n\n\n## Features\n- Model definitions in pure Python.\n- Validation showing up in code coverage.\n- Type annotations for all public-facing APIs.\n- (Optionally) ensures immutability.\n- Easily extensible.\n- Made for people.\n- Documented rigorously.\n\n## Basics\n### Installation\nAvailable from [PyPI][pypi]:\n```shell\npip install serious\n```\n\n### Quick Example\n\nCentral part of Serious API are different [Models][doc-models].\n\nGiven a regular dataclass:\n```python\nfrom dataclasses import dataclass\n\n@dataclass\nclass Person:\n    name: str\n```\n\nLet\u2019s create a `JsonModel`:  \n```python\nfrom serious.json import JsonModel\n    \nmodel = JsonModel(Person)\n```\n\nAnd use its [dump/load methods][doc-serialization]:\n```python\nperson = Person('Albert Einstein')\n\nmodel.dump(person) # {\"name\": \"Albert Einstein\"}\n```\n\n### Validation\nTo add validation to the example above all we need is to add `__validate__` method to person:\n```python\nfrom dataclasses import dataclass\nfrom typing import Optional\nfrom serious import ValidationError, Email\n\n@dataclass\nclass Person:\n    name: str\n    email: Optional[Email]\n    phone: Optional[str]\n\n    def __validate__(self):\n        if len(self.name) == 0:\n            raise ValidationError('Every person needs a name')\n        if self.phone is None and self.email is None:\n            raise ValidationError('At least some contact should be present')\n```\n\n[More on validation.][doc-validation]\n\n\n### Supported formats:\n- [x] [JSON][doc-json-model]\n- [x] [Python Dictionaries][doc-dict-model]\n- [ ] YAML\n- [ ] Form data\n\n\n### Supported field types\n[More in docs.][doc-types]\n\n- Other dataclasses\n- Primitives: `str`, `int`, `float`, `bool`\n- Dictionaries: only with string keys: `Dict[str, Any]`  \n- Lists, [sets][set], [deques][deque]: python collections of any serializable type\n- [Tuples][tuple] both with and without ellipsis:\n    - tuples as set of independent elements (e.g. `Tuple[str, int, date]`) \n    - with ellipses, acting as a frozen list (`Tuple[str, ...]`)\n- [Enumerations][enum] by value:\n    - of primitives (e.g. `OperatingSystem(Enum)`) \n    - typed enums (`Color(str, Enum)` and `FilePermission(IntFlag)`)\n- [Decimal][decimal]: encoded to JSON as string \n- [Datetime][datetime], [date][date] and [time][time]:\u00a0encoded to the [ISO 8601][iso8601] formatted string\n- [UUID][uuid]\n- `serious.types.Timestamp`: a UTC timestamp since [UNIX epoch][epoch] as float ms value \n- `serious.types.Email`: a string Tiny Type that supports validation and contains additional properties \n- custom immutable alternatives to native python types in `serious.types`: `FrozenList`, `FrozenDict`\n\n## A bigger example\n\n```python\nfrom dataclasses import dataclass\nfrom serious import JsonModel, ValidationError\nfrom typing import List\nfrom enum import Enum\n\nclass Specialty(Enum):\n    Worker = 1\n    Fool = 2\n\n\n@dataclass(frozen=True)\nclass Minion:\n    name: str\n    type: Specialty\n\n\n@dataclass(frozen=True)\nclass Boss:\n    name: str\n    minions: List[Minion]\n    \n    def __validate__(self):\n        if len(self.minions) < 2:\n            raise ValidationError('What kind of boss are you?')\n\n\nboss = Boss(\"me\", [Minion('evil minion', Specialty.Fool), Minion('very evil minion', Specialty.Worker)])\nboss_json = \"\"\"{\n    \"name\": \"me\",\n    \"minions\": [\n        {\n            \"name\": \"evil minion\",\n            \"type\": \"Fool\"\n        },\n        {\n            \"name\": \"very evil minion\",\n            \"type\": \"Worker\"\n        }\n    ]\n}\"\"\"\n\nmodel = JsonModel(Boss, indent=4)\n\nassert model.dump(boss) == boss_json\nassert model.load(boss_json) == boss\n```\n\n\n## Acknowledgements\nInitially, a fork of [@lidatong/dataclasses-json](https://github.com/lidatong/dataclasses-json).\n\n[pypi]: https://pypi.org/project/serious/\n[dataclass]: https://docs.python.org/3/library/dataclasses.html\n[iso8601]: https://en.wikipedia.org/wiki/ISO_8601\n[epoch]: https://en.wikipedia.org/wiki/Unix_time\n[enum]: https://docs.python.org/3/library/enum.html\n[decimal]: https://docs.python.org/3/library/decimal.html\n[tuple]: https://docs.python.org/3/library/stdtypes.html#tuple\n[list]: https://docs.python.org/3/library/stdtypes.html#list\n[set]: https://docs.python.org/3/library/stdtypes.html#set\n[deque]: https://docs.python.org/3.7/library/collections.html#collections.deque\n[datetime]: https://docs.python.org/3.7/library/datetime.html#datetime.datetime\n[date]: https://docs.python.org/3.7/library/datetime.html#datetime.date\n[time]: https://docs.python.org/3.7/library/datetime.html#datetime.time\n[uuid]: https://docs.python.org/3.7/library/uuid.html?highlight=uuid#uuid.UUID\n[doc-types]: https://serious.readthedocs.io/en/latest/types/\n[doc-models]: https://serious.readthedocs.io/en/latest/models/\n[doc-json-model]: https://serious.readthedocs.io/en/latest/models/#jsonmodel\n[doc-dict-model]: https://serious.readthedocs.io/en/latest/models/#dictmodel\n[doc-serialization]: https://serious.readthedocs.io/en/latest/serialization/ (Serialization documentation)\n[doc-validation]: https://serious.readthedocs.io/en/latest/validation/ (Validation documentation)\n[docs]: https://serious.readthedocs.io/en/latest/ \n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Easily serialize dataclasses to and from JSON",
    "version": "1.6.2",
    "project_urls": {
        "Homepage": "https://github.com/mdrachuk/serious",
        "Issues": "https://github.com/mdrachuk/serious/issues",
        "Pipelines": "https://dev.azure.com/misha-drachuk/serious",
        "Source": "https://github.com/mdrachuk/serious/"
    },
    "split_keywords": [
        "dataclasses",
        "json",
        "serialization"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a8563a444766462825506d48fd71b08a6a41b3fe6d9bc17bc2e08f2de44b0307",
                "md5": "53783268d2e66461b48ebdb9b8828a15",
                "sha256": "5327ffe1c30a95d91d33c6d9b2d6a98840016fc149cd4569523ac601741bc774"
            },
            "downloads": -1,
            "filename": "serious-1.6.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "53783268d2e66461b48ebdb9b8828a15",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 33708,
            "upload_time": "2024-12-15T21:40:53",
            "upload_time_iso_8601": "2024-12-15T21:40:53.219549Z",
            "url": "https://files.pythonhosted.org/packages/a8/56/3a444766462825506d48fd71b08a6a41b3fe6d9bc17bc2e08f2de44b0307/serious-1.6.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c20d4521c2b0c8ed477414bd1f53f3b4fcd6d2a28c2a7a001221dd589cc9322a",
                "md5": "500660544684d3c019917a020bc6c4c8",
                "sha256": "fd1bf279d2ae860f057a893c214d2e5b538991b935ca0d1791ad9cb7b9c81ce5"
            },
            "downloads": -1,
            "filename": "serious-1.6.2.tar.gz",
            "has_sig": false,
            "md5_digest": "500660544684d3c019917a020bc6c4c8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 28086,
            "upload_time": "2024-12-15T21:40:55",
            "upload_time_iso_8601": "2024-12-15T21:40:55.821907Z",
            "url": "https://files.pythonhosted.org/packages/c2/0d/4521c2b0c8ed477414bd1f53f3b4fcd6d2a28c2a7a001221dd589cc9322a/serious-1.6.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-15 21:40:55",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mdrachuk",
    "github_project": "serious",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "coveralls",
            "specs": [
                [
                    "==",
                    "3.3.1"
                ]
            ]
        },
        {
            "name": "cv",
            "specs": [
                [
                    "==",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "mkdocs",
            "specs": [
                [
                    "==",
                    "1.5.2"
                ]
            ]
        },
        {
            "name": "mypy",
            "specs": [
                [
                    "==",
                    "1.4.1"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "7.4.0"
                ]
            ]
        },
        {
            "name": "pytest-cov",
            "specs": [
                [
                    "==",
                    "4.1.0"
                ]
            ]
        },
        {
            "name": "twine",
            "specs": [
                [
                    "==",
                    "5.1.1"
                ]
            ]
        },
        {
            "name": "wheel",
            "specs": [
                [
                    "==",
                    "0.41.1"
                ]
            ]
        },
        {
            "name": "sqlalchemy",
            "specs": [
                [
                    "==",
                    "2.0.34"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    "==",
                    "2.9.1"
                ]
            ]
        }
    ],
    "lcname": "serious"
}
        
Elapsed time: 0.48367s