I published a lib on PyPi that does that, which pushed to write a complete readme, that I will reproduce here if anybody is interested in more discussion about this, along with my conclusions:
Overall, it seems like the cost of maintenance is going to be insignificant.
While the value is reduced with objects that can't be patched during runtime such as datetime (TypeError: can't set attributes of built-in/extension type 'datetime.datetime') that you'd need to import from that library instead of from datetime, it still brings value in making serialization and deserialization into the versatile and popular JSON format easier and more reusable than with the current object_hook, by leveraging typical object oriented programing in a very boring way that makes it easy for anyone to grasp.
The README looks like:
from json import loads, dumps from uuid import UUID, uuid4
obj = uuid4() encoded = dumps(str(obj)) decoded = UUID(loads(encoded))
assert obj == decoded
We can do:
from jsonlight import loads, dumps from uuid import UUID, uuid4
obj = uuid4() encoded = dumps(obj) decoded = loads(UUID, encoded) assert obj == decoded
This is because jsonlight patches uuid.UUID class to add the following methods:
- ``__jsondump__``: return a representation of self with JSON data types - ``__jsonload__``: instantiate an object based on the result from __jsondump__
You can see that the main difference with ``json.loads`` is that ``jsonlight.loads`` requires a type as the first argument. This is because ``jsonlight.loads`` will first call ``json.loads`` to convert the string into a Python object with basic JSON types, and then pass that to the type's ``__jsonload__`` function.
Other types can't be monkey patched, so you have to import them from jsonlight instead, which is the sad case of datetime:
from jsonlight import loads, dumps, datetime obj = datetime.now() assert obj == loads(datetime, dumps(obj))
You may also define ``__jsondump__`` and ``__jsonload__`` methods on your own classes, example:
from jsonlight import load
class YourClass: def __init__(self, uuid=None): self.uuid = uuid or uuid4()
def __jsondump__(self): return dict(uuid=self.uuid)
@classmethod def __jsonload__(cls, data): return cls(load(UUID, data['uuid'])
# This also works, but would not illustrate how to support recursion # return cls(UUID(data['uuid']))
As you can see:
- you don't have to worry about calling ``__jsondump__`` on return values of your own ``__jsondump__`` because ``jsonlight.dumps`` will do that recursively, - you have full control on deserialization just like with ``__setstate__``, but if you call jsonlight.load in there yourself then you don't have to duplicate deserialization logic or bother calling ``__jsonload__`` on nested objects yourself,
Monkey-patched stdlib objects are:
- UUID - Path
Feel free to add more.
Stdlib objects that couldn't be monkey patched, and that you have to import from jsonlight instead are: