pyserde
pyserde copied to clipboard
Be able to serialize dicts with Enum keys to JSON
It would be nice if this worked:
from enum import Enum
from serde.json import to_json
class MyEnum(Enum):
FOO = 'foo'
BAR = 'bar'
my_dict: dict[MyEnum, str] = {
MyEnum.FOO: 'foo',
MyEnum.BAR: 'bar',
}
print(to_json(my_dict))
But currently (0.13.0
) is:
Traceback (most recent call last):
File "/workspaces/ng/serde_enum_dict.py", line 16, in <module>
print(to_json(my_dict))
^^^^^^^^^^^^^^^^
File "/opt/python/3.11.6/lib/python3.11/site-packages/serde/json.py", line 70, in to_json
return se.serialize(to_dict(obj, c=cls, reuse_instances=False, convert_sets=True), **opts)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/python/3.11.6/lib/python3.11/site-packages/serde/json.py", line 45, in serialize
return json_dumps(obj, **opts)
^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/python/3.11.6/lib/python3.11/site-packages/serde/json.py", line 19, in json_dumps
return orjson.dumps(obj, **opts).decode() # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Dict key must be str
I'd hoped to work around it with this ⬇️ but it doesn't work (same error) 😞
class Serializer:
@dispatch
def serialize(self, value: MyEnum) -> Any:
return value.value
class Deserializer:
@dispatch
def deserialize(self, cls: Type[MyEnum], value: Any) -> MyEnum:
return MyEnum(value)
serde.add_serializer(Serializer())
serde.add_deserializer(Deserializer())
I wondered if wrapping in a class might help, but no luck:
class MyDict(dict[MyEnum, str]):
...
class Serializer:
@dispatch
def serialize(self, value: MyDict) -> dict[str, str]:
return {k.value: v for k, v in value.items()}
class Deserializer:
@dispatch
def deserialize(self, cls: Type[MyDict], value: dict[str, str]) -> MyDict:
return MyDict({MyEnum(k): v for k, v in value.items()})
Ah, if I wrap it in a class (instead of inheriting) then it works out of the box (i.e. no serializer needed):
@dataclass
class MyClass:
my_dict: dict[MyEnum, str]
my_class = MyClass({
MyEnum.FOO: 'foo',
MyEnum.BAR: 'bar',
})
json = to_json(my_class)
print(json)
my_class_ = from_json(MyClass, json)
print(my_class_)
{"my_dict":{"foo":"foo","bar":"bar"}}
MyClass(my_dict={<MyEnum.FOO: 'foo'>: 'foo', <MyEnum.BAR: 'bar'>: 'bar'})
That'll do as a workaround for now! ✅