Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Be able to serialize dicts with Enum keys to JSON #468

Open
davetapley opened this issue Jan 31, 2024 · 3 comments
Open

Be able to serialize dicts with Enum keys to JSON #468

davetapley opened this issue Jan 31, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@davetapley
Copy link
Contributor

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
@davetapley
Copy link
Contributor Author

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())

@davetapley
Copy link
Contributor Author

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()})

@davetapley
Copy link
Contributor Author

davetapley commented Jan 31, 2024

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! ✅

@yukinarit yukinarit added the enhancement New feature or request label Apr 29, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants