V1: Recursive Types and Dataclasses with Cyclic References - rnag/dataclass-wizard GitHub Wiki
Starting with version 0.34.0, recursive types are supported out of the box (OOTB) with the v1
opt-in, eliminating the need for Meta
settings like recursive_classes = True
.
This makes working with recursive dataclasses even easier and more streamlined. In addition, recursive types are now supported for the following Python type constructs:
- NamedTuple
- TypedDict
- Union
- Literal
- Nested dataclasses
- Type aliases (introduced in Python 3.12+)
Example Usage
Recursive types allow handling complex nested data structures, such as deeply nested JSON objects or lists. With v0.34.0
of Dataclass Wizard, de/serializing these structures becomes seamless and more intuitive.
Union
Recursive First, define the Type Alias JSON
.
Python 3.9
For Python 3.9, use this Union
approach:
from typing_extensions import TypeAlias
JSON: TypeAlias = 'str | int | float | bool | dict[str, JSON] | list[JSON] | None'
Python 3.10 and 3.11
For Python 3.10 and above, use this simpler approach:
JSON = str | int | float | bool | dict[str, 'JSON'] | list['JSON'] | None
Python 3.12+
For Python 3.12+, you can use the type
statement:
type JSON = str | int | float | bool | dict[str, JSON] | list[JSON] | None
Usage
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class MyTestClass(JSONWizard):
class _(JSONWizard.Meta):
v1 = True
name: str
meta: str
msg: JSON
x = MyTestClass.from_dict(
{
"name": "name",
"meta": "meta",
"msg": [{"x": {"x": [{"x": ["x", 1, 1.0, True, None]}]}}],
}
)
assert x == MyTestClass(
name="name",
meta="meta",
msg=[{"x": {"x": [{"x": ["x", 1, 1.0, True, None]}]}}],
)
[!NOTE] The
type
statement in Python 3.12+ simplifies type alias definitions by avoiding string annotations for recursive references.
Union
with Nested dataclasses
Recursive from dataclasses import dataclass, field
from dataclass_wizard import JSONWizard
@dataclass
class A(JSONWizard):
class _(JSONWizard.Meta):
v1 = True
value: int
nested: 'B'
next: 'A | None' = None
@dataclass
class B:
items: list[A] = field(default_factory=list)
x = A.from_dict(
{
"value": 1,
"next": {"value": 2, "next": None, "nested": {}},
"nested": {"items": [{"value": 3, "nested": {}}]},
}
)
assert x == A(
value=1,
next=A(value=2, next=None, nested=B(items=[])),
nested=B(items=[A(value=3, nested=B())]),
)
[!NOTE] Nested
dataclasses
are particularly useful for representing hierarchical structures, such as trees or graphs, in a readable and maintainable way.