Skip to content

Commit 4933dc5

Browse files
authored
Data converter non-string keys (#833)
* Failing test for non-string dict keys * Support non-string keys in JSONPlain data converter
1 parent 52bc5cf commit 4933dc5

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

Diff for: temporalio/converter.py

+24-7
Original file line numberDiff line numberDiff line change
@@ -1471,22 +1471,39 @@ def value_to_type(
14711471
)
14721472
# Convert each key/value
14731473
for key, value in value.items():
1474-
if key_type:
1475-
try:
1476-
key = value_to_type(key_type, key, custom_converters)
1477-
except Exception as err:
1478-
raise TypeError(f"Failed converting key {key} on {hint}") from err
1479-
# If there are per-key types, use it instead of single type
14801474
this_value_type = value_type
14811475
if per_key_types:
14821476
# TODO(cretz): Strict mode would fail an unknown key
14831477
this_value_type = per_key_types.get(key)
1478+
1479+
if key_type:
1480+
# This function is used only by JSONPlainPayloadConverter. When
1481+
# serializing to JSON, Python supports key types str, int, float, bool,
1482+
# and None, serializing all to string representations. We now attempt to
1483+
# use the provided type annotation to recover the original value with its
1484+
# original type.
1485+
try:
1486+
if isinstance(key, str):
1487+
if key_type is int or key_type is float:
1488+
key = key_type(key)
1489+
elif key_type is bool:
1490+
key = {"true": True, "false": False}[key]
1491+
elif key_type is type(None):
1492+
key = {"null": None}[key]
1493+
1494+
if not isinstance(key, key_type):
1495+
key = value_to_type(key_type, key, custom_converters)
1496+
except Exception as err:
1497+
raise TypeError(
1498+
f"Failed converting key {repr(key)} to type {key_type} in mapping {hint}"
1499+
) from err
1500+
14841501
if this_value_type:
14851502
try:
14861503
value = value_to_type(this_value_type, value, custom_converters)
14871504
except Exception as err:
14881505
raise TypeError(
1489-
f"Failed converting value for key {key} on {hint}"
1506+
f"Failed converting value for key {repr(key)} in mapping {hint}"
14901507
) from err
14911508
ret_dict[key] = value
14921509
# If there are per-key types, it's a typed dict and we want to attempt

Diff for: tests/test_converter.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,12 @@ def fail(hint: Any, value: Any) -> None:
373373
# just accepting any dict.
374374
ok(MyTypedDictNotTotal, {"foo": "bar"})
375375
ok(MyTypedDict, {"foo": "bar", "blah": "meh"})
376-
# Note, dicts can't have int key in JSON
377-
fail(Dict[int, str], {1: "2"})
376+
377+
# Non-string dict keys are supported
378+
ok(Dict[int, str], {1: "1"})
379+
ok(Dict[float, str], {1.0: "1"})
380+
ok(Dict[bool, str], {True: "1"})
381+
ok(Dict[None, str], {None: "1"})
378382

379383
# Alias
380384
ok(MyDataClassAlias, MyDataClass("foo", 5, SerializableEnum.FOO))

0 commit comments

Comments
 (0)