Skip to content

Commit b8ab990

Browse files
committed
Use structural typing for the interface
1 parent 3a7f84e commit b8ab990

File tree

3 files changed

+18
-23
lines changed

3 files changed

+18
-23
lines changed

temporalio/client.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
from temporalio.converter import (
6767
DataConverter,
6868
SerializationContext,
69-
WithSerializationContext,
7069
WorkflowSerializationContext,
7170
)
7271
from temporalio.service import (
@@ -2737,7 +2736,7 @@ class AsyncActivityIDReference:
27372736
activity_id: str
27382737

27392738

2740-
class AsyncActivityHandle(WithSerializationContext):
2739+
class AsyncActivityHandle:
27412740
"""Handle representing an external activity for completion and heartbeat."""
27422741

27432742
def __init__(

temporalio/converter.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@
2828
Mapping,
2929
NewType,
3030
Optional,
31+
Protocol,
3132
Sequence,
3233
Tuple,
3334
Type,
3435
TypeVar,
3536
Union,
3637
get_type_hints,
3738
overload,
39+
runtime_checkable,
3840
)
3941

4042
import google.protobuf.duration_pb2
@@ -136,10 +138,13 @@ class ActivitySerializationContext(BaseWorkflowSerializationContext):
136138
is_local: bool
137139

138140

139-
# TODO: duck typing or nominal typing?
140-
class WithSerializationContext(ABC):
141+
@runtime_checkable
142+
class WithSerializationContext(Protocol):
141143
"""Interface for classes that can use serialization context.
142144
145+
To use serialization context in your class, implementing this interface is sufficient; you do
146+
not need to inherit from this class.
147+
143148
The following classes may implement this interface:
144149
- :py:class:`PayloadConverter`
145150
- :py:class:`PayloadCodec`
@@ -331,7 +336,7 @@ def from_payload(
331336
raise NotImplementedError
332337

333338

334-
class CompositePayloadConverter(PayloadConverter, WithSerializationContext):
339+
class CompositePayloadConverter(PayloadConverter):
335340
"""Composite payload converter that delegates to a list of encoding payload converters.
336341
337342
Encoding/decoding are attempted on each payload converter successively until

tests/test_serialization_context.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
PayloadCodec,
3939
PayloadConverter,
4040
SerializationContext,
41-
WithSerializationContext,
4241
WorkflowSerializationContext,
4342
)
4443
from temporalio.exceptions import ApplicationError
@@ -66,9 +65,7 @@ class TraceData:
6665
items: list[TraceItem] = field(default_factory=list)
6766

6867

69-
class SerializationContextPayloadConverter(
70-
EncodingPayloadConverter, WithSerializationContext
71-
):
68+
class SerializationContextPayloadConverter(EncodingPayloadConverter):
7269
def __init__(self):
7370
self.context: Optional[SerializationContext] = None
7471

@@ -133,9 +130,7 @@ def from_payload(
133130
return value
134131

135132

136-
class SerializationContextCompositePayloadConverter(
137-
CompositePayloadConverter, WithSerializationContext
138-
):
133+
class SerializationContextCompositePayloadConverter(CompositePayloadConverter):
139134
def __init__(self):
140135
super().__init__(
141136
SerializationContextPayloadConverter(),
@@ -1000,7 +995,7 @@ async def run(self) -> Never:
1000995
test_traces: dict[str, list[TraceItem]] = defaultdict(list)
1001996

1002997

1003-
class FailureConverterWithContext(DefaultFailureConverter, WithSerializationContext):
998+
class FailureConverterWithContext(DefaultFailureConverter):
1004999
def __init__(self):
10051000
super().__init__(encode_common_attributes=False)
10061001
self.context: Optional[SerializationContext] = None
@@ -1131,7 +1126,7 @@ async def test_failure_converter_with_context(client: Client):
11311126
# Test payload codec
11321127

11331128

1134-
class PayloadCodecWithContext(PayloadCodec, WithSerializationContext):
1129+
class PayloadCodecWithContext(PayloadCodec):
11351130
def __init__(self):
11361131
self.context: Optional[SerializationContext] = None
11371132
self.encode_called_with_context = False
@@ -1432,7 +1427,7 @@ async def test_child_workflow_codec_with_context(client: Client):
14321427
# Payload codec: test decode context matches encode context
14331428

14341429

1435-
class PayloadEncryptionCodec(PayloadCodec, WithSerializationContext):
1430+
class PayloadEncryptionCodec(PayloadCodec):
14361431
"""
14371432
The outbound data for encoding must always be the string "outbound". "Encrypt" it by replacing
14381433
it with a key that is derived from the context available during encoding. On decryption, assert
@@ -1597,7 +1592,7 @@ async def test_decode_context_matches_encode_context(
15971592
# Test nexus payload codec
15981593

15991594

1600-
class AssertNexusLacksContextPayloadCodec(PayloadCodec, WithSerializationContext):
1595+
class AssertNexusLacksContextPayloadCodec(PayloadCodec):
16011596
def __init__(self):
16021597
self.context = None
16031598

@@ -1679,9 +1674,7 @@ class PydanticData(BaseModel):
16791674
trace: List[str] = []
16801675

16811676

1682-
class PydanticJSONConverterWithContext(
1683-
PydanticJSONPlainPayloadConverter, WithSerializationContext
1684-
):
1677+
class PydanticJSONConverterWithContext(PydanticJSONPlainPayloadConverter):
16851678
def __init__(self):
16861679
super().__init__()
16871680
self.context: Optional[SerializationContext] = None
@@ -1700,7 +1693,7 @@ def to_payload(self, value: Any) -> Optional[temporalio.api.common.v1.Payload]:
17001693
return super().to_payload(value)
17011694

17021695

1703-
class PydanticConverterWithContext(CompositePayloadConverter, WithSerializationContext):
1696+
class PydanticConverterWithContext(CompositePayloadConverter):
17041697
def __init__(self):
17051698
super().__init__(
17061699
*(
@@ -1758,9 +1751,7 @@ class UserMethodCalledError(Exception):
17581751
pass
17591752

17601753

1761-
class CustomEncodingPayloadConverter(
1762-
JSONPlainPayloadConverter, WithSerializationContext
1763-
):
1754+
class CustomEncodingPayloadConverter(JSONPlainPayloadConverter):
17641755
@property
17651756
def encoding(self) -> str:
17661757
return "custom-encoding-that-does-not-clash-with-default-converters"

0 commit comments

Comments
 (0)