iiif-prezi / iiif-prezi3

IIIF Presentation API 3 Python Library
https://iiif-prezi.github.io/iiif-prezi3/
Apache License 2.0
28 stars 14 forks source link

`navDate` property causes serialization error #150

Closed digitaldogsbody closed 1 year ago

digitaldogsbody commented 1 year ago

Because we override the .json() function provided by Pydantic in order to be able to inject the Prezi3 context, we are using the native json.dumps(), which cannot serialize datetime instances (amongst other things).

Expected behaviour:

A Manifest with a navDate property is correctly serialized

Observed behaviour:

>>> from iiif_prezi3 import Manifest, Collection
>>> m = Manifest(label="1987")
>>> m.navDate = "1987-01-01T00:00:00+00:00"
>>> m.json()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/mike/projects/iiif-prezi3/iiif_prezi3/base.py", line 53, in json
    return self.jsonld(**kwargs)
  File "/home/mike/projects/iiif-prezi3/iiif_prezi3/base.py", line 62, in jsonld
    return json.dumps({"@context": "http://iiif.io/api/presentation/3/context.json",
  File "/usr/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable

Potential bug location(s):

https://github.com/iiif-prezi/iiif-prezi3/blob/main/iiif_prezi3/base.py#L62-L63

Any other comments:

The fix is simple, we can leverage Pydantic's existing JSON encoder functionality (https://github.com/pydantic/pydantic/blob/main/pydantic/json.py#L72-L90) and pass it to the default argument of json.dumps() (https://docs.python.org/3/library/json.html#json.dump), which is used for providing a function that handles the serialization of classes that the native JSONEncoder can't deal with. As a bonus, we also get serialization of all the other types Pydantic supports.