serde
pyserde
Yet another serialization library on top of dataclasses, inspired by serde-rs.
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
- Supported data formats
- dict
- tuple
- JSON
- Yaml
- Toml
- MsgPack
- Pickle
- Supported types
- Primitives (
int
,float
,str
,bool
) - Containers
list
,set
,tuple
,dict
frozenset
,defaultdict
typing.Optional
typing.Union
- User defined class with
@dataclass
typing.NewType
for primitive typestyping.Any
typing.Literal
typing.Generic
typing.ClassVar
dataclasses.InitVar
Enum
andIntEnum
- Standard library
- PyPI library
numpy
types
- Primitives (
- Class Attributes
- Field Attributes
- Decorators
- Type Check
- Union Representation
- Forward reference
- PEP563 Postponed Evaluation of Annotations
- PEP585 Type Hinting Generics In Standard Collections
- PEP604 Allow writing union types as X | Y
- PEP681 Data Class Transform
- Case Conversion
- Rename
- Alias
- Skip (de)serialization (skip, skip_if, skip_if_false, skip_if_default)
- Custom field (de)serializer
- Custom class (de)serializer
- Custom global (de)serializer
- Flatten
Extensions
- pyserde-timedelta: (de)serializing datetime.timedelta in ISO 8601 duration format.
Contributors β¨
Thanks goes to these wonderful people (emoji key):
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
.
serde.se
: All about serialization.serde.de
: All about deserialization.serde.core
: Core module used byserde.se
andserde.de
modules.serde.compat
: Compatibility layer which handles mostly differences oftyping
module between python versions.
The following modules provide pyserde's (de)serialize APIs.
serde.json
: Serialize and Deserialize in JSON.serde.msgpack
: Serialize and Deserialize in MsgPack.serde.yaml
: Serialize and Deserialize in YAML.serde.toml
: Serialize and Deserialize in TOML.serde.pickle
: Serialize and Deserialize in Pickle.
Other modules
serde.inspect
: Prints generated code by pyserde.
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)
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
.
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}'
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)
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
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
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}]
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)]
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)]
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)]
Serde error class.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- add_note
- args
Skip a field in custom (de)serializer.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- add_note
- args
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.
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.
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.
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.
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.
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")
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)
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")
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)
1023def add_serializer(serializer: ClassSerializer) -> None: 1024 """ 1025 Register custom global serializer. 1026 """ 1027 GLOBAL_CLASS_SERIALIZER.append(serializer)
Register custom global serializer.
1030def add_deserializer(deserializer: ClassDeserializer) -> None: 1031 """ 1032 Register custom global deserializer. 1033 """ 1034 GLOBAL_CLASS_DESERIALIZER.append(deserializer)
Register custom global deserializer.