Class Attributes¶
Class attributes can be specified as arguments in the serialize/deserialize decorators in order to customize the (de)serialization behaviour of the class entirely. If you want to customize a field, please consider using Field Attributes.
Class attributes affect how every field is treated, so they are ideal for naming conventions, tagging, or behavior that must be consistent across the whole class.
Attributes offered by dataclasses¶
frozen¶
dataclass frozen class attribute works as expected.
kw_only¶
New in v0.12.2. dataclass kw_only class attribute works as expected.
See examples/kw_only.py for the complete example.
Attributes offered by pyserde¶
rename_all¶
rename_all can converts field names into the specified string case. The following example converts camel case field names into snake case names. Case coversion depends on python-casefy. You can find the list of supported cases in the python-casefy's docs.
@serde(rename_all = 'camelcase')
class Foo:
int_field: int
str_field: str
f = Foo(int_field=10, str_field='foo')
print(to_json(f))
"int_field" is converted to "intField" and "str_field" is converted to "strField".
Note
If rename_all class attribute and rename field attribute are used at the same time, rename will be prioritized.
See examples/rename_all.py for the complete example.
tagging¶
New in v0.7.0. See Union.
transparent¶
When transparent=True, a wrapper class with a single field is (de)serialized as that field, like serde-rs #[serde(transparent)].
@serde(transparent=True)
class UserId:
value: int
assert to_json(UserId(1)) == "1"
assert from_json(UserId, "1") == UserId(1)
Constraints:
* The class must have exactly one init=True field that is not skipped.
* Any other dataclass fields must be both init=False and skip=True (e.g. internal cache fields).
class_serializer / class_deserializer¶
If you want to use a custom (de)serializer at class level, you can pass your (de)serializer object in class_serializer and class_deserializer class attributes. Class custom (de)serializer depends on a python library plum which allows multiple method overloading like C++. With plum, you can write robust custom (de)serializer in a quite neat way.
class MySerializer:
@dispatch
def serialize(self, value: datetime) -> str:
return value.strftime("%d/%m/%y")
class MyDeserializer:
@dispatch
def deserialize(self, cls: Type[datetime], value: Any) -> datetime:
return datetime.strptime(value, "%d/%m/%y")
@serde(class_serializer=MySerializer(), class_deserializer=MyDeserializer())
class Foo:
v: datetime
One big difference from legacy serializer and deserializer is the fact that new class_serializer and class_deserializer are more deeply integrated at the pyserde's code generator level. You no longer need to handle Optional, List and Nested dataclass by yourself. Custom class (de)serializer will be used at all level of (de)serialization so you can extend pyserde to support third party types just like builtin types.
Also, * If both field and class serializer specified, field serializer is prioritized * If both legacy and new class serializer specified, new class serializer is prioritized
Tip
If you implements multiple serialize methods, you will receive "Redefinition of unused serialize" warning from type checker. In such case, try using plum.overload and plum.dispatch to workaround it. See plum's documentation for more information.
from plum import dispatch, overload
class Serializer:
# use @overload
@overload
def serialize(self, value: int) -> Any:
return str(value)
# use @overload
@overload
def serialize(self, value: float) -> Any:
return int(value)
# Add method time and make sure to add @dispatch. Plum will do all the magic to erase warnings from type checker.
@dispatch
def serialize(self, value: Any) -> Any:
...
See examples/custom_class_serializer.py for complete example.
New in v0.13.0.
serializer / deserializer¶
Deprecated
Deprecated since v0.13.0. Consider using class_serializer and class_deserializer.
If you want to use a custom (de)serializer at class level, you can pass your (de)serializer methods in serializer and deserializer class attributes.
def serializer(cls, o):
if cls is datetime:
return o.strftime('%d/%m/%y')
else:
raise SerdeSkip()
def deserializer(cls, o):
if cls is datetime:
return datetime.strptime(o, '%d/%m/%y')
else:
raise SerdeSkip()
@serde(serializer=serializer, deserializer=deserializer)
class Foo:
a: datetime
See examples/custom_legacy_class_serializer.py for complete example.
type_check¶
New in v0.9.0. See Type Check.
serialize_class_var¶
New in v0.9.8. Since dataclasses.fields doesn't include a class variable 1, pyserde doesn't serialize class variable as default. This option allows a field of typing.ClassVar to be serialized.
See examples/class_var.py for complete example.
skip_if_default¶
New in v0.30.0. When skip_if_default=True is set on the class decorator, every field is skipped during (de)serialization if its value equals its default (or the result of its default_factory). Field-level skip_if_default still wins, so you can turn it off for specific fields by setting skip_if_default=False on that field.
@serde(skip_if_default=True)
class Settings:
theme: str = "light"
retries: int = 3
api_key: str | None = None
# this one is kept even though class-level skipping is on
note: str = field(default="keep me", skip_if_default=False)
Nested dataclasses respect the class-level setting, and defaults created via default_factory are handled as well. See examples/skip_if_default_class.py for a runnable demo.
skip_if_none¶
New in v0.30.0. When skip_if_none=True is set on the class decorator, all fields whose value is None are skipped during (de)serialization. Field-level skip_if_none overrides the class setting (False keeps the field even when it is None).
@serde(skip_if_none=True)
class Profile:
nickname: str | None = None
bio: str | None = field(default=None, skip_if_none=False) # keep even when None
Use this when you want compact payloads but need to keep specific None fields.
deny_unknown_fields¶
New in v0.22.0, the deny_unknown_fields option in the pyserde decorator allows you to enforce strict field validation during deserialization. When this option is enabled, any fields in the input data that are not defined in the target class will cause deserialization to fail with a SerdeError.
Consider the following example:
With deny_unknown_fields=True, attempting to deserialize data containing fields beyond those defined (a and b in this case) will raise an error. For instance:
SerdeError since fields c and d are not recognized members of Foo.
See examples/deny_unknown_fields.py for complete example.