Skip to content

Commit 4ad6bea

Browse files
committed
Add client type errors test
1 parent 602875e commit 4ad6bea

File tree

1 file changed

+245
-0
lines changed

1 file changed

+245
-0
lines changed

tests/test_client_type_errors.py

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
"""
2+
This file exists to test for type-checker false positives and false negatives.
3+
It doesn't contain any test functions.
4+
"""
5+
6+
from dataclasses import dataclass
7+
from unittest.mock import Mock
8+
9+
from temporalio import workflow
10+
from temporalio.client import (
11+
Client,
12+
WithStartWorkflowOperation,
13+
WorkflowHandle,
14+
WorkflowUpdateHandle,
15+
WorkflowUpdateStage,
16+
)
17+
from temporalio.common import WorkflowIDConflictPolicy
18+
from temporalio.service import ServiceClient
19+
20+
21+
@dataclass
22+
class WorkflowInput:
23+
pass
24+
25+
26+
@dataclass
27+
class SignalInput:
28+
pass
29+
30+
31+
@dataclass
32+
class QueryInput:
33+
pass
34+
35+
36+
@dataclass
37+
class UpdateInput:
38+
pass
39+
40+
41+
@dataclass
42+
class WorkflowOutput:
43+
pass
44+
45+
46+
@dataclass
47+
class QueryOutput:
48+
pass
49+
50+
51+
@dataclass
52+
class UpdateOutput:
53+
pass
54+
55+
56+
@workflow.defn
57+
class TestWorkflow:
58+
@workflow.run
59+
async def run(self, _: WorkflowInput) -> WorkflowOutput:
60+
return WorkflowOutput()
61+
62+
@workflow.signal
63+
async def signal(self, _: SignalInput) -> None:
64+
pass
65+
66+
@workflow.query
67+
async def query(self, _: QueryInput) -> QueryOutput:
68+
return QueryOutput()
69+
70+
@workflow.update
71+
async def update(self, _: UpdateInput) -> UpdateOutput:
72+
return UpdateOutput()
73+
74+
75+
@workflow.defn
76+
class TestWorkflow2(TestWorkflow):
77+
@workflow.run
78+
async def run(self, _: WorkflowInput) -> WorkflowOutput:
79+
return WorkflowOutput()
80+
81+
82+
async def _test_start_and_execute_workflow_type_errors():
83+
client = Client(service_client=Mock(spec=ServiceClient))
84+
85+
# Good
86+
_handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
87+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
88+
)
89+
90+
# id and task_queue are required
91+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
92+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "workflow" of type "str"'
93+
await client.start_workflow(TestWorkflow.run, id="wid", task_queue="tq") # type: ignore
94+
# assert-type-error-pyright: 'No overloads for "start_workflow" match'
95+
await client.start_workflow(
96+
TestWorkflow.run,
97+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
98+
SignalInput(), # type: ignore
99+
id="wid",
100+
task_queue="tq",
101+
)
102+
103+
# Good
104+
_output: WorkflowOutput = await client.execute_workflow(
105+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
106+
)
107+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
108+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "workflow" of type "str"'
109+
await client.execute_workflow(TestWorkflow.run, id="wid", task_queue="tq") # type: ignore
110+
# assert-type-error-pyright: 'No overloads for "execute_workflow" match'
111+
await client.execute_workflow(
112+
TestWorkflow.run,
113+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
114+
SignalInput(), # type: ignore
115+
id="wid",
116+
task_queue="tq",
117+
)
118+
119+
120+
async def _test_signal_type_errors():
121+
client = Client(service_client=Mock(spec=ServiceClient))
122+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
123+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
124+
)
125+
126+
# Good
127+
await handle.signal(TestWorkflow.signal, SignalInput())
128+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
129+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "signal" of type "str"'
130+
await handle.signal(TestWorkflow.signal) # type: ignore
131+
132+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
133+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "signal" of type "str"'
134+
await handle.signal(TestWorkflow2.signal, SignalInput()) # type: ignore
135+
136+
137+
async def _test_query_type_errors():
138+
client = Client(service_client=Mock(spec=ServiceClient))
139+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
140+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
141+
)
142+
# Good
143+
_: QueryOutput = await handle.query(TestWorkflow.query, QueryInput())
144+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
145+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "query" of type "str"'
146+
await handle.query(TestWorkflow.query) # type: ignore
147+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
148+
await handle.query(TestWorkflow.query, SignalInput()) # type: ignore
149+
150+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
151+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "query" of type "str"'
152+
await handle.query(TestWorkflow2.query, QueryInput()) # type: ignore
153+
154+
155+
async def _test_start_and_execute_update_type_errors():
156+
client = Client(service_client=Mock(spec=ServiceClient))
157+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
158+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
159+
)
160+
161+
# Good
162+
_handle: WorkflowUpdateHandle[UpdateOutput] = await handle.start_update(
163+
TestWorkflow.update, UpdateInput(), wait_for_stage=WorkflowUpdateStage.ACCEPTED
164+
)
165+
# wait_for_stage is required
166+
# assert-type-error-pyright: 'No overloads for "start_update" match'
167+
await handle.start_update(TestWorkflow.update, UpdateInput()) # type: ignore
168+
169+
# assert-type-error-pyright: 'No overloads for "start_update" match the provided arguments'
170+
await handle.start_update(TestWorkflow2.update, UpdateInput()) # type: ignore
171+
172+
# Good
173+
_result: UpdateOutput = await handle.execute_update(
174+
TestWorkflow.update, UpdateInput()
175+
)
176+
# assert-type-error-pyright: 'No overloads for "execute_update" match'
177+
await handle.execute_update(
178+
TestWorkflow.update,
179+
wait_for_stage=WorkflowUpdateStage.ACCEPTED, # type: ignore
180+
)
181+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
182+
await handle.execute_update(TestWorkflow.update, SignalInput()) # type: ignore
183+
184+
# TODO: this type error is misleading: it's resolving to an unecpected overload.
185+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "update" of type "str"'
186+
await handle.execute_update(TestWorkflow2.update, UpdateInput()) # type: ignore
187+
188+
189+
async def _test_start_and_execute_update_with_start_type_errors():
190+
client = Client(service_client=Mock(spec=ServiceClient))
191+
192+
# Good
193+
with_start = WithStartWorkflowOperation(
194+
TestWorkflow.run,
195+
WorkflowInput(),
196+
id="wid",
197+
task_queue="tq",
198+
id_conflict_policy=WorkflowIDConflictPolicy.USE_EXISTING,
199+
)
200+
_update_handle: WorkflowUpdateHandle[
201+
UpdateOutput
202+
] = await client.start_update_with_start_workflow(
203+
TestWorkflow.update,
204+
UpdateInput(),
205+
wait_for_stage=WorkflowUpdateStage.ACCEPTED,
206+
start_workflow_operation=with_start,
207+
)
208+
_update_result: UpdateOutput = await _update_handle.result()
209+
210+
_wf_handle: WorkflowHandle[
211+
TestWorkflow, WorkflowOutput
212+
] = await with_start.workflow_handle()
213+
214+
_wf_result: WorkflowOutput = await _wf_handle.result()
215+
216+
# id_conflict_policy is required
217+
# assert-type-error-pyright: 'No overloads for "__init__" match'
218+
with_start = WithStartWorkflowOperation( # type: ignore
219+
TestWorkflow.run,
220+
WorkflowInput(),
221+
id="wid",
222+
task_queue="tq",
223+
)
224+
225+
# wait_for_stage is required
226+
# assert-type-error-pyright: 'No overloads for "start_update_with_start_workflow" match'
227+
await client.start_update_with_start_workflow( # type: ignore
228+
TestWorkflow.update, UpdateInput(), start_workflow_operation=with_start
229+
)
230+
231+
# Good
232+
_update_result_2: UpdateOutput = await client.execute_update_with_start_workflow(
233+
TestWorkflow.update,
234+
UpdateInput(),
235+
start_workflow_operation=with_start,
236+
)
237+
238+
# cannot supply wait_for_stage
239+
# assert-type-error-pyright: 'No overloads for "execute_update_with_start_workflow" match'
240+
await client.execute_update_with_start_workflow( # type: ignore
241+
TestWorkflow.update,
242+
UpdateInput(),
243+
start_workflow_operation=with_start,
244+
wait_for_stage=WorkflowUpdateStage.ACCEPTED,
245+
)

0 commit comments

Comments
 (0)