Skip to content

Decorators

@serde

@serde is a wrapper of @serialize and @deserialize decorators.

This code

@serde
class Foo:
    ...

is equivalent to the following code.

@deserialize
@serialize
@dataclass
class Foo:
    ...

@serde decorator does these for you: * Add @serialize and @deserialize decorators to a class * Add @dataclass decorator to a class if a class doesn't have @dataclass * You can pass both (de)serialize attributes to the decorator * serializer attribute is ignored in @deserialize and deserializer attribute is ignored in @serialize

Use @serde for most classes unless you need separate serialization/deserialization configs.

@serde(serializer=serializer, deserializer=deserializer)
@dataclass
class Foo:
    ...

Note

@serde actually works without @dataclass decorator, because it detects and add @dataclass to the declared class automatically. However, mypy will produce Too many arguments or Unexpected keyword argument error. This is due to the mypy limitation.

@serde
class Foo:
    ...

But if you use a PEP681 compliant type checker (e.g. pyright), you don't get the type error because pyserde supports PEP681 dataclass_transform

@serialize/@deserialize

@serialize and @deserialize are used by @serde under the hood. We recommend to use those two decorators in the following cases. Otherwise @serde is recommended. * You only need either serialization or deserialization functionality * You want to have different class attributes as below

@deserialize(rename_all = "snakecase")
@serialize(rename_all = "camelcase")
class Foo:
    ...

(de)serializing class without @serde

pyserde can (de)serialize dataclasses without @serde since v0.10.0. This feature is convenient when you want to use classes declared in external libraries or a type checker doesn't work with @serde decorator. See this example.

How does it work? It's quite simple that pyserde add @serde decorator if a class doesn't has it. It may take for a while for the first API call, but the generated code will be cached internally. So it won't be a problem. See the following example to deserialize a class in a third party package.

@dataclass
class External:
    ...

to_dict(External()) # works without @serde

Note that you can't specify class attributes e.g. rename_all in this case. If you want to add a class attribute to an external dataclass, there is a technique to do that by extending dataclass. See this example.

@dataclass
class External:
    some_value: int

@serde(rename_all="kebabcase")
@dataclass
class Wrapper(External):
    pass

How can I use forward references?

pyserde supports forward references. If you replace a nested class name with with string, pyserde looks up and evaluate the decorator after nested class is defined.

from __future__ import annotations # make sure to import annotations

@dataclass
class Foo:
    i: int
    s: str
    bar: Bar  # Bar can be specified although it's declared afterward.

@serde
@dataclass
class Bar:
    f: float
    b: bool

# Evaluate pyserde decorators after `Bar` is defined.
serde(Foo)

PEP563 Postponed Evaluation of Annotations

pyserde supports PEP563 Postponed evaluation of annotation.

from __future__ import annotations
from serde import serde

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

    def foo(self, cls: Foo):  # You can use "Foo" type before it's defined.
        print('foo')

See examples/lazy_type_evaluation.py for complete example.