Fast and well tested serialization library
APACHE-2.0 License
Bot releases are hidden (Show)
collections.OrderedDict
(3.7+) and collections.Counter
typesserialize
and deserialize
field metadata options in Union
and Optional
typesSerializationStrategy
is now a field option (backward incompatible change). See here for details.Config
class. See here for details.Union
types. It's recommended to place more complex variant types at first place like Union[Dict[int, int], List[int]]
not Union[List[int], Dict[int, int]]
. When optional type validation is implemented it will be possible not to follow this rule.serialize
and deserialize
options for any third-party types and SerializableType
classes if you need it for some reason.@dataclass
class A(DataClassDictMixin):
@dataclass
class B(DataClassDictMixin):
b: int
a: int
b: B
print(A.from_dict({'a': 1, 'b': {'b': 2}}))
class Counter:
deserialize = 0
serialize = 0
@classmethod
def __pre_deserialize__(cls, d):
Counter.deserialize += 1
return d
def __pre_serialize__(self):
Counter.serialize += 1
return self
@dataclass
class Derived(Counter, DataClassDictMixin):
a: int
obj = Derived.from_dict({"a": 1})
obj.to_dict()
print(Counter.deserialize) # 1
print(Counter.serialize) # 1
ipaddress
types (https://github.com/Fatal1ty/mashumaro/pull/29)@dataclass
class User(DataClassJSONMixin):
name: str
password: str
is_deserialized: bool = False
counter: ClassVar[int] = 0
@classmethod
def __pre_deserialize__(cls, d: Dict[Any, Any]) -> Dict[Any, Any]:
return {k.lower(): v for k, v in d.items()}
@classmethod
def __post_deserialize__(cls, obj: "User") -> "User":
obj.is_deserialized = True
return obj
def __pre_serialize__(self) -> "User":
self.counter += 1
return self
def __post_serialize__(self, d: Dict[Any, Any]) -> Dict[Any, Any]:
d.pop("password")
return d
user = User.from_json('{"NAME": "Name", "PASSWORD": "secret"}')
print(user) # User(name='Name', password='secret', is_deserialized=True)
print(user.to_json()) # {"name": "Name", "is_deserialized": true}
print(user.counter) # 1
TypeError
exception that was thrown instead of MissingField
in case when field
doesn't have default
argumentmetadata
argument. See here for details.pathlib
os.PathLike
will be deserialized into an instance of that classos.PathLike
will be deserialized into an instance of PurePath
class: PurePosixClass
on posix, PureWindowsPath
in windowsIn the previous versions if a data class had been derived from another data class with a default_factory, MissingField
would have been raised on instantiation without field value provided as it shown in the following example:
@dataclass()
class A(DataClassJSONMixin):
foo: List[str] = field(default_factory=list)
@dataclass()
class B(A):
pass
print(B.from_dict({})) # MissingField: Field "foo" of type typing.List[str] is missing in __main__.B instance
Thanks to @ian-sentropy who found this bug.
In the version 1.12
if you inherit both Enum
and SerializableType
classes you will get an exception TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
like in the following example:
class Example(IntEnum, SerializableType):
A = 1
B = 2
def _serialize(self):
return {"value": self.name}
@classmethod
def _deserialize(cls, value):
return Example.__members__[value["value"]]
In the version 1.11
if a data class without annotations had been derived from another data class, KeyError
would have been raised as it shown in the following example:
@dataclass
class A:
a: int
@dataclass
class B(A, DataClassDictMixin):
pass
# ...
# KeyError: '__annotations__'
In the previous versions there was a problem in case one data class is derived from another data class that have default values. If any ancestor had had a field with a default value, constructing an instance from a dictionary without that field would've been failed as it shown in the following example:
@dataclass
class A:
a: int
b: int = 123
@dataclass
class B(A, DataClassDictMixin):
c: int = 456
B.from_dict({'a': 111, 'c': 222}) # mashumaro.exceptions.MissingField: Field "b" of type builtins.int is missing in __main__.B instance