Open cableray opened 3 years ago
Hi @cableray,
I like your idea! It allows one to influence the serialization/deserialization without access to the actually call of dump
. Or in other words: it allows one to conveniently decentralize the knowledge of how to dump/load classes.
Some of the features you describe can already be done (e.g. jsons.dump(strip_attr='python_only_prop')
). I'd like them to be implemented first, as the primary use of jsons should be dumping regular Python (data)classes without compromising them.
The other features (e.g. a dedicated serializer for an attribute) can be added later, as soon as it has been added to the "standard" jsons dump (e.g. something like: jsons.dump(some_obj, serializers=[('SomeClass.some_attr', custom_serializer)])
).
Would you agree?
Yeah, makes sense. Looking into it more, and trying to implement something on my own, I'm kinda thinking there needs to be some sort of configurable serializer builder object that can handle this, and it can be a class property (probably a callable/descriptor):
class Foo:
serializer = Serializer(
strip_attr='serializer', # although it would probably strip itself by default
serializers=[('some_attr', custom_serializer)]
)
def __init__(self):
serializer.some_option = "some dynamic value"
@serializer.serialize(…)
def get_computation(self, a, b):
return f"{a} & {b}"
Using a builder object allows some configuration when creating the builder, some configuration using decorators, and even some configuration during init, if you fork a serializer instance for each object instance (using a descriptor that works like how functions bind on __get__
)
Trying to implement it myself, I'm seeing how it gets tricky quick, because of a lot of edge cases with descriptors and decorators -- they're not always exactly composable the way I wish.
I think I'm currently needing this feature.
Currently I use jsons to transform from an application model to dtos. Unfortunately I have the case where the model may have attributes that need to be transformed in order to be converted into dtos.
e.g one of the Models has two attributes that are filled depending on the api call, vendor_name and account_name. But in the dtos we currently only want to load the account_name, that means if the vendor_name gets filled it should be returned as account_name too. This is easy using the dedicated serializer decorators, something like:
class Foo:
@property
@json_attribute(key='account_name', serializer=some_serializer, deserializer=some_deserializer)
def vendor_name(self):
return 'something'
Maybe there is already a simple solution to rename attributes when deserializing but I couldn't find a way without re-writing the whole deserializer function.
It would be nice to modify JSON serialization for class instances in a more flexible manner. I have been hoping for something that could be used like this:
Something like this gives more flexible and declarative customization. This pattern would also allow smaller refactoring, allowing adding just a few json properties at a time (if you could set
skip
toTrue
by default, if you wanted...).I'd love to help with an implementation, and I'm trying to figure one out on my own. Playing nice with other descriptors is the hard part, as descriptors are not very composable...