1+ """A data converter for Pydantic models
2+
3+ To use, pass ``pydantic_data_converter`` as the ``data_converter`` argument to
4+ :py:class:`temporalio.client.Client`:
5+
6+ .. code-block:: python
7+
8+ client = Client(
9+ data_converter=pydantic_data_converter,
10+ ...
11+ )
12+ """
13+
114import inspect
215import json
316from typing import (
2134from temporalio .worker .workflow_sandbox ._restrictions import RestrictionContext
2235
2336
24- class PydanticJSONPayloadConverter (JSONPlainPayloadConverter ):
25- """Pydantic JSON payload converter.
26-
27- Extends :py:class:`JSONPlainPayloadConverter` to override :py:meth:`to_payload` using
28- the Pydantic encoder. :py:meth:`from_payload` uses the parent implementation, with a
29- custom type converter.
30- """
31-
32- def __init__ (self ) -> None :
33- super ().__init__ (custom_type_converters = [PydanticModelTypeConverter ()])
34-
35- def to_payload (self , value : Any ) -> Optional [Payload ]:
36- """Convert all values with Pydantic encoder or fail.
37-
38- Like the base class, we fail if we cannot convert. This payload
39- converter is expected to be the last in the chain, so it can fail if
40- unable to convert.
41- """
42- # Let JSON conversion errors be thrown to caller
43- return Payload (
44- metadata = {"encoding" : self .encoding .encode ()},
45- data = json .dumps (
46- value , separators = ("," , ":" ), sort_keys = True , default = pydantic_encoder
47- ).encode (),
48- )
49-
50-
51- class PydanticModelTypeConverter (JSONTypeConverter ):
37+ class _PydanticModelTypeConverter (JSONTypeConverter ):
5238 def to_typed_value (self , hint : Type , value : Any ) -> Any :
5339 if not inspect .isclass (hint ) or not issubclass (hint , pydantic .BaseModel ):
5440 return JSONTypeConverter .Unhandled
@@ -77,13 +63,47 @@ def to_typed_value(self, hint: Type, value: Any) -> Any:
7763 )
7864
7965
80- class PydanticPayloadConverter (CompositePayloadConverter ):
81- """Payload converter that replaces Temporal JSON conversion with Pydantic
66+ class _PydanticJSONPayloadConverter (JSONPlainPayloadConverter ):
67+ """Pydantic JSON payload converter.
68+
69+ Conversion to JSON is implemented by overriding :py:meth:`to_payload` to use the
70+ Pydantic encoder.
71+
72+ Conversion from JSON uses the parent implementation of :py:meth:`from_payload`, with a
73+ custom type converter. The parent implementation of :py:meth:`from_payload` traverses
74+ the JSON document according to the structure specified by the type annotation; the
75+ custom type converter ensures that, during this traversal, Pydantic model instances
76+ will be created as specified by the type annotation.
77+ """
78+
79+ def __init__ (self ) -> None :
80+ super ().__init__ (custom_type_converters = [_PydanticModelTypeConverter ()])
81+
82+ def to_payload (self , value : Any ) -> Optional [Payload ]:
83+ """Convert all values with Pydantic encoder or fail.
84+
85+ Like the base class, we fail if we cannot convert. This payload
86+ converter is expected to be the last in the chain, so it can fail if
87+ unable to convert.
88+ """
89+ # Let JSON conversion errors be thrown to caller
90+ return Payload (
91+ metadata = {"encoding" : self .encoding .encode ()},
92+ data = json .dumps (
93+ value , separators = ("," , ":" ), sort_keys = True , default = pydantic_encoder
94+ ).encode (),
95+ )
96+
97+
98+ class _PydanticPayloadConverter (CompositePayloadConverter ):
99+ """Pydantic payload converter.
100+
101+ Payload converter that replaces the default JSON conversion with Pydantic
82102 JSON conversion.
83103 """
84104
85105 def __init__ (self ) -> None :
86- json_payload_converter = PydanticJSONPayloadConverter ()
106+ json_payload_converter = _PydanticJSONPayloadConverter ()
87107 super ().__init__ (
88108 * (
89109 c
@@ -95,6 +115,9 @@ def __init__(self) -> None:
95115
96116
97117pydantic_data_converter = DataConverter (
98- payload_converter_class = PydanticPayloadConverter
118+ payload_converter_class = _PydanticPayloadConverter
99119)
100- """Data converter using Pydantic JSON conversion."""
120+ """Data converter for Pydantic models.
121+
122+ To use, pass this as the ``data_converter`` argument to :py:class:`temporalio.client.Client`
123+ """
0 commit comments