Skip to content

Data converter non-string keys #833

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions temporalio/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1471,22 +1471,39 @@ def value_to_type(
)
# Convert each key/value
for key, value in value.items():
if key_type:
try:
key = value_to_type(key_type, key, custom_converters)
except Exception as err:
raise TypeError(f"Failed converting key {key} on {hint}") from err
# If there are per-key types, use it instead of single type
this_value_type = value_type
if per_key_types:
# TODO(cretz): Strict mode would fail an unknown key
this_value_type = per_key_types.get(key)

if key_type:
# This function is used only by JSONPlainPayloadConverter. When
# serializing to JSON, Python supports key types str, int, float, bool,
# and None, serializing all to string representations. We now attempt to
# use the provided type annotation to recover the original value with its
# original type.
try:
if isinstance(key, str):
if key_type is int or key_type is float:
key = key_type(key)
elif key_type is bool:
key = {"true": True, "false": False}[key]
elif key_type is type(None):
key = {"null": None}[key]

if not isinstance(key, key_type):
key = value_to_type(key_type, key, custom_converters)
except Exception as err:
raise TypeError(
f"Failed converting key {repr(key)} to type {key_type} in mapping {hint}"
) from err

if this_value_type:
try:
value = value_to_type(this_value_type, value, custom_converters)
except Exception as err:
raise TypeError(
f"Failed converting value for key {key} on {hint}"
f"Failed converting value for key {repr(key)} in mapping {hint}"
) from err
ret_dict[key] = value
# If there are per-key types, it's a typed dict and we want to attempt
Expand Down
8 changes: 6 additions & 2 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,12 @@ def fail(hint: Any, value: Any) -> None:
# just accepting any dict.
ok(MyTypedDictNotTotal, {"foo": "bar"})
ok(MyTypedDict, {"foo": "bar", "blah": "meh"})
# Note, dicts can't have int key in JSON
fail(Dict[int, str], {1: "2"})

# Non-string dict keys are supported
ok(Dict[int, str], {1: "1"})
ok(Dict[float, str], {1.0: "1"})
ok(Dict[bool, str], {True: "1"})
ok(Dict[None, str], {None: "1"})
Comment on lines +378 to +381
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm that before this change, all of these failed? I just want to make sure one of these didn't accidentally work before we made these changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I actually confirmed that same thing myself before marking the PR ready for review. They do all fail.


# Alias
ok(MyDataClassAlias, MyDataClass("foo", 5, SerializableEnum.FOO))
Expand Down
Loading