Skip to content

Commit 564cb90

Browse files
committed
Use JSONEncoder
1 parent 4b6b7f7 commit 564cb90

File tree

1 file changed

+20
-43
lines changed

1 file changed

+20
-43
lines changed

temporalio/contrib/pydantic.py

Lines changed: 20 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,22 @@
1212
"""
1313

1414
import inspect
15-
import json
1615
from typing import (
1716
Any,
18-
Optional,
1917
Type,
2018
)
2119

2220
import pydantic
2321

22+
try:
23+
from pydantic_core import to_jsonable_python
24+
except ImportError:
25+
# pydantic v1
26+
from pydantic.json import pydantic_encoder as to_jsonable_python
27+
2428
import temporalio.workflow
25-
from temporalio.api.common.v1 import Payload
2629
from temporalio.converter import (
30+
AdvancedJSONEncoder,
2731
CompositePayloadConverter,
2832
DataConverter,
2933
DefaultPayloadConverter,
@@ -32,13 +36,8 @@
3236
)
3337
from temporalio.worker.workflow_sandbox._restrictions import RestrictionContext
3438

35-
try:
36-
from pydantic_core import to_jsonable_python
37-
except ImportError:
38-
from pydantic.json import pydantic_encoder as to_jsonable_python
3939

40-
41-
class _PydanticModelTypeConverter(JSONTypeConverter):
40+
class PydanticModelTypeConverter(JSONTypeConverter):
4241
def to_typed_value(self, hint: Type, value: Any) -> Any:
4342
if not inspect.isclass(hint) or not issubclass(hint, pydantic.BaseModel):
4443
return JSONTypeConverter.Unhandled
@@ -59,55 +58,33 @@ def to_typed_value(self, hint: Type, value: Any) -> Any:
5958
if hasattr(model, "model_validate"):
6059
return model.model_validate(value)
6160
elif hasattr(model, "parse_obj"):
62-
# Pydantic v1
61+
# pydantic v1
6362
return model.parse_obj(value)
6463
else:
6564
raise ValueError(
6665
f"{model} is a Pydantic model but does not have a `model_validate` or `parse_obj` method"
6766
)
6867

6968

70-
class _PydanticJSONPayloadConverter(JSONPlainPayloadConverter):
71-
"""Pydantic JSON payload converter.
72-
73-
Conversion to JSON is implemented by overriding :py:meth:`to_payload` to use the
74-
Pydantic encoder.
75-
76-
Conversion from JSON uses the parent implementation of :py:meth:`from_payload`, with a
77-
custom type converter. The parent implementation of :py:meth:`from_payload` traverses
78-
the JSON document according to the structure specified by the type annotation; the
79-
custom type converter ensures that, during this traversal, Pydantic model instances
80-
will be created as specified by the type annotation.
81-
"""
82-
83-
def __init__(self) -> None:
84-
super().__init__(custom_type_converters=[_PydanticModelTypeConverter()])
85-
86-
def to_payload(self, value: Any) -> Optional[Payload]:
87-
"""Convert all values with Pydantic encoder or fail.
88-
89-
Like the base class, we fail if we cannot convert. This payload
90-
converter is expected to be the last in the chain, so it can fail if
91-
unable to convert.
92-
"""
93-
# Let JSON conversion errors be thrown to caller
94-
return Payload(
95-
metadata={"encoding": self.encoding.encode()},
96-
data=json.dumps(
97-
value, separators=(",", ":"), sort_keys=True, default=to_jsonable_python
98-
).encode(),
99-
)
69+
class PydanticJSONEncoder(AdvancedJSONEncoder):
70+
def default(self, o: Any) -> Any:
71+
if isinstance(o, pydantic.BaseModel):
72+
return to_jsonable_python(o)
73+
return super().default(o)
10074

10175

102-
class _PydanticPayloadConverter(CompositePayloadConverter):
76+
class PydanticPayloadConverter(CompositePayloadConverter):
10377
"""Pydantic payload converter.
10478
10579
Payload converter that replaces the default JSON conversion with Pydantic
10680
JSON conversion.
10781
"""
10882

10983
def __init__(self) -> None:
110-
json_payload_converter = _PydanticJSONPayloadConverter()
84+
json_payload_converter = JSONPlainPayloadConverter(
85+
encoder=PydanticJSONEncoder,
86+
custom_type_converters=[PydanticModelTypeConverter()],
87+
)
11188
super().__init__(
11289
*(
11390
c
@@ -119,7 +96,7 @@ def __init__(self) -> None:
11996

12097

12198
pydantic_data_converter = DataConverter(
122-
payload_converter_class=_PydanticPayloadConverter
99+
payload_converter_class=PydanticPayloadConverter
123100
)
124101
"""Data converter for Pydantic models.
125102

0 commit comments

Comments
 (0)