File: skip_inheritance.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 (81 lines) | stat: -rw-r--r-- 3,180 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
Skip the Class Inheritance
--------------------------

It is important to note that the main purpose of sub-classing from
``JSONWizard`` Mixin class is to provide helper methods like :meth:`from_dict`
and :meth:`to_dict`, which makes it much more convenient and easier to load or
dump your data class from and to JSON.

That is, it's meant to *complement* the usage of the ``dataclass`` decorator,
rather than to serve as a drop-in replacement for data classes, or to provide type
validation for example; there are already excellent libraries like `pydantic`_ that
provide these features if so desired.

However, there may be use cases where we prefer to do away with the class
inheritance model introduced by the Mixin class. In the interests of convenience
and also so that data classes can be used *as is*, the Dataclass
Wizard library provides the helper functions :func:`fromlist` and :func:`fromdict`
for de-serialization, and :func:`asdict` for serialization. These functions also
work recursively, so there is full support for nested dataclasses -- just as with
the class inheritance approach.

Here is an example to demonstrate the usage of these helper functions:

.. code:: python3

    from dataclasses import dataclass
    from datetime import datetime
    from typing import Optional, Union

    from dataclass_wizard import fromdict, asdict, DumpMeta


    @dataclass
    class Container:
        id: int
        created_at: datetime
        my_elements: list['MyElement']


    @dataclass
    class MyElement:
        order_index: Optional[int]
        status_code: Union[int, str]


    source_dict = {'id': '123',
                   'createdAt': '2021-01-01 05:00:00Z',
                   'myElements': [
                       {'orderIndex': 111, 'statusCode': '200'},
                       {'order_index': '222', 'status_code': 404}
                   ]}

    # De-serialize the JSON dictionary object into a `Container` instance.
    c = fromdict(Container, source_dict)

    print(repr(c))
    # prints:
    #   Container(id=123, created_at=datetime.datetime(2021, 1, 1, 5, 0), my_elements=[MyElement(order_index=111, status_code='200'), MyElement(order_index=222, status_code=404)])

    # (Optional) Set up dump config for the inner class, as unfortunately there's
    # no option currently to have the meta config apply in a recursive fashion.
    _ = DumpMeta(MyElement, key_transform='SNAKE')

    # Serialize the `Container` instance to a Python dict object with a custom
    # dump config, for example one which converts field names to snake case.
    json_dict = asdict(c, DumpMeta(Container,
                                   key_transform='SNAKE',
                                   marshal_date_time_as='TIMESTAMP'))

    expected_dict = {'id': 123,
                     'created_at': 1609477200,
                     'my_elements': [
                         {'order_index': 111, 'status_code': '200'},
                         {'order_index': 222, 'status_code': 404}
                     ]}

    # Assert that we get the expected dictionary object.
    assert json_dict == expected_dict


.. _`pydantic`: https://pydantic-docs.helpmanual.io/