cattrs icon indicating copy to clipboard operation
cattrs copied to clipboard

How to serialize (JSON) a type reference?

Open kkg-else42 opened this issue 3 years ago • 6 comments

(I know it's not a cattrs issue.) I'm looking for a way to JSON-serialize a type-ref inside a attrs-class. But type-refs aren't supported by json-lib. See a litte example:

import attrs, cattrs, json

@attrs.mutable
class A:
    my_type: type

@attrs.mutable
class B:
    foo: int

a1=A(my_type=B)

a1u=cattrs.unstructure(a1)

a1uj=json.dumps(a1u)
Traceback (most recent call last):
  File "C:\Python310\lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "C:\Python310\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\Python310\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Python310\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Python310\lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type type is not JSON serializable

Are there any ideas on how to achieve my goal?

kkg-else42 avatar Oct 24 '22 14:10 kkg-else42

What json output are you expecting?

Tinche avatar Oct 24 '22 20:10 Tinche

I want to make the de-serialization as generic as possible for various attrs classes (their instances are sent as JSON messages via MQTT). For this purpose, the respective type information should be contained in the message (in a container). Since this information is needed by cattrs.structure. My current work-around is to store the type information as str-value.

kkg-else42 avatar Oct 25 '22 12:10 kkg-else42

Do you only want the class name in the JSON payload, or more information?

Tinche avatar Oct 31 '22 11:10 Tinche

To rebuild a type object one needs the class name (my_type.__name__) and the module name (my_type.__module__): my_type: type = getattr(importlib.import_module(<module-name>), <class-name>)

At the moment I store these two values. I'm sure this could be done via hooks, which I haven't looked into yet.

But maybe a general json-lib support for type-object would be the better.

kkg-else42 avatar Oct 31 '22 11:10 kkg-else42

Interesting, ok. We're working on what we're calling tagged union support, this sounds like it. It's un/structuring a union with some metadata attached so it can be recreated on the other end.

Looks like you want the metadata to be a fully-qualified name for a class, and the structuring hook to import it. I'll keep this use case in mind.

Tinche avatar Oct 31 '22 11:10 Tinche

Looks like you want the metadata to be a fully-qualified name for a class, and the structuring hook to import it.

Yes, this is what I want.

kkg-else42 avatar Oct 31 '22 12:10 kkg-else42