Serializing objects¶
Typefit also comes with the ability to serialize objects into a JSON-encodable
structure. While there is no strict warranty that
serialize()
is the strict inverse function of
typefit()
function, it is engineered so that the delta
should be minimal by default and that you have a way to get to the result
you want.
Usage¶
The default behavior tries to be sane and straightforward. It is calibrated so
that if you can deserialize things using typefit()
then they
should look the same when going back through
serialize()
.
from typefit import serialize
from typing import NamedTuple
class Foo(NamedTuple):
x: int
y: int
assert serialize(Foo(1, 2)) == {"x": 1, "y": 2}
Choosing your serializer¶
Of course, it’s not always so simple. That’s why typefit lets you choose your serializer and gives you the opportunity to customize it.
Serializer
is the basic serializer that will only do 100% safe operations. However, it could be a bit limited for types who have no clear conversion between JSON and Python, typically like dates.SaneSerializer
adds some sane defaults to the mix to help you serialize dates and UUIDs without worrying too much.You can inherit from either of those if you want to create your own serializer. In that case you’ll probably want to override the
find_serializer
method in your subclass to obtain the desired behavior.
The serialize()
shortcut will use the
SaneSerializer
class.
Local behavior¶
If you want one specific object to serialize in a different way than what the
serializer has in mind, you can add a __typefit_serialize__()
method
to it and this method will be called in stead of the serializer’s method.
By example:
from typing import NamedTuple
from typefit import serialize
class IntString(int):
def __typefit_serialize__(self):
return f"{self}"
class Foo(NamedTuple):
x: IntString
foo = Foo(IntString(42))
assert serialize(foo) == {"x": "42"}
Reference¶
Narrows are data types that integrate some form of parsing to generate Python objects from more generic types like strings. All those classes accept exactly one argument to their constructor which is the data structure to convert.
- class typefit.serialize.SaneSerializer¶
Opinionated version of what sane default for non-JSON-standard types should be. Comes as an extension of
Serializer
.Dates are serialized to the ISO format
UUIDs are serialized into their default str() representation
- find_serializer(obj: Any)¶
Tries to find special cases and if none of them are matched then resort to the parent method.
- serialize_std_date(obj: datetime.date)¶
Dates are converted to ISO format
- serialize_std_datetime(obj: datetime.datetime)¶
Datetime are converted into ISO format
- serialize_uuid(obj: uuid.UUID)¶
UUIDs are simply converted to strings
- class typefit.serialize.Serializer¶
Base serializer, that has no opinion and will serialize anything that is 100% to serialize without making any assumption.
Supported types are:
Numbers (int, float)
Booleans
Strings
Sequences
Mappings
Named (and typed) tuples
Dataclasses (including with Typefit metadata in the field)
Any object with a __typefit_serialize__() method
Enums
You’ll notice that the behavior of this class is a best effort to make something sane and simple. This means there is no warranty that this works:
>>> base: SomeData = # Some data >>> serialized = serialize(base) >>> assert typefit(SomeData, serialized) == base
If you want more types to be recognized by this serializer, you can inherit from it and extend the
find_serializer()
method.If you don’t know where to look, check out the following methods:
See also
- find_serializer(obj: Any)¶
Trying to be as generic as possible. There is a few tricks there, like strings which are also sequences so the order of tests matters quite a lot.
Please override this if you want to change the behavior. See how it’s done in
SaneSerializer
for an idea on how to do it.
- json(obj: Any) → str¶
Shortcut to transform an object into a JSON string going through
serialize()
.
- serialize(obj: Any)¶
Transforms a given object into a structure of basic types which can easily be serialized to JSON. It is not a strict inverse of
typefit()
but it should be good enough for most uses.Please note that this at least assumes that objects are consistent with their type declarations, no additional security is put in place.
This method relies on the
find_serializer()
method, which means that if you implement a subclass in order to change the mapping of serialization functions you should overridefind_serializer()
.- Parameters
obj – Object to be serialized
- serialize_dataclass(obj: Any)¶
Dataclasses are mappings but they merit a special attention due to the fact that their fields are not necessarily the fields that will be used in the output, thanks to the meta(source=X) feature.
Notes
See
Source
, but basically the conversion to JSON structure generates a series of dictionaries that are then superposed into a single dictionary and returned.All values of this dictionary are of course recursively serialized.
- serialize_enum(obj: enum.Enum)¶
Enums are serialized into their value.
- serialize_generic(obj: Any) → Any¶
By default, leave the object untouched
- serialize_mapping(obj: collections.abc.Mapping)¶
Mappings are just copied into another mapping. While copying, all the values are recursively serialized.
- serialize_sequence(obj: collections.abc.Sequence)¶
Sequences are converted to regular lists, and each item of the list is recursively serialized.
- serialize_tuple(obj: tuple)¶
Named tuples are expected to have typing annotations, we’ll use that as a reference to get the fields list, however types are not enforced.
- serialize_typefit(obj: Any)¶
Serializes an object by calling its __typefit_serialize__() method.
- typefit.serialize.serialize(obj: Any) → Any¶
Shortcut to use the
SaneSerializer
’sserialize()
method.- Parameters
obj – Object to be serializer