1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
Cyclic or "Recursive" Dataclasses
=================================
.. note::
**Important:** The current functionality for cyclic or "recursive" dataclasses is being re-imagined.
Please refer to the new docs for **V1 Opt-in** features, which introduces enhanced support for these use
cases. For more details, see the `Field Guide to V1 Opt‐in`_ and the `Recursive Types and Dataclasses with Cyclic References in V1`_ documentation.
This change is part of the ongoing improvements in version ``v0.34.0+``, and the old functionality will no longer be maintained in future releases.
.. _Field Guide to V1 Opt‐in: https://github.com/rnag/dataclass-wizard/wiki/Field-Guide-to-V1-Opt%E2%80%90in
.. _Recursive Types and Dataclasses with Cyclic References in V1: https://github.com/rnag/dataclass-wizard/wiki/V1:-Recursive-Types-and-Dataclasses-with-Cyclic-References
Prior to version ``v0.27.0``, dataclasses with cyclic references
or self-referential structures were not supported. This
limitation is shown in the following toy example:
.. code:: python3
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class A(JSONWizard):
a: 'A | None' = None
a = A.from_dict({'a': {'a': {'a': None}}})
assert a == A(a=A(a=A(a=None)))
This has been a `longstanding issue`_.
New in ``v0.27.0``: The Dataclass Wizard now extends its support
to cyclic and self-referential dataclass models.
The example below demonstrates recursive dataclasses with cyclic
dependencies, following the pattern ``A -> B -> A -> B``.
With Class Inheritance
**********************
Here’s a basic example demonstrating the use of recursive dataclasses
with cyclic dependencies, using a class inheritance model and
the :class:`JSONWizard` mixin:
.. code:: python3
from __future__ import annotations # This can be removed in Python 3.10+
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class A(JSONWizard):
class _(JSONWizard.Meta):
# enable support for self-referential / recursive dataclasses
recursive_classes = True
b: 'B | None' = None
@dataclass
class B:
a: A | None = None
# confirm that `from_dict` with a recursive, self-referential
# input `dict` works as expected.
a = A.from_dict({'b': {'a': {'b': {'a': None}}}})
assert a == A(b=B(a=A(b=B())))
Without Class Inheritance
*************************
Here is the same example as above, but with relying solely on ``dataclasses``, without
using any special class inheritance model:
.. code:: python3
from __future__ import annotations # This can be removed in Python 3.10+
from dataclasses import dataclass
from dataclass_wizard import fromdict, LoadMeta
@dataclass
class A:
b: 'B | None' = None
@dataclass
class B:
a: A | None = None
# enable support for self-referential / recursive dataclasses
LoadMeta(recursive_classes=True).bind_to(A)
# confirm that `from_dict` with a recursive, self-referential
# input `dict` works as expected.
a = fromdict(A, {'b': {'a': {'b': {'a': None}}}})
assert a == A(b=B(a=A(b=B())))
.. _longstanding issue: https://github.com/rnag/dataclass-wizard/issues/62
|