File: cyclic_or_recursive_dataclasses.rst

package info (click to toggle)
dataclass-wizard 0.35.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,808 kB
  • sloc: python: 15,276; makefile: 111; javascript: 23
file content (110 lines) | stat: -rw-r--r-- 3,334 bytes parent folder | download
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