Edit on GitHub

serde

pyserde

Yet another serialization library on top of dataclasses, inspired by serde-rs.

pypi pypi GithubActions CodeCov

Guide | API Docs | Examples

Overview

Declare a class with pyserde's @serde decorator.

@serde
class Foo:
    i: int
    s: str
    f: float
    b: bool

You can serialize Foo object into JSON.

>>> to_json(Foo(i=10, s='foo', f=100.0, b=True))
'{"i":10,"s":"foo","f":100.0,"b":true}'

You can deserialize JSON into Foo object.

>>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
Foo(i=10, s='foo', f=100.0, b=True)

Features

Extensions

Contributors ✨

Thanks goes to these wonderful people (emoji key):

yukinarit
yukinarit

πŸ’»
Alexander Miskaryan
Alexander Miskaryan

πŸ’»
ydylla
ydylla

πŸ’»
Kevin Squire
Kevin Squire

πŸ’» πŸ“–
Yushi OMOTE
Yushi OMOTE

πŸ’»
Yuji Kanagawa
Yuji Kanagawa

πŸ’»
Weiliang Li
Weiliang Li

πŸ’»
Mauve
Mauve

πŸ’»
adsharma
adsharma

πŸ’»
Guilhem C.
Guilhem C.

πŸ“–
Pierre Tardy
Pierre Tardy

πŸ’»
Raphael Nestler
Raphael Nestler

πŸ“–
Pranav V P
Pranav V P

πŸ’»
andreymal
andreymal

πŸ’»
Johann Fuechsl
Johann Fuechsl

πŸ’»
DoeringChristian
DoeringChristian

πŸ’»
Stuart Axelbrooke
Stuart Axelbrooke

πŸ’»
Jakub BerΓ‘nek
Jakub BerΓ‘nek

πŸ’»
Fredrik Reinholdsen
Fredrik Reinholdsen

πŸ’»
Bruno Oliveira
Bruno Oliveira

πŸ“–
Kyle Kosic
Kyle Kosic

πŸ’»
Gajo Petrovic
Gajo Petrovic

πŸ“–
m472
m472

πŸ’»
acolley-gel
acolley-gel

πŸ’»
Marc-AndrΓ© Allaire
Marc-AndrΓ© Allaire

πŸ’»
Ganden Schaffner
Ganden Schaffner

πŸ’»
Dave Tapley
Dave Tapley

πŸ’»
Beartama
Beartama

πŸ’»
Rachael Sexton
Rachael Sexton

πŸ’»
Add your contributions

This project follows the all-contributors specification. Contributions of any kind welcome!

LICENSE

This project is licensed under the MIT license.

Modules

The following modules provide the core functionalities of pyserde.

The following modules provide pyserde's (de)serialize APIs.

Other modules

  1"""
  2.. include:: ../README.md
  3
  4## Modules
  5
  6The following modules provide the core functionalities of `pyserde`.
  7* `serde.se`: All about serialization.
  8* `serde.de`: All about deserialization.
  9* `serde.core`: Core module used by `serde.se` and `serde.de` modules.
 10* `serde.compat`: Compatibility layer which handles mostly differences of `typing` module between
 11python versions.
 12
 13The following modules provide pyserde's (de)serialize APIs.
 14* `serde.json`: Serialize and Deserialize in JSON.
 15* `serde.msgpack`: Serialize and Deserialize in MsgPack.
 16* `serde.yaml`: Serialize and Deserialize in YAML.
 17* `serde.toml`: Serialize and Deserialize in TOML.
 18* `serde.pickle`: Serialize and Deserialize in Pickle.
 19
 20Other modules
 21* `serde.inspect`: Prints generated code by pyserde.
 22"""
 23
 24from dataclasses import dataclass
 25from collections.abc import Callable
 26from typing import Optional, overload, Any
 27
 28from typing_extensions import dataclass_transform
 29
 30from .compat import SerdeError, SerdeSkip, T
 31from .core import (
 32    ClassSerializer,
 33    ClassDeserializer,
 34    AdjacentTagging,
 35    coerce,
 36    DefaultTagging,
 37    ExternalTagging,
 38    InternalTagging,
 39    disabled,
 40    strict,
 41    Tagging,
 42    TypeCheck,
 43    Untagged,
 44    field,
 45    init,
 46    logger,
 47    should_impl_dataclass,
 48    add_serializer,
 49    add_deserializer,
 50)
 51from .de import (
 52    DeserializeFunc,
 53    default_deserializer,
 54    deserialize,
 55    from_dict,
 56    from_tuple,
 57    is_deserializable,
 58)
 59from .se import (
 60    SerializeFunc,
 61    asdict,
 62    astuple,
 63    default_serializer,
 64    is_serializable,
 65    serialize,
 66    to_dict,
 67    to_tuple,
 68)
 69
 70__all__ = [
 71    "serde",
 72    "serialize",
 73    "deserialize",
 74    "is_serializable",
 75    "is_deserializable",
 76    "to_dict",
 77    "from_dict",
 78    "to_tuple",
 79    "from_tuple",
 80    "SerdeError",
 81    "SerdeSkip",
 82    "AdjacentTagging",
 83    "ExternalTagging",
 84    "InternalTagging",
 85    "Untagged",
 86    "disabled",
 87    "strict",
 88    "coerce",
 89    "field",
 90    "default_deserializer",
 91    "asdict",
 92    "astuple",
 93    "default_serializer",
 94    "compat",
 95    "core",
 96    "de",
 97    "inspect",
 98    "json",
 99    "msgpack",
100    "numpy",
101    "se",
102    "toml",
103    "pickle",
104    "yaml",
105    "init",
106    "logger",
107    "ClassSerializer",
108    "ClassDeserializer",
109    "add_serializer",
110    "add_deserializer",
111]
112
113
114@overload
115def serde(
116    _cls: type[T],
117    rename_all: Optional[str] = None,
118    reuse_instances_default: bool = True,
119    convert_sets_default: bool = False,
120    serializer: Optional[SerializeFunc] = None,
121    deserializer: Optional[DeserializeFunc] = None,
122    tagging: Tagging = DefaultTagging,
123    type_check: TypeCheck = strict,
124    serialize_class_var: bool = False,
125    class_serializer: Optional[ClassSerializer] = None,
126    class_deserializer: Optional[ClassDeserializer] = None,
127) -> type[T]: ...
128
129
130@overload
131def serde(
132    rename_all: Optional[str] = None,
133    reuse_instances_default: bool = True,
134    convert_sets_default: bool = False,
135    serializer: Optional[SerializeFunc] = None,
136    deserializer: Optional[DeserializeFunc] = None,
137    tagging: Tagging = DefaultTagging,
138    type_check: TypeCheck = strict,
139    serialize_class_var: bool = False,
140    class_serializer: Optional[ClassSerializer] = None,
141    class_deserializer: Optional[ClassDeserializer] = None,
142) -> Callable[[type[T]], type[T]]: ...
143
144
145@dataclass_transform(field_specifiers=(field,))  # type: ignore
146def serde(
147    _cls: Any = None,
148    rename_all: Optional[str] = None,
149    reuse_instances_default: bool = True,
150    convert_sets_default: bool = False,
151    serializer: Optional[SerializeFunc] = None,
152    deserializer: Optional[DeserializeFunc] = None,
153    tagging: Tagging = DefaultTagging,
154    type_check: TypeCheck = strict,
155    serialize_class_var: bool = False,
156    class_serializer: Optional[ClassSerializer] = None,
157    class_deserializer: Optional[ClassDeserializer] = None,
158) -> Any:
159    """
160    serde decorator. Keyword arguments are passed in `serialize` and `deserialize`.
161    """
162
163    def wrap(cls: Any) -> Any:
164        if should_impl_dataclass(cls):
165            dataclass(cls)
166        serialize(
167            cls,
168            rename_all=rename_all,
169            reuse_instances_default=reuse_instances_default,
170            convert_sets_default=convert_sets_default,
171            serializer=serializer,
172            deserializer=deserializer,
173            tagging=tagging,
174            type_check=type_check,
175            serialize_class_var=serialize_class_var,
176            class_serializer=class_serializer,
177        )
178        deserialize(
179            cls,
180            rename_all=rename_all,
181            reuse_instances_default=reuse_instances_default,
182            convert_sets_default=convert_sets_default,
183            serializer=serializer,
184            deserializer=deserializer,
185            tagging=tagging,
186            type_check=type_check,
187            serialize_class_var=serialize_class_var,
188            class_deserializer=class_deserializer,
189        )
190        return cls
191
192    if _cls is None:
193        return wrap
194
195    return wrap(_cls)
@dataclass_transform(field_specifiers=(field,))
def serde( _cls: Any = None, rename_all: Optional[str] = None, reuse_instances_default: bool = True, convert_sets_default: bool = False, serializer: Optional[collections.abc.Callable[[type[Any], Any], Any]] = None, deserializer: Optional[collections.abc.Callable[[type[Any], Any], Any]] = None, tagging: serde.core.Tagging = Tagging(tag=None, content=None, kind=<Kind.External: 1>), type_check: serde.core.TypeCheck = TypeCheck(kind=<Kind.Strict: 3>), serialize_class_var: bool = False, class_serializer: Optional[ClassSerializer] = None, class_deserializer: Optional[ClassDeserializer] = None) -> Any:
146@dataclass_transform(field_specifiers=(field,))  # type: ignore
147def serde(
148    _cls: Any = None,
149    rename_all: Optional[str] = None,
150    reuse_instances_default: bool = True,
151    convert_sets_default: bool = False,
152    serializer: Optional[SerializeFunc] = None,
153    deserializer: Optional[DeserializeFunc] = None,
154    tagging: Tagging = DefaultTagging,
155    type_check: TypeCheck = strict,
156    serialize_class_var: bool = False,
157    class_serializer: Optional[ClassSerializer] = None,
158    class_deserializer: Optional[ClassDeserializer] = None,
159) -> Any:
160    """
161    serde decorator. Keyword arguments are passed in `serialize` and `deserialize`.
162    """
163
164    def wrap(cls: Any) -> Any:
165        if should_impl_dataclass(cls):
166            dataclass(cls)
167        serialize(
168            cls,
169            rename_all=rename_all,
170            reuse_instances_default=reuse_instances_default,
171            convert_sets_default=convert_sets_default,
172            serializer=serializer,
173            deserializer=deserializer,
174            tagging=tagging,
175            type_check=type_check,
176            serialize_class_var=serialize_class_var,
177            class_serializer=class_serializer,
178        )
179        deserialize(
180            cls,
181            rename_all=rename_all,
182            reuse_instances_default=reuse_instances_default,
183            convert_sets_default=convert_sets_default,
184            serializer=serializer,
185            deserializer=deserializer,
186            tagging=tagging,
187            type_check=type_check,
188            serialize_class_var=serialize_class_var,
189            class_deserializer=class_deserializer,
190        )
191        return cls
192
193    if _cls is None:
194        return wrap
195
196    return wrap(_cls)

serde decorator. Keyword arguments are passed in serialize and deserialize.

@dataclass_transform()
def serialize( _cls: Optional[type[~T]] = None, rename_all: Optional[str] = None, reuse_instances_default: bool = False, convert_sets_default: bool = False, serializer: Optional[collections.abc.Callable[[type[Any], Any], Any]] = None, tagging: serde.core.Tagging = Tagging(tag=None, content=None, kind=<Kind.External: 1>), type_check: serde.core.TypeCheck = TypeCheck(kind=<Kind.Strict: 3>), serialize_class_var: bool = False, class_serializer: Optional[ClassSerializer] = None, **kwargs: Any) -> type[~T]:
162@dataclass_transform()
163def serialize(
164    _cls: Optional[type[T]] = None,
165    rename_all: Optional[str] = None,
166    reuse_instances_default: bool = False,
167    convert_sets_default: bool = False,
168    serializer: Optional[SerializeFunc] = None,
169    tagging: Tagging = DefaultTagging,
170    type_check: TypeCheck = strict,
171    serialize_class_var: bool = False,
172    class_serializer: Optional[ClassSerializer] = None,
173    **kwargs: Any,
174) -> type[T]:
175    """
176    A dataclass with this decorator is serializable into any of the data formats
177    supported by pyserde.
178
179    >>> from datetime import datetime
180    >>> from serde import serialize
181    >>> from serde.json import to_json
182    >>>
183    >>> @serialize
184    ... class Foo:
185    ...     i: int
186    ...     s: str
187    ...     f: float
188    ...     b: bool
189    >>>
190    >>> to_json(Foo(i=10, s='foo', f=100.0, b=True))
191    '{"i":10,"s":"foo","f":100.0,"b":true}'
192    """
193
194    def wrap(cls: type[T]) -> type[T]:
195        tagging.check()
196
197        # If no `dataclass` found in the class, dataclassify it automatically.
198        if not is_dataclass(cls):
199            dataclass(cls)
200
201        if type_check.is_strict():
202            serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
203            serde_beartype(cls)
204
205        g: dict[str, Any] = {}
206
207        # Create a scope storage used by serde.
208        # Each class should get own scope. Child classes can not share scope with parent class.
209        # That's why we need the "scope.cls is not cls" check.
210        scope: Optional[Scope] = getattr(cls, SERDE_SCOPE, None)
211        if scope is None or scope.cls is not cls:
212            scope = Scope(
213                cls,
214                reuse_instances_default=reuse_instances_default,
215                convert_sets_default=convert_sets_default,
216            )
217            setattr(cls, SERDE_SCOPE, scope)
218
219        class_serializers: list[ClassSerializer] = list(
220            itertools.chain(GLOBAL_CLASS_SERIALIZER, [class_serializer] if class_serializer else [])
221        )
222
223        # Set some globals for all generated functions
224        g["cls"] = cls
225        g["copy"] = copy
226        g["serde_scope"] = scope
227        g["SerdeError"] = SerdeError
228        g["raise_unsupported_type"] = raise_unsupported_type
229        g["enum_value"] = enum_value
230        g["is_dataclass"] = is_dataclass
231        g["typename"] = typename  # used in union functions
232        g["is_instance"] = is_instance  # used in union functions
233        g["to_obj"] = to_obj
234        g["typing"] = typing
235        g["Literal"] = Literal
236        g["TypeCheck"] = TypeCheck
237        g["disabled"] = disabled
238        g["coerce_object"] = coerce_object
239        g["class_serializers"] = class_serializers
240        if serializer:
241            g["serde_legacy_custom_class_serializer"] = functools.partial(
242                serde_legacy_custom_class_serializer, custom=serializer
243            )
244
245        # Collect types used in the generated code.
246        for typ in iter_types(cls):
247            # When we encounter a dataclass not marked with serialize, then also generate serialize
248            # functions for it.
249            if is_dataclass_without_se(typ):
250                # We call serialize and not wrap to make sure that we will use the default serde
251                # configuration for generating the serialization function.
252                serialize(typ)
253
254            if is_primitive(typ) and not is_enum(typ):
255                continue
256            g[typename(typ)] = typ
257
258        # render all union functions
259        for union in iter_unions(cls):
260            union_args = list(type_args(union))
261            union_key = union_func_name(UNION_SE_PREFIX, union_args)
262            add_func(scope, union_key, render_union_func(cls, union_args, tagging), g)
263            scope.union_se_args[union_key] = union_args
264
265        for f in sefields(cls, serialize_class_var):
266            if f.skip_if:
267                g[f.skip_if.name] = f.skip_if
268            if f.serializer:
269                g[f.serializer.name] = f.serializer
270
271        add_func(
272            scope,
273            TO_ITER,
274            render_to_tuple(cls, serializer, type_check, serialize_class_var, class_serializer),
275            g,
276        )
277        add_func(
278            scope,
279            TO_DICT,
280            render_to_dict(
281                cls, rename_all, serializer, type_check, serialize_class_var, class_serializer
282            ),
283            g,
284        )
285
286        logger.debug(f"{typename(cls)}: {SERDE_SCOPE} {scope}")
287
288        return cls
289
290    if _cls is None:
291        return wrap  # type: ignore
292
293    if _cls in GENERATION_STACK:
294        return _cls
295
296    GENERATION_STACK.append(_cls)
297    try:
298        return wrap(_cls)
299    finally:
300        GENERATION_STACK.pop()

A dataclass with this decorator is serializable into any of the data formats supported by pyserde.

>>> from datetime import datetime
>>> from serde import serialize
>>> from serde.json import to_json
>>>
>>> @serialize
... class Foo:
...     i: int
...     s: str
...     f: float
...     b: bool
>>>
>>> to_json(Foo(i=10, s='foo', f=100.0, b=True))
'{"i":10,"s":"foo","f":100.0,"b":true}'
@dataclass_transform()
def deserialize( _cls: Optional[type[~T]] = None, rename_all: Optional[str] = None, reuse_instances_default: bool = True, convert_sets_default: bool = False, deserializer: Optional[collections.abc.Callable[[type[Any], Any], Any]] = None, tagging: serde.core.Tagging = Tagging(tag=None, content=None, kind=<Kind.External: 1>), type_check: serde.core.TypeCheck = TypeCheck(kind=<Kind.Strict: 3>), class_deserializer: Optional[ClassDeserializer] = None, **kwargs: Any) -> type[~T]:
183@dataclass_transform()
184def deserialize(
185    _cls: Optional[type[T]] = None,
186    rename_all: Optional[str] = None,
187    reuse_instances_default: bool = True,
188    convert_sets_default: bool = False,
189    deserializer: Optional[DeserializeFunc] = None,
190    tagging: Tagging = DefaultTagging,
191    type_check: TypeCheck = strict,
192    class_deserializer: Optional[ClassDeserializer] = None,
193    **kwargs: Any,
194) -> type[T]:
195    """
196    A dataclass with this decorator is deserializable from any of the data formats supported
197    by pyserde.
198
199    >>> from serde import deserialize
200    >>> from serde.json import from_json
201    >>>
202    >>> @deserialize
203    ... class Foo:
204    ...     i: int
205    ...     s: str
206    ...     f: float
207    ...     b: bool
208    >>>
209    >>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
210    Foo(i=10, s='foo', f=100.0, b=True)
211    """
212
213    stack = []
214
215    def wrap(cls: type[T]) -> type[T]:
216        if cls in stack:
217            return cls
218        stack.append(cls)
219
220        tagging.check()
221
222        # If no `dataclass` found in the class, dataclassify it automatically.
223        if not is_dataclass(cls):
224            dataclass(cls)
225
226        if type_check.is_strict():
227            serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
228            serde_beartype(cls)
229
230        g: dict[str, Any] = {}
231
232        # Create a scope storage used by serde.
233        # Each class should get own scope. Child classes can not share scope with parent class.
234        # That's why we need the "scope.cls is not cls" check.
235        scope: Optional[Scope] = getattr(cls, SERDE_SCOPE, None)
236        if scope is None or scope.cls is not cls:
237            scope = Scope(cls, reuse_instances_default=reuse_instances_default)
238            setattr(cls, SERDE_SCOPE, scope)
239
240        class_deserializers: list[ClassDeserializer] = list(
241            itertools.chain(
242                GLOBAL_CLASS_DESERIALIZER, [class_deserializer] if class_deserializer else []
243            )
244        )
245
246        # Set some globals for all generated functions
247        g["cls"] = cls
248        g["serde_scope"] = scope
249        g["SerdeError"] = SerdeError
250        g["UserError"] = UserError
251        g["raise_unsupported_type"] = raise_unsupported_type
252        g["typename"] = typename
253        g["ensure"] = ensure
254        g["typing"] = typing
255        g["collections"] = collections
256        g["Literal"] = Literal
257        g["from_obj"] = from_obj
258        g["get_generic_arg"] = get_generic_arg
259        g["is_instance"] = is_instance
260        g["TypeCheck"] = TypeCheck
261        g["disabled"] = disabled
262        g["coerce_object"] = coerce_object
263        g["_exists_by_aliases"] = _exists_by_aliases
264        g["_get_by_aliases"] = _get_by_aliases
265        g["class_deserializers"] = class_deserializers
266        g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
267        if deserializer:
268            g["serde_legacy_custom_class_deserializer"] = functools.partial(
269                serde_legacy_custom_class_deserializer, custom=deserializer
270            )
271
272        # Collect types used in the generated code.
273        for typ in iter_types(cls):
274            # When we encounter a dataclass not marked with deserialize, then also generate
275            # deserialize functions for it.
276            if is_dataclass_without_de(typ):
277                # We call deserialize and not wrap to make sure that we will use the default serde
278                # configuration for generating the deserialization function.
279                deserialize(typ)
280
281            # We don't want to add primitive class e.g "str" into the scope, but primitive
282            # compatible types such as IntEnum and a subclass of primitives are added,
283            # so that generated code can use those types.
284            if is_primitive(typ) and not is_enum(typ) and not is_primitive_subclass(typ):
285                continue
286
287            if is_generic(typ):
288                g[typename(typ)] = get_origin(typ)
289            else:
290                g[typename(typ)] = typ
291
292        # render all union functions
293        for union in iter_unions(cls):
294            union_args = type_args(union)
295            add_func(
296                scope,
297                union_func_name(UNION_DE_PREFIX, union_args),
298                render_union_func(cls, union_args, tagging),
299                g,
300            )
301
302        # render literal functions
303        for literal in iter_literals(cls):
304            literal_args = type_args(literal)
305            add_func(
306                scope, literal_func_name(literal_args), render_literal_func(cls, literal_args), g
307            )
308
309        # Collect default values and default factories used in the generated code.
310        for f in defields(cls):
311            assert f.name
312            if has_default(f):
313                scope.defaults[f.name] = f.default
314            elif has_default_factory(f):
315                scope.defaults[f.name] = f.default_factory
316            if f.deserializer:
317                g[f.deserializer.name] = f.deserializer
318
319        add_func(
320            scope,
321            FROM_ITER,
322            render_from_iter(cls, deserializer, type_check, class_deserializer=class_deserializer),
323            g,
324        )
325        add_func(
326            scope,
327            FROM_DICT,
328            render_from_dict(
329                cls, rename_all, deserializer, type_check, class_deserializer=class_deserializer
330            ),
331            g,
332        )
333
334        logger.debug(f"{typename(cls)}: {SERDE_SCOPE} {scope}")
335
336        stack.pop()
337        return cls
338
339    if _cls is None:
340        return wrap  # type: ignore
341
342    if _cls in GENERATION_STACK:
343        return _cls
344
345    GENERATION_STACK.append(_cls)
346    try:
347        return wrap(_cls)
348    finally:
349        GENERATION_STACK.pop()

A dataclass with this decorator is deserializable from any of the data formats supported by pyserde.

>>> from serde import deserialize
>>> from serde.json import from_json
>>>
>>> @deserialize
... class Foo:
...     i: int
...     s: str
...     f: float
...     b: bool
>>>
>>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
Foo(i=10, s='foo', f=100.0, b=True)
def is_serializable(instance_or_class: Any) -> bool:
303def is_serializable(instance_or_class: Any) -> bool:
304    """
305    Test if an instance or class is serializable.
306
307    >>> @serialize
308    ... class Foo:
309    ...     pass
310
311    Testing `Foo` class object returns `True`.
312    >>> is_serializable(Foo)
313    True
314
315    Testing `Foo` object also returns `True`.
316    >>> is_serializable(Foo())
317    True
318    """
319    return hasattr(instance_or_class, SERDE_SCOPE)

Test if an instance or class is serializable.

>>> @serialize
... class Foo:
...     pass

Testing Foo class object returns True.

>>> is_serializable(Foo)
True

Testing Foo object also returns True.

>>> is_serializable(Foo())
True
def is_deserializable(instance_or_class: Any) -> bool:
352def is_deserializable(instance_or_class: Any) -> bool:
353    """
354    Test if an instance or class is deserializable.
355
356    >>> @deserialize
357    ... class Foo:
358    ...     pass
359    >>>
360    >>> is_deserializable(Foo)
361    True
362    """
363    return hasattr(instance_or_class, SERDE_SCOPE)

Test if an instance or class is deserializable.

>>> @deserialize
... class Foo:
...     pass
>>>
>>> is_deserializable(Foo)
True
def to_dict( o: Any, c: Optional[type[Any]] = None, reuse_instances: Optional[bool] = None, convert_sets: Optional[bool] = None) -> dict[typing.Any, typing.Any]:
434def to_dict(
435    o: Any,
436    c: Optional[type[Any]] = None,
437    reuse_instances: Optional[bool] = None,
438    convert_sets: Optional[bool] = None,
439) -> dict[Any, Any]:
440    """
441    Serialize object into dictionary.
442
443    >>> @serialize
444    ... class Foo:
445    ...     i: int
446    ...     s: str = 'foo'
447    ...     f: float = 100.0
448    ...     b: bool = True
449    >>>
450    >>> to_dict(Foo(i=10))
451    {'i': 10, 's': 'foo', 'f': 100.0, 'b': True}
452
453    You can pass any type supported by pyserde. For example,
454
455    >>> lst = [Foo(i=10), Foo(i=20)]
456    >>> to_dict(lst)
457    [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True}, {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
458    """
459    return to_obj(  # type: ignore
460        o, named=True, c=c, reuse_instances=reuse_instances, convert_sets=convert_sets
461    )

Serialize object into dictionary.

>>> @serialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> to_dict(Foo(i=10))
{'i': 10, 's': 'foo', 'f': 100.0, 'b': True}

You can pass any type supported by pyserde. For example,

>>> lst = [Foo(i=10), Foo(i=20)]
>>> to_dict(lst)
[{'i': 10, 's': 'foo', 'f': 100.0, 'b': True}, {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
def from_dict( cls: Any, o: dict[str, typing.Any], reuse_instances: Optional[bool] = None) -> Any:
509def from_dict(cls: Any, o: dict[str, Any], reuse_instances: Optional[bool] = None) -> Any:
510    """
511    Deserialize dictionary into object.
512
513    >>> @deserialize
514    ... class Foo:
515    ...     i: int
516    ...     s: str = 'foo'
517    ...     f: float = 100.0
518    ...     b: bool = True
519    >>>
520    >>> from_dict(Foo, {'i': 10, 's': 'foo', 'f': 100.0, 'b': True})
521    Foo(i=10, s='foo', f=100.0, b=True)
522
523    You can pass any type supported by pyserde. For example,
524
525    >>> lst = [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True},
526    ...        {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
527    >>> from_dict(list[Foo], lst)
528    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
529    """
530    return from_obj(cls, o, named=True, reuse_instances=reuse_instances)

Deserialize dictionary into object.

>>> @deserialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> from_dict(Foo, {'i': 10, 's': 'foo', 'f': 100.0, 'b': True})
Foo(i=10, s='foo', f=100.0, b=True)

You can pass any type supported by pyserde. For example,

>>> lst = [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True},
...        {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
>>> from_dict(list[Foo], lst)
[Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
def to_tuple( o: Any, c: Optional[type[Any]] = None, reuse_instances: Optional[bool] = None, convert_sets: Optional[bool] = None) -> tuple[typing.Any, ...]:
397def to_tuple(
398    o: Any,
399    c: Optional[type[Any]] = None,
400    reuse_instances: Optional[bool] = None,
401    convert_sets: Optional[bool] = None,
402) -> tuple[Any, ...]:
403    """
404    Serialize object into tuple.
405
406    >>> @serialize
407    ... class Foo:
408    ...     i: int
409    ...     s: str = 'foo'
410    ...     f: float = 100.0
411    ...     b: bool = True
412    >>>
413    >>> to_tuple(Foo(i=10))
414    (10, 'foo', 100.0, True)
415
416    You can pass any type supported by pyserde. For example,
417
418    >>> lst = [Foo(i=10), Foo(i=20)]
419    >>> to_tuple(lst)
420    [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
421    """
422    return to_obj(  # type: ignore
423        o, named=False, c=c, reuse_instances=reuse_instances, convert_sets=convert_sets
424    )

Serialize object into tuple.

>>> @serialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> to_tuple(Foo(i=10))
(10, 'foo', 100.0, True)

You can pass any type supported by pyserde. For example,

>>> lst = [Foo(i=10), Foo(i=20)]
>>> to_tuple(lst)
[(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any:
541def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any:
542    """
543    Deserialize tuple into object.
544
545    >>> @deserialize
546    ... class Foo:
547    ...     i: int
548    ...     s: str = 'foo'
549    ...     f: float = 100.0
550    ...     b: bool = True
551    >>>
552    >>> from_tuple(Foo, (10, 'foo', 100.0, True))
553    Foo(i=10, s='foo', f=100.0, b=True)
554
555    You can pass any type supported by pyserde. For example,
556
557    >>> lst = [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
558    >>> from_tuple(list[Foo], lst)
559    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
560    """
561    return from_obj(cls, o, named=False, reuse_instances=reuse_instances)

Deserialize tuple into object.

>>> @deserialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> from_tuple(Foo, (10, 'foo', 100.0, True))
Foo(i=10, s='foo', f=100.0, b=True)

You can pass any type supported by pyserde. For example,

>>> lst = [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
>>> from_tuple(list[Foo], lst)
[Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
class SerdeError(builtins.Exception):
74class SerdeError(Exception):
75    """
76    Serde error class.
77    """

Serde error class.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
class SerdeSkip(builtins.Exception):
89class SerdeSkip(Exception):
90    """
91    Skip a field in custom (de)serializer.
92    """

Skip a field in custom (de)serializer.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
add_note
args
def AdjacentTagging( tag: str, content: str, cls: Optional[~T] = None) -> Union[serde.core.Tagging, serde.compat._WithTagging[~T]]:
846def AdjacentTagging(
847    tag: str, content: str, cls: Optional[T] = None
848) -> Union[Tagging, _WithTagging[T]]:
849    tagging = Tagging(tag, content, kind=Tagging.Kind.Adjacent)
850    if cls:
851        return tagging(cls)
852    else:
853        return tagging
ExternalTagging = Tagging(tag=None, content=None, kind=<Kind.External: 1>)
def InternalTagging( tag: str, cls: Optional[~T] = None) -> Union[serde.core.Tagging, serde.compat._WithTagging[~T]]:
830def InternalTagging(tag: str, cls: Optional[T] = None) -> Union[Tagging, _WithTagging[T]]:
831    tagging = Tagging(tag, kind=Tagging.Kind.Internal)
832    if cls:
833        return tagging(cls)
834    else:
835        return tagging
Untagged = Tagging(tag=None, content=None, kind=<Kind.Untagged: 4>)
disabled = TypeCheck(kind=<Kind.Disabled: 1>)
strict = TypeCheck(kind=<Kind.Strict: 3>)
coerce = TypeCheck(kind=<Kind.Coerce: 2>)
def field( *args: Any, rename: Optional[str] = None, alias: Optional[list[str]] = None, skip: Optional[bool] = None, skip_if: Optional[collections.abc.Callable[[Any], Any]] = None, skip_if_false: Optional[bool] = None, skip_if_default: Optional[bool] = None, serializer: Optional[collections.abc.Callable[..., Any]] = None, deserializer: Optional[collections.abc.Callable[..., Any]] = None, flatten: Union[serde.core.FlattenOpts, bool, NoneType] = None, metadata: Optional[dict[str, Any]] = None, **kwargs: Any) -> Any:
512def field(
513    *args: Any,
514    rename: Optional[str] = None,
515    alias: Optional[list[str]] = None,
516    skip: Optional[bool] = None,
517    skip_if: Optional[Callable[[Any], Any]] = None,
518    skip_if_false: Optional[bool] = None,
519    skip_if_default: Optional[bool] = None,
520    serializer: Optional[Callable[..., Any]] = None,
521    deserializer: Optional[Callable[..., Any]] = None,
522    flatten: Optional[Union[FlattenOpts, bool]] = None,
523    metadata: Optional[dict[str, Any]] = None,
524    **kwargs: Any,
525) -> Any:
526    """
527    Declare a field with parameters.
528    """
529    if not metadata:
530        metadata = {}
531
532    if rename is not None:
533        metadata["serde_rename"] = rename
534    if alias is not None:
535        metadata["serde_alias"] = alias
536    if skip is not None:
537        metadata["serde_skip"] = skip
538    if skip_if is not None:
539        metadata["serde_skip_if"] = skip_if
540    if skip_if_false is not None:
541        metadata["serde_skip_if_false"] = skip_if_false
542    if skip_if_default is not None:
543        metadata["serde_skip_if_default"] = skip_if_default
544    if serializer:
545        metadata["serde_serializer"] = serializer
546    if deserializer:
547        metadata["serde_deserializer"] = deserializer
548    if flatten is True:
549        metadata["serde_flatten"] = FlattenOpts()
550    elif flatten:
551        metadata["serde_flatten"] = flatten
552
553    return dataclasses.field(*args, metadata=metadata, **kwargs)

Declare a field with parameters.

def default_deserializer(_cls: type[typing.Any], obj: Any) -> Any:
122def default_deserializer(_cls: type[Any], obj: Any) -> Any:
123    """
124    Marker function to tell serde to use the default deserializer. It's used when custom
125    deserializer is specified at the class but you want to override a field with the default
126    deserializer.
127    """

Marker function to tell serde to use the default deserializer. It's used when custom deserializer is specified at the class but you want to override a field with the default deserializer.

def asdict(v: Any) -> dict[typing.Any, typing.Any]:
427def asdict(v: Any) -> dict[Any, Any]:
428    """
429    Serialize object into dictionary.
430    """
431    return to_dict(v, reuse_instances=False, convert_sets=False)

Serialize object into dictionary.

def astuple(v: Any) -> tuple[typing.Any, ...]:
390def astuple(v: Any) -> tuple[Any, ...]:
391    """
392    Serialize object into tuple.
393    """
394    return to_tuple(v, reuse_instances=False, convert_sets=False)

Serialize object into tuple.

def default_serializer(_cls: type[typing.Any], obj: Any) -> Any:
95def default_serializer(_cls: type[Any], obj: Any) -> Any:
96    """
97    Marker function to tell serde to use the default serializer. It's used when custom serializer
98    is specified at the class but you want to override a field with the default serializer.
99    """

Marker function to tell serde to use the default serializer. It's used when custom serializer is specified at the class but you want to override a field with the default serializer.

def init(debug: bool = False) -> None:
88def init(debug: bool = False) -> None:
89    SETTINGS["debug"] = debug
logger = <Logger serde (WARNING)>
class ClassSerializer(typing.Protocol):
980class ClassSerializer(Protocol):
981    """
982    Interface for custom class serializer.
983
984    This protocol is intended to be used for custom class serializer.
985
986    >>> from datetime import datetime
987    >>> from serde import serde
988    >>> from plum import dispatch
989    >>> class MySerializer(ClassSerializer):
990    ...     @dispatch
991    ...     def serialize(self, value: datetime) -> str:
992    ...         return value.strftime("%d/%m/%y")
993    """
994
995    def serialize(self, value: Any) -> Any:
996        pass

Interface for custom class serializer.

This protocol is intended to be used for custom class serializer.

>>> from datetime import datetime
>>> from serde import serde
>>> from plum import dispatch
>>> class MySerializer(ClassSerializer):
...     @dispatch
...     def serialize(self, value: datetime) -> str:
...         return value.strftime("%d/%m/%y")
ClassSerializer(*args, **kwargs)
1717def _no_init_or_replace_init(self, *args, **kwargs):
1718    cls = type(self)
1719
1720    if cls._is_protocol:
1721        raise TypeError('Protocols cannot be instantiated')
1722
1723    # Already using a custom `__init__`. No need to calculate correct
1724    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1725    if cls.__init__ is not _no_init_or_replace_init:
1726        return
1727
1728    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1729    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1730    # searches for a proper new `__init__` in the MRO. The new `__init__`
1731    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1732    # instantiation of the protocol subclass will thus use the new
1733    # `__init__` and no longer call `_no_init_or_replace_init`.
1734    for base in cls.__mro__:
1735        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1736        if init is not _no_init_or_replace_init:
1737            cls.__init__ = init
1738            break
1739    else:
1740        # should not happen
1741        cls.__init__ = object.__init__
1742
1743    cls.__init__(self, *args, **kwargs)
def serialize(self, value: Any) -> Any:
995    def serialize(self, value: Any) -> Any:
996        pass
class ClassDeserializer(typing.Protocol):
 999class ClassDeserializer(Protocol):
1000    """
1001    Interface for custom class deserializer.
1002
1003    This protocol is intended to be used for custom class deserializer.
1004
1005    >>> from datetime import datetime
1006    >>> from serde import serde
1007    >>> from plum import dispatch
1008    >>> class MyDeserializer(ClassDeserializer):
1009    ...     @dispatch
1010    ...     def deserialize(self, cls: type[datetime], value: Any) -> datetime:
1011    ...         return datetime.strptime(value, "%d/%m/%y")
1012    """
1013
1014    def deserialize(self, cls: Any, value: Any) -> Any:
1015        pass

Interface for custom class deserializer.

This protocol is intended to be used for custom class deserializer.

>>> from datetime import datetime
>>> from serde import serde
>>> from plum import dispatch
>>> class MyDeserializer(ClassDeserializer):
...     @dispatch
...     def deserialize(self, cls: type[datetime], value: Any) -> datetime:
...         return datetime.strptime(value, "%d/%m/%y")
ClassDeserializer(*args, **kwargs)
1717def _no_init_or_replace_init(self, *args, **kwargs):
1718    cls = type(self)
1719
1720    if cls._is_protocol:
1721        raise TypeError('Protocols cannot be instantiated')
1722
1723    # Already using a custom `__init__`. No need to calculate correct
1724    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1725    if cls.__init__ is not _no_init_or_replace_init:
1726        return
1727
1728    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1729    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1730    # searches for a proper new `__init__` in the MRO. The new `__init__`
1731    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1732    # instantiation of the protocol subclass will thus use the new
1733    # `__init__` and no longer call `_no_init_or_replace_init`.
1734    for base in cls.__mro__:
1735        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1736        if init is not _no_init_or_replace_init:
1737            cls.__init__ = init
1738            break
1739    else:
1740        # should not happen
1741        cls.__init__ = object.__init__
1742
1743    cls.__init__(self, *args, **kwargs)
def deserialize(self, cls: Any, value: Any) -> Any:
1014    def deserialize(self, cls: Any, value: Any) -> Any:
1015        pass
def add_serializer(serializer: ClassSerializer) -> None:
1023def add_serializer(serializer: ClassSerializer) -> None:
1024    """
1025    Register custom global serializer.
1026    """
1027    GLOBAL_CLASS_SERIALIZER.append(serializer)

Register custom global serializer.

def add_deserializer(deserializer: ClassDeserializer) -> None:
1030def add_deserializer(deserializer: ClassDeserializer) -> None:
1031    """
1032    Register custom global deserializer.
1033    """
1034    GLOBAL_CLASS_DESERIALIZER.append(deserializer)

Register custom global deserializer.