# dataclass-jsonable
[![dataclass-jsonable ci](https://github.com/hit9/dataclass-jsonable/actions/workflows/ci.yml/badge.svg)](https://github.com/hit9/dataclass-jsonable/actions/workflows/ci.yml)
![](https://img.shields.io/badge/license-BSD3-brightgreen)
[中文说明](README.zh.md)
Simple and flexible conversions between dataclasses and jsonable dictionaries.
It maps dataclasses to jsonable dictionaries but not json strings.
## Features
* Easy to use.
* Supports common type annotations.
* Supports recursive conversions.
* Supports field-level and dataclass-level overriding.
## Installation
Requirements: Python >= 3.7
Install via `pip`:
```
pip install dataclass-jsonable
```
## Quick Example
```python
from dataclasses import dataclass
from datetime import datetime
from decimal import Decimal
from enum import IntEnum
from typing import List
from dataclass_jsonable import J
class Color(IntEnum):
BLACK = 0
BLUE = 1
RED = 2
@dataclass
class Pen(J):
color: Color
price: Decimal
produced_at: datetime
@dataclass
class Box(J):
pens: List[Pen]
box = Box(pens=[Pen(color=Color.BLUE, price=Decimal("20.1"), produced_at=datetime.now())])
# Encode to a jsonable dictionary.
d = box.json()
print(d) # {'pens': [{'color': 1, 'price': '20.1', 'produced_at': 1660023062}]}
# Construct dataclass from a jsonable dictionary.
print(Box.from_json(d))
```
APIs are only the two: `.json()` and `.from_json()`.
## Built-in Supported Types
* `bool`, `int`, `float`, `str`, `None` encoded as it is.
```python
@dataclass
class Obj(J):
a: int
b: str
c: bool
d: None
Obj(a=1, b="b", c=True, d=None).json()
# => {'a': 1, 'b': 'b', 'c': True, 'd': None}
```
* `Decimal` encoded to `str`.
```python
@dataclass
class Obj(J):
a: Decimal
Obj(a=Decimal("3.1")).json() # => {'a': '3.1'}
```
* `datetime` encoded to timestamp integer via `.timestamp()` method.
`timedelta` encoded to integer via `.total_seconds()` method.
```python
@dataclass
class Obj(J):
a: datetime
b: timedelta
Obj(a=datetime.now(), b=timedelta(minutes=1)).json()
# => {'a': 1660062019, 'b': 60}
```
* `Enum` and `IntEnum` encoded to their values via `.value` attribute.
```python
@dataclass
class Obj(J):
status: Status
Obj(status=Status.DONE).json() # => {'status': 1}
```
* `Any` is encoded according to its `type`.
```python
@dataclass
class Obj(J):
a: Any
Obj(1).json() # {'a': 1}
Obj("a").json() # {'a': 'a'}
Obj.from_json({"a": 1}) # Obj(a=1)
```
* `Optional[X]` is supported, but `Union[X, Y, ...]` is not.
```python
@dataclass
class Obj(J):
a: Optional[int] = None
Obj(a=1).json() # => {'a': 1}
```
* `List[X]`, `Tuple[X]`, `Set[X]` are all encoded to `list`.
```python
@dataclass
class Obj(J):
a: List[int]
b: Set[int]
c: Tuple[int, str]
d: Tuple[int, ...]
Obj(a=[1], b={2, 3}, c=(4, "5"), d=(7, 8, 9)).json())
# => {'a': [1], 'b': [2, 3], 'c': [4, '5'], 'd': [7, 8, 9]}
Obj.from_json({"a": [1], "b": [2, 3], "c": [4, "5"], "d": [7, 8, 9]}))
# => Obj(a=[1], b={2, 3}, c=(4, '5'), d=(7, 8, 9))
```
* `Dict[str, X]` encoded to `dict`.
```python
@dataclass
class Obj(J):
a: Dict[str, int]
Obj(a={"x": 1}).json() # => {'a': {'x': 1}}
Obj.from_json({"a": {"x": 1}}) # => Obj(a={'x': 1})
```
* Nested or recursively `JSONAble` (or `J`) dataclasses.
```python
@dataclass
class Elem(J):
k: str
@dataclass
class Obj(J):
a: List[Elem]
Obj([Elem("v")]).json() # => {'a': [{'k': 'v'}]}
Obj.from_json({"a": [{"k": "v"}]}) # Obj(a=[Elem(k='v')])
```
* Postponed annotations (the `ForwardRef` in [PEP 563](https://www.python.org/dev/peps/pep-0563/)).
```python
@dataclass
class Node(J):
name: str
left: Optional["Node"] = None
right: Optional["Node"] = None
root = Node("root", left=Node("left"), right=Node("right"))
root.json()
# {'name': 'root', 'left': {'name': 'left', 'left': None, 'right': None}, 'right': {'name': 'right', 'left': None, 'right': None}}
```
If these built-in default conversion behaviors do not meet your needs,
or your type is not on the list,
you can use [json_options](#customization--overriding-examples) introduced below to customize it.
## Customization / Overriding Examples
We can override the default conversion behaviors with `json_options`,
which uses the dataclass field's metadata for field-level customization purpose,
and the namespace is `j`.
The following pseudo code gives the pattern:
```python
from dataclasses import field
from dataclass_jsonable import json_options
@dataclass
class Struct(J):
attr: T = field(metadata={"j": json_options(**kwds)})
```
An example list about `json_options`:
* Specific a custom dictionary key over the default field's name:
```python
@dataclass
class Person(J):
attr: str = field(metadata={"j": json_options(name="new_attr")})
Person(attr="value").json() # => {"new_attr": "value"}
```
And more, we can use a function to specific a custom dictionary key.
This may be convenient to work with class-level `__default_json_options__` attribute (check it below).
```python
@dataclass
class Obj(J):
simple_value: int = field(metadata={"j": json_options(name_converter=to_camel_case)})
Obj(simple_value=1).json() # => {"simpleValue": 1}
```
And we may specific a custom field name converter when converts dictionary to dataclass:
```python
@dataclass
def Person(J):
name: str = field(
metadata={
"j": json_options(
name_converter=lambda x: x.capitalize(),
name_inverter=lambda x: "nickname",
)
}
)
```
As the `Person` defined above, it will convert to dictionary like `{"Name": "Jack"}` and can be loaded from `{"nickname": "Jack"}`.
* Omit a field if its value is empty:
```python
@dataclass
class Book(J):
name: str = field(metadata={"j": json_options(omitempty=True)})
Book(name="").json() # => {}
```
Further, we can specify what is 'empty' via option `omitempty_tester`:
```python
@dataclass
class Book(J):
attr: Optional[str] = field(
default=None,
metadata={
# By default, we test `empty` using `not x`.
"j": json_options(omitempty=True, omitempty_tester=lambda x: x is None)
},
)
Book(attr="").json() # => {'attr': ''}
Book(attr=None).json() # => {}
```
* Always skip a field. So we can stop some "private" fields from exporting:
```python
@dataclass
class Obj(J):
attr: str = field(metadata={"j": json_options(skip=True)})
Obj(attr="private").json() # => {}
```
* Always keep a field without encoding nor decoding, this prevents the default encoding/decoding behavior:
```python
@dataclass
class Obj(J):
timestamp: datetime = field(metadata={"j": json_options(keep=True)})
Obj(timestamp=datetime.now()).json() # => {'timestamp': datetime.datetime(2023, 9, 5, 14, 54, 24, 679103)}
```
* dataclasses's `field` allows us to pass a `default` or `default_factory` argument to
set a default value:
```python
@dataclass
class Obj(J):
attr: List[str] = field(default_factory=list, metadata={"j": json_options(**kwds)})
```
There's also an option `default_before_decoding` in dataclass-jsonable,
which specifics a default value before decoding if the key is missing in the dictionary.
Sometimes this way is more concise:
```python
@dataclass
class Obj(J):
updated_at: datetime = field(metadata={"j": json_options(default_before_decoding=0)})
Obj.from_json({}) # => Obj(updated_at=datetime.datetime(1970, 1, 1, 8, 0))
```
dataclass-jsonable also introduces a class-level similar option `__default_factory__`.
If a field has no `default` or `default_factory` declared, and has no `default_before_decoding` option used,
this function will generate a default value according to its type, to prevent a
"missing positional arguments" TypeError from raising.
```python
from dataclass_jsonable import J, zero
@dataclass
class Obj(J):
__default_factory__ = zero
n: int
s: str
k: List[str]
Obj.from_json({}) # => Obj(n=0, s='', k=[])
```
* Override the default encoders and decoders.
This way, you have complete control over how to encode and decode at field level.
```python
@dataclass
class Obj(J):
elems: List[str] = field(
metadata={
"j": json_options(
encoder=lambda x: ",".join(x),
decoder=lambda x: x.split(","),
)
}
)
Obj(elems=["a", "b", "c"]).json() # => {'elems': 'a,b,c'}
Obj.from_json({"elems": "a,b,c"}) # => Obj(elems=['a', 'b', 'c'])
```
The following code snippet about `datetime` is a very common example,
you might want ISO format datetime conversion over timestamp integers.
```python
@dataclass
class Record(J):
created_at: datetime = field(
default_factory=datetime.now,
metadata={
"j": json_options(
encoder=datetime.isoformat,
decoder=datetime.fromisoformat,
)
},
)
Record().json() # => {'created_at': '2022-08-09T23:23:02.543007'}
```
dataclass-jsonable gives `encoder` and `decoder` better alias names since 0.1.1:
`to_json` and `from_json`.
```python
@dataclass
class Obj(J):
elems: List[str] = field(
metadata={
"j": json_options(
to_json=lambda x: ",".join(x), # Alias for encoder
from_json=lambda x: x.split(","), # Alias for decoder
)
}
)
Obj(elems=["a", "b", "c"]).json() # => {'elems': 'a,b,c'}
Obj.from_json({"elems": "a,b,c"}) # => Obj(elems=['a', 'b', 'c'])
```
* For some very narrow scenarios, we may need to execute a hook function before decoding,
for example, the data to be decoded is a serialized json string,
and but we still want to use the built-in decoder functions instead of making a new decoder.
```python
import json
@dataclass
class Obj(J):
data: Dict[str, Any] = field(metadata={"j": json_options(before_decoder=json.loads)})
Obj.from_json({"data": '{"k": "v"}'})
# => Obj(data={'k': 'v'})
```
* Customize default behaviors at the class level.
If an option is not explicitly set at the field level,
the `__default_json_options__` provided at the class level will be attempted.
````python
@dataclass
class Obj(J):
__default_json_options__ = json_options(omitempty=True)
a: Optional[int] = None
b: Optional[str] = None
Obj(b="b").json() # => {'b': 'b'}
````
```python
@dataclass
class Obj(J):
__default_json_options__ = json_options(name_converter=to_camel_case)
status_code: int
simple_value: str
Obj2(status_code=1, simple_value="simple").json()
# => {"statusCode": 1, "simpleValue": "simple"}
```
## Debuging
It provides a method `obj._get_origin_json()`,
it returns the original json dictionary which constructs instance `obj` via `from_json()`.
```python
d = {"a": 1}
obj = Obj.from_json(d)
obj._get_origin_json()
# => {"a": 1}
```
## License
BSD.
Raw data
{
"_id": null,
"home_page": "https://github.com/hit9/dataclass-jsonable",
"name": "dataclass-jsonable",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "dataclasses,json,jsonable",
"author": "hit9",
"author_email": "hit9@icloud.com",
"download_url": "https://files.pythonhosted.org/packages/91/13/ebace88a4f9cdead6e8489641ac188242a55da0e8673d877e41ec92809c3/dataclass-jsonable-0.1.3.tar.gz",
"platform": null,
"description": "# dataclass-jsonable\n\n[![dataclass-jsonable ci](https://github.com/hit9/dataclass-jsonable/actions/workflows/ci.yml/badge.svg)](https://github.com/hit9/dataclass-jsonable/actions/workflows/ci.yml)\n![](https://img.shields.io/badge/license-BSD3-brightgreen)\n\n[\u4e2d\u6587\u8bf4\u660e](README.zh.md)\n\nSimple and flexible conversions between dataclasses and jsonable dictionaries.\n\nIt maps dataclasses to jsonable dictionaries but not json strings.\n\n\n## Features\n\n* Easy to use.\n* Supports common type annotations.\n* Supports recursive conversions.\n* Supports field-level and dataclass-level overriding.\n\n## Installation\n\nRequirements: Python >= 3.7\n\nInstall via `pip`:\n\n```\npip install dataclass-jsonable\n```\n\n## Quick Example\n\n```python\nfrom dataclasses import dataclass\nfrom datetime import datetime\nfrom decimal import Decimal\nfrom enum import IntEnum\nfrom typing import List\nfrom dataclass_jsonable import J\n\nclass Color(IntEnum):\n BLACK = 0\n BLUE = 1\n RED = 2\n\n@dataclass\nclass Pen(J):\n color: Color\n price: Decimal\n produced_at: datetime\n\n@dataclass\nclass Box(J):\n pens: List[Pen]\n\nbox = Box(pens=[Pen(color=Color.BLUE, price=Decimal(\"20.1\"), produced_at=datetime.now())])\n\n# Encode to a jsonable dictionary.\nd = box.json()\nprint(d) # {'pens': [{'color': 1, 'price': '20.1', 'produced_at': 1660023062}]}\n\n# Construct dataclass from a jsonable dictionary.\nprint(Box.from_json(d))\n```\n\nAPIs are only the two: `.json()` and `.from_json()`.\n\n## Built-in Supported Types\n\n* `bool`, `int`, `float`, `str`, `None` encoded as it is.\n\n ```python\n @dataclass\n class Obj(J):\n a: int\n b: str\n c: bool\n d: None\n\n Obj(a=1, b=\"b\", c=True, d=None).json()\n # => {'a': 1, 'b': 'b', 'c': True, 'd': None}\n ```\n\n* `Decimal` encoded to `str`.\n\n ```python\n @dataclass\n class Obj(J):\n a: Decimal\n\n Obj(a=Decimal(\"3.1\")).json() # => {'a': '3.1'}\n ```\n\n* `datetime` encoded to timestamp integer via `.timestamp()` method.\n `timedelta` encoded to integer via `.total_seconds()` method.\n\n ```python\n @dataclass\n class Obj(J):\n a: datetime\n b: timedelta\n\n Obj(a=datetime.now(), b=timedelta(minutes=1)).json()\n # => {'a': 1660062019, 'b': 60}\n ```\n\n* `Enum` and `IntEnum` encoded to their values via `.value` attribute.\n\n ```python\n @dataclass\n class Obj(J):\n status: Status\n\n Obj(status=Status.DONE).json() # => {'status': 1}\n ```\n\n* `Any` is encoded according to its `type`.\n\n ```python\n @dataclass\n class Obj(J):\n a: Any\n\n Obj(1).json() # {'a': 1}\n Obj(\"a\").json() # {'a': 'a'}\n Obj.from_json({\"a\": 1}) # Obj(a=1)\n ```\n\n* `Optional[X]` is supported, but `Union[X, Y, ...]` is not.\n\n ```python\n @dataclass\n class Obj(J):\n a: Optional[int] = None\n\n Obj(a=1).json() # => {'a': 1}\n ```\n\n* `List[X]`, `Tuple[X]`, `Set[X]` are all encoded to `list`.\n\n ```python\n @dataclass\n class Obj(J):\n a: List[int]\n b: Set[int]\n c: Tuple[int, str]\n d: Tuple[int, ...]\n\n Obj(a=[1], b={2, 3}, c=(4, \"5\"), d=(7, 8, 9)).json())\n # => {'a': [1], 'b': [2, 3], 'c': [4, '5'], 'd': [7, 8, 9]}\n\n Obj.from_json({\"a\": [1], \"b\": [2, 3], \"c\": [4, \"5\"], \"d\": [7, 8, 9]}))\n # => Obj(a=[1], b={2, 3}, c=(4, '5'), d=(7, 8, 9))\n ```\n\n* `Dict[str, X]` encoded to `dict`.\n\n ```python\n @dataclass\n class Obj(J):\n a: Dict[str, int]\n Obj(a={\"x\": 1}).json() # => {'a': {'x': 1}}\n Obj.from_json({\"a\": {\"x\": 1}}) # => Obj(a={'x': 1})\n ```\n\n* Nested or recursively `JSONAble` (or `J`) dataclasses.\n\n ```python\n @dataclass\n class Elem(J):\n k: str\n\n @dataclass\n class Obj(J):\n a: List[Elem]\n\n Obj([Elem(\"v\")]).json() # => {'a': [{'k': 'v'}]}\n Obj.from_json({\"a\": [{\"k\": \"v\"}]}) # Obj(a=[Elem(k='v')])\n ```\n\n* Postponed annotations (the `ForwardRef` in [PEP 563](https://www.python.org/dev/peps/pep-0563/)).\n\n ```python\n @dataclass\n class Node(J):\n name: str\n left: Optional[\"Node\"] = None\n right: Optional[\"Node\"] = None\n\n root = Node(\"root\", left=Node(\"left\"), right=Node(\"right\"))\n root.json()\n # {'name': 'root', 'left': {'name': 'left', 'left': None, 'right': None}, 'right': {'name': 'right', 'left': None, 'right': None}}\n ```\n\nIf these built-in default conversion behaviors do not meet your needs,\nor your type is not on the list,\nyou can use [json_options](#customization--overriding-examples) introduced below to customize it.\n\n## Customization / Overriding Examples\n\nWe can override the default conversion behaviors with `json_options`,\nwhich uses the dataclass field's metadata for field-level customization purpose,\nand the namespace is `j`.\n\nThe following pseudo code gives the pattern:\n\n```python\nfrom dataclasses import field\nfrom dataclass_jsonable import json_options\n\n@dataclass\nclass Struct(J):\n attr: T = field(metadata={\"j\": json_options(**kwds)})\n```\n\nAn example list about `json_options`:\n\n* Specific a custom dictionary key over the default field's name:\n\n ```python\n @dataclass\n class Person(J):\n attr: str = field(metadata={\"j\": json_options(name=\"new_attr\")})\n Person(attr=\"value\").json() # => {\"new_attr\": \"value\"}\n ```\n\n And more, we can use a function to specific a custom dictionary key.\n This may be convenient to work with class-level `__default_json_options__` attribute (check it below).\n\n ```python\n @dataclass\n class Obj(J):\n simple_value: int = field(metadata={\"j\": json_options(name_converter=to_camel_case)})\n Obj(simple_value=1).json() # => {\"simpleValue\": 1}\n ```\n\n And we may specific a custom field name converter when converts dictionary to dataclass:\n\n ```python\n @dataclass\n def Person(J):\n name: str = field(\n metadata={\n \"j\": json_options(\n name_converter=lambda x: x.capitalize(),\n name_inverter=lambda x: \"nickname\",\n )\n }\n )\n ```\n\n As the `Person` defined above, it will convert to dictionary like `{\"Name\": \"Jack\"}` and can be loaded from `{\"nickname\": \"Jack\"}`.\n\n* Omit a field if its value is empty:\n\n ```python\n @dataclass\n class Book(J):\n name: str = field(metadata={\"j\": json_options(omitempty=True)})\n Book(name=\"\").json() # => {}\n ```\n\n Further, we can specify what is 'empty' via option `omitempty_tester`:\n\n ```python\n @dataclass\n class Book(J):\n attr: Optional[str] = field(\n default=None,\n metadata={\n # By default, we test `empty` using `not x`.\n \"j\": json_options(omitempty=True, omitempty_tester=lambda x: x is None)\n },\n )\n\n Book(attr=\"\").json() # => {'attr': ''}\n Book(attr=None).json() # => {}\n ```\n\n* Always skip a field. So we can stop some \"private\" fields from exporting:\n\n ```python\n @dataclass\n class Obj(J):\n attr: str = field(metadata={\"j\": json_options(skip=True)})\n\n Obj(attr=\"private\").json() # => {}\n ```\n\n* Always keep a field without encoding nor decoding, this prevents the default encoding/decoding behavior:\n\n ```python\n @dataclass\n class Obj(J):\n timestamp: datetime = field(metadata={\"j\": json_options(keep=True)})\n\n Obj(timestamp=datetime.now()).json() # => {'timestamp': datetime.datetime(2023, 9, 5, 14, 54, 24, 679103)}\n ```\n\n* dataclasses's `field` allows us to pass a `default` or `default_factory` argument to\n set a default value:\n\n ```python\n @dataclass\n class Obj(J):\n attr: List[str] = field(default_factory=list, metadata={\"j\": json_options(**kwds)})\n ```\n\n There's also an option `default_before_decoding` in dataclass-jsonable,\n which specifics a default value before decoding if the key is missing in the dictionary.\n Sometimes this way is more concise:\n\n ```python\n @dataclass\n class Obj(J):\n updated_at: datetime = field(metadata={\"j\": json_options(default_before_decoding=0)})\n\n Obj.from_json({}) # => Obj(updated_at=datetime.datetime(1970, 1, 1, 8, 0))\n ```\n\n dataclass-jsonable also introduces a class-level similar option `__default_factory__`.\n If a field has no `default` or `default_factory` declared, and has no `default_before_decoding` option used,\n this function will generate a default value according to its type, to prevent a\n \"missing positional arguments\" TypeError from raising.\n\n ```python\n from dataclass_jsonable import J, zero\n\n @dataclass\n class Obj(J):\n __default_factory__ = zero\n\n n: int\n s: str\n k: List[str]\n\n Obj.from_json({}) # => Obj(n=0, s='', k=[])\n ```\n\n* Override the default encoders and decoders.\n\n This way, you have complete control over how to encode and decode at field level.\n\n ```python\n @dataclass\n class Obj(J):\n elems: List[str] = field(\n metadata={\n \"j\": json_options(\n encoder=lambda x: \",\".join(x),\n decoder=lambda x: x.split(\",\"),\n )\n }\n )\n\n Obj(elems=[\"a\", \"b\", \"c\"]).json() # => {'elems': 'a,b,c'}\n Obj.from_json({\"elems\": \"a,b,c\"}) # => Obj(elems=['a', 'b', 'c'])\n ```\n\n The following code snippet about `datetime` is a very common example,\n you might want ISO format datetime conversion over timestamp integers.\n\n ```python\n @dataclass\n class Record(J):\n created_at: datetime = field(\n default_factory=datetime.now,\n metadata={\n \"j\": json_options(\n encoder=datetime.isoformat,\n decoder=datetime.fromisoformat,\n )\n },\n )\n\n Record().json() # => {'created_at': '2022-08-09T23:23:02.543007'}\n ```\n\n dataclass-jsonable gives `encoder` and `decoder` better alias names since 0.1.1:\n `to_json` and `from_json`.\n\n ```python\n @dataclass\n class Obj(J):\n elems: List[str] = field(\n metadata={\n \"j\": json_options(\n to_json=lambda x: \",\".join(x), # Alias for encoder\n from_json=lambda x: x.split(\",\"), # Alias for decoder\n )\n }\n )\n\n Obj(elems=[\"a\", \"b\", \"c\"]).json() # => {'elems': 'a,b,c'}\n Obj.from_json({\"elems\": \"a,b,c\"}) # => Obj(elems=['a', 'b', 'c'])\n ```\n\n* For some very narrow scenarios, we may need to execute a hook function before decoding,\n for example, the data to be decoded is a serialized json string,\n and but we still want to use the built-in decoder functions instead of making a new decoder.\n\n ```python\n import json\n\n @dataclass\n class Obj(J):\n data: Dict[str, Any] = field(metadata={\"j\": json_options(before_decoder=json.loads)})\n\n Obj.from_json({\"data\": '{\"k\": \"v\"}'})\n # => Obj(data={'k': 'v'})\n ```\n\n* Customize default behaviors at the class level.\n\n If an option is not explicitly set at the field level,\n the `__default_json_options__` provided at the class level will be attempted.\n\n ````python\n @dataclass\n class Obj(J):\n __default_json_options__ = json_options(omitempty=True)\n\n a: Optional[int] = None\n b: Optional[str] = None\n\n Obj(b=\"b\").json() # => {'b': 'b'}\n ````\n\n ```python\n @dataclass\n class Obj(J):\n __default_json_options__ = json_options(name_converter=to_camel_case)\n\n status_code: int\n simple_value: str\n\n Obj2(status_code=1, simple_value=\"simple\").json()\n # => {\"statusCode\": 1, \"simpleValue\": \"simple\"}\n ```\n\n## Debuging\n\nIt provides a method `obj._get_origin_json()`,\nit returns the original json dictionary which constructs instance `obj` via `from_json()`.\n\n```python\nd = {\"a\": 1}\nobj = Obj.from_json(d)\nobj._get_origin_json()\n# => {\"a\": 1}\n```\n\n## License\n\nBSD.\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "Simple and flexible conversions between dataclasses and jsonable dictionaries.",
"version": "0.1.3",
"project_urls": {
"Homepage": "https://github.com/hit9/dataclass-jsonable"
},
"split_keywords": [
"dataclasses",
"json",
"jsonable"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9113ebace88a4f9cdead6e8489641ac188242a55da0e8673d877e41ec92809c3",
"md5": "37ea794d2e741d718ae9782cb6750b99",
"sha256": "6bcfa8f31bb06b847cfe007ddf0c976d220c36bc28fe47660ee71a673b90347c"
},
"downloads": -1,
"filename": "dataclass-jsonable-0.1.3.tar.gz",
"has_sig": false,
"md5_digest": "37ea794d2e741d718ae9782cb6750b99",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 11639,
"upload_time": "2023-09-06T06:11:08",
"upload_time_iso_8601": "2023-09-06T06:11:08.234972Z",
"url": "https://files.pythonhosted.org/packages/91/13/ebace88a4f9cdead6e8489641ac188242a55da0e8673d877e41ec92809c3/dataclass-jsonable-0.1.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-09-06 06:11:08",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "hit9",
"github_project": "dataclass-jsonable",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "dataclass-jsonable"
}