Serialization / Deserialization¶
Core to state-persistence is the ability to serialize and deserialize objects.
Burr comes with a pluggable serialization/deserialization mechanism.
There are two approaches: class/type based, & field level registration. See serialize
and deserialize
for reference details.
How it works¶
The State
object has a serialize
method that returns a dictionary.
The State
class also has a deserialize
method that takes a dictionary and returns a state object.
It is then delegated to persisters and trackers to call these methods and store the serialized state.
Underneath the State object delegates to the serialize
and deserialize
functions.
Customizing Serialization/Deserialization¶
Here’s a video walkthrough of how to add custom type and field serialization/deserialization:
See this example for the notebook.
Type based serialization/deserialization¶
To create your own python type based serialization/deserialization mechanism, you need to implement the following code. The assumption here is that you have some custom class/type you want to serialize/deserialize.
from typing import Any, Dict
from burr.core import serde
class MY_CLASS:
# your custom class/type
pass
@serde.serialize.register(MY_CLASS)
def serialize_myclass(value: cls, myclass_kwargs: dict = None, **kwargs) -> dict:
"""Serializes the value using my custom methodology.
:param value: the value to serialize.
:param myclass_kwargs: not required. Optional.
:param kwargs:
:return: dictionary of serde.KEY and value
"""
if myclass_kwargs is None:
myclass_kwargs = {}
return {
# required to identify how to deserialize
serde.KEY: "myclass",
# delegate to your custom serialization
"value": some_custom_serialization(value, **myclass_kwargs),
}
@serde.deserializer.register("myclass")
def deserialize_myclass(value: dict, myclass_kwargs: dict = None, **kwargs) -> cls:
"""Deserializes the value using my custom methodology.
:param value: the value to deserialize from.
:param myclass_kwargs: not required. Optional.
:param kwargs:
:return: object of type cls
"""
if myclass_kwargs is None:
myclass_kwargs = {}
# delegate to your custom deserialization
return some_custom_deserialization(value["value"], **myclass_kwargs)
You’ll need to this code to run/be imported so it can register itself.
Field level Serialization/Deserialization¶
Field level serialization/deserialization is for when you want to further customize your state serialization strategy. E.g. you have two fields of the same type but want to serialize things differently. Registration of this approach is handled by a registration function in the core.state module. When serializing/deserializing state, field names will be first checked to see if there is a custom serializer/deserializer registered for that field, before delegating to the default type based serialization/deserialization mechanism.
from burr.core import state
def my_field_serializer(value: MyType, **kwargs) -> dict:
serde_value = _do_something_to_serialize(value)
return {"value": serde_value}
def my_field_deserializer(value: dict, **kwargs) -> MyType:
serde_value = value["value"]
return _do_something_to_deserialize(serde_value)
state.register_field_serde("my_field", my_field_serializer, my_field_deserializer)
This will register a custom serializer/deserializer for the field “my_field”.
Requirements for the serializer/deserializer functions:
The serializer function needs to return a dictionary.
Both function signatures needs to have a
**kwargs
parameter to allow for custom arguments to be passed in. We advise namespacing the kwargs provided to avoid conflicts with other serializers/deserializers.