Python SDK - Error when deserializing dicts with Enum's as keys

Hi,
I have a data model which includes a field which is an dictionary with an “Enum” key.
When trying to send that data model to an activity, the serialization in the workflow task works just fine, but there is an error when deserializing it on the activity end.
The error is “TypeError: unhashable type: ‘list’”

Not sure if this is a bug or if I’m doing something wrong, would appreciate the help.
Thank you!

Code for reproducing:

import asyncio
from dataclasses import dataclass
from datetime import timedelta
from enum import Enum
import logging
from temporalio import activity, workflow
from temporalio.client import Client
from temporalio.worker import Worker


class MyEnum(str, Enum):
    A = "a"
    B = "b"


@dataclass
class Input:
    m: dict[MyEnum, int]


@activity.defn
async def my_activity(input: Input) -> str:
    activity.logger.info("In activity")
    return "done"


@workflow.defn
class MyWorkflow:
    @workflow.run
    async def run(self) -> str:
        workflow.logger.info("In workflow")
        input = Input(m={MyEnum.A: 1, MyEnum.B: 2})
        result = await workflow.execute_activity(my_activity, input, start_to_close_timeout=timedelta(minutes=1))
        return result


interrupt_event = asyncio.Event()


async def main():
    logging.basicConfig(level=logging.INFO)
    # Connect client using the Pydantic converter
    client = await Client.connect("localhost:7233")

    # Run a worker for the workflow
    async with Worker(
        client,
        task_queue="task-queue",
        workflows=[MyWorkflow],
        activities=[my_activity],
    ):
        # Wait until interrupted
        print("Worker started, ctrl+c to exit")
        await interrupt_event.wait()
        print("Shutting down")


if __name__ == "__main__":
    loop = asyncio.new_event_loop()
    try:
        loop.run_until_complete(main())
    except KeyboardInterrupt:
        interrupt_event.set()
        loop.run_until_complete(loop.shutdown_asyncgens())

Interesting portions of the stacktrace:

WARNING:temporalio.activity:Completing activity as failed
Traceback (most recent call last):
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 1511, in value_to_type
    field_values[field.name] = value_to_type(
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 1485, in value_to_type
    ret_dict[key] = value
TypeError: unhashable type: 'list'

And later:

Traceback (most recent call last):
  File "/.../.venv/lib/python3.10/site-packages/temporalio/worker/_activity.py", line 352, in _run_activity
    else await self._data_converter.decode(
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 1075, in decode
    return self.payload_converter.from_payloads(payloads, type_hints)
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 307, in from_payloads
    values.append(converter.from_payload(payload, type_hint))
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 583, in from_payload
    obj = value_to_type(type_hint, obj, self._custom_type_converters)
  File "/.../.venv/lib/python3.10/site-packages/temporalio/converter.py", line 1515, in value_to_type
    raise TypeError(
TypeError: Failed converting field m on dataclass <class '__main__.Input'>

Just saw this reply by Chad Retz on slack, this resolves the issue for me thanks:

So we don’t support Enum or str extensions, but we do support StrEnum. See GitHub - temporalio/sdk-python: Temporal Python SDK and the logic at sdk-python/temporalio/converter.py at d5edb71ac25f0d82582ec16f13410b0388addc10 · temporalio/sdk-python · GitHub. What’s probably happening with your code is the hint is not a str and is not IntEnum or StrEnum so it’s matching Iterable and treated like an iterable of characters.

You can either set the datatype to str, use a StrEnum, or make a custom converter