Skip to content

Commit

Permalink
Call JSON type converters recursively (#304)
Browse files Browse the repository at this point in the history
Fixes #289
  • Loading branch information
cretz authored Mar 30, 2023
1 parent cd8cbf9 commit d790468
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 9 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ jobs:
working-directory: temporalio/bridge

# Prepare
- run: python -m pip install --upgrade wheel poetry poethepoet
# Using fixed Poetry version until
# https://github.com/python-poetry/poetry/issues/7611 and
# https://github.com/python-poetry/poetry/pull/7694 are fixed
- run: python -m pip install --upgrade wheel "poetry==1.3.2" poethepoet
- run: poetry install --no-root -E opentelemetry

# Add the source dist only for Linux x64 for now
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ jobs:
uses: deadsnakes/[email protected]
with:
python-version: ${{ matrix.python }}
- run: python -m pip install --upgrade wheel poetry poethepoet
# Using fixed Poetry version until
# https://github.com/python-poetry/poetry/issues/7611 and
# https://github.com/python-poetry/poetry/pull/7694 are fixed
- run: python -m pip install --upgrade wheel "poetry==1.3.2" poethepoet
- run: poetry install --no-root -E opentelemetry
- run: poe lint
- run: poe build-develop
Expand Down
12 changes: 6 additions & 6 deletions temporalio/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ def value_to_type(
# of a supertype.
supertype = getattr(hint, "__supertype__", None)
if supertype:
return value_to_type(supertype, value)
return value_to_type(supertype, value, custom_converters)

# Load origin for other checks
origin = getattr(hint, "__origin__", hint)
Expand All @@ -1230,7 +1230,7 @@ def value_to_type(
# Try each one. Note, Optional is just a union w/ none.
for arg in type_args:
try:
return value_to_type(arg, value)
return value_to_type(arg, value, custom_converters)
except Exception:
pass
raise TypeError(f"Failed converting to {hint} from {value}")
Expand Down Expand Up @@ -1265,7 +1265,7 @@ def value_to_type(
for key, value in value.items():
if key_type:
try:
key = value_to_type(key_type, key)
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
Expand All @@ -1275,7 +1275,7 @@ def value_to_type(
this_value_type = per_key_types.get(key)
if this_value_type:
try:
value = value_to_type(this_value_type, value)
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}"
Expand Down Expand Up @@ -1307,7 +1307,7 @@ def value_to_type(
if field_value is not dataclasses.MISSING:
try:
field_values[field.name] = value_to_type(
field_hints[field.name], field_value
field_hints[field.name], field_value, custom_converters
)
except Exception as err:
raise TypeError(
Expand Down Expand Up @@ -1379,7 +1379,7 @@ def value_to_type(
f"Type {hint} only expecting {len(type_args)} values, got at least {i + 1}"
)
try:
ret_list.append(value_to_type(arg_type, item))
ret_list.append(value_to_type(arg_type, item, custom_converters))
except Exception as err:
raise TypeError(f"Failed converting {hint} index {i}") from err
# If tuple, set, or deque convert back to that type
Expand Down
14 changes: 13 additions & 1 deletion tests/test_converter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import dataclasses
import inspect
import ipaddress
import logging
import sys
Expand Down Expand Up @@ -551,7 +552,7 @@ class IPv4AddressJSONTypeConverter(JSONTypeConverter):
def to_typed_value(
self, hint: Type, value: Any
) -> Union[Optional[Any], _JSONTypeConverterUnhandled]:
if issubclass(hint, ipaddress.IPv4Address):
if inspect.isclass(hint) and issubclass(hint, ipaddress.IPv4Address):
return ipaddress.IPv4Address(value)
return JSONTypeConverter.Unhandled

Expand All @@ -565,14 +566,25 @@ async def test_json_type_converter():
# Fails to encode with default
with pytest.raises(TypeError):
await DataConverter.default.encode([addr])
with pytest.raises(TypeError):
await DataConverter.default.encode([[addr, addr]])

# But encodes with custom
payload = (await custom_conv.encode([addr]))[0]
assert '"1.2.3.4"' == payload.data.decode()
list_payload = (await custom_conv.encode([[addr, addr]]))[0]
assert '["1.2.3.4","1.2.3.4"]' == list_payload.data.decode()

# Fails to decode with default
with pytest.raises(TypeError):
await DataConverter.default.decode([payload], [ipaddress.IPv4Address])
with pytest.raises(TypeError):
await DataConverter.default.decode(
[list_payload], [List[ipaddress.IPv4Address]]
)

# But decodes with custom
assert addr == (await custom_conv.decode([payload], [ipaddress.IPv4Address]))[0]
assert [addr, addr] == (
await custom_conv.decode([list_payload], [List[ipaddress.IPv4Address]])
)[0]

0 comments on commit d790468

Please sign in to comment.