Skip to content

Commit aedd91e

Browse files
committed
Add client type errors test
1 parent 4eceb4a commit aedd91e

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed

tests/test_client_type_errors.py

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
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+
pass
78+
79+
80+
async def test_start_and_execute_workflow_type_errors():
81+
client = Client(service_client=Mock(spec=ServiceClient))
82+
83+
# Good
84+
_handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
85+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
86+
)
87+
88+
# id and task_queue are required
89+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
90+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "workflow" of type "str"'
91+
await client.start_workflow(TestWorkflow.run, id="wid", task_queue="tq") # type: ignore
92+
# assert-type-error-pyright: 'No overloads for "start_workflow" match'
93+
await client.start_workflow(
94+
TestWorkflow.run,
95+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
96+
SignalInput(), # type: ignore
97+
id="wid",
98+
task_queue="tq",
99+
)
100+
101+
# Good
102+
_output: WorkflowOutput = await client.execute_workflow(
103+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
104+
)
105+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
106+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "workflow" of type "str"'
107+
await client.execute_workflow(TestWorkflow.run, id="wid", task_queue="tq") # type: ignore
108+
# assert-type-error-pyright: 'No overloads for "execute_workflow" match'
109+
await client.execute_workflow(
110+
TestWorkflow.run,
111+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
112+
SignalInput(), # type: ignore
113+
id="wid",
114+
task_queue="tq",
115+
)
116+
117+
118+
async def test_signal_type_errors():
119+
client = Client(service_client=Mock(spec=ServiceClient))
120+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
121+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
122+
)
123+
124+
# Good
125+
await handle.signal(TestWorkflow.signal, SignalInput())
126+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
127+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "signal" of type "str"'
128+
await handle.signal(TestWorkflow.signal) # type: ignore
129+
130+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
131+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "signal" of type "str"'
132+
await handle.signal(TestWorkflow2.signal, SignalInput()) # type: ignore
133+
134+
135+
async def test_query_type_errors():
136+
client = Client(service_client=Mock(spec=ServiceClient))
137+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
138+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
139+
)
140+
# Good
141+
_: QueryOutput = await handle.query(TestWorkflow.query, QueryInput())
142+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
143+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "query" of type "str"'
144+
await handle.query(TestWorkflow.query) # type: ignore
145+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
146+
await handle.query(TestWorkflow.query, SignalInput()) # type: ignore
147+
148+
# TODO: this type error is misleading: it's resolving to an unexpected overload.
149+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "query" of type "str"'
150+
await handle.query(TestWorkflow2.query, QueryInput()) # type: ignore
151+
152+
153+
async def test_start_and_execute_update_type_errors():
154+
client = Client(service_client=Mock(spec=ServiceClient))
155+
handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow(
156+
TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq"
157+
)
158+
159+
# Good
160+
_handle: WorkflowUpdateHandle[UpdateOutput] = await handle.start_update(
161+
TestWorkflow.update, UpdateInput(), wait_for_stage=WorkflowUpdateStage.ACCEPTED
162+
)
163+
# wait_for_stage is required
164+
# assert-type-error-pyright: 'No overloads for "start_update" match'
165+
await handle.start_update(TestWorkflow.update, UpdateInput()) # type: ignore
166+
167+
# assert-type-error-pyright: 'No overloads for "start_update" match the provided arguments'
168+
await handle.start_update(TestWorkflow2.update, UpdateInput()) # type: ignore
169+
170+
# Good
171+
_result: UpdateOutput = await handle.execute_update(
172+
TestWorkflow.update, UpdateInput()
173+
)
174+
# assert-type-error-pyright: 'No overloads for "execute_update" match'
175+
await handle.execute_update(
176+
TestWorkflow.update,
177+
wait_for_stage=WorkflowUpdateStage.ACCEPTED, # type: ignore
178+
)
179+
# assert-type-error-pyright: 'Argument of type "SignalInput" cannot be assigned to parameter'
180+
await handle.execute_update(TestWorkflow.update, SignalInput()) # type: ignore
181+
182+
# TODO: this type error is misleading: it's resolving to an unecpected overload.
183+
# assert-type-error-pyright: 'Argument of type .+ cannot be assigned to parameter "update" of type "str"'
184+
await handle.execute_update(TestWorkflow2.update, UpdateInput()) # type: ignore
185+
186+
187+
async def test_start_and_execute_update_with_start_type_errors():
188+
client = Client(service_client=Mock(spec=ServiceClient))
189+
190+
# Good
191+
with_start = WithStartWorkflowOperation(
192+
TestWorkflow.run,
193+
WorkflowInput(),
194+
id="wid",
195+
task_queue="tq",
196+
id_conflict_policy=WorkflowIDConflictPolicy.USE_EXISTING,
197+
)
198+
_update_handle: WorkflowUpdateHandle[
199+
UpdateOutput
200+
] = await client.start_update_with_start_workflow(
201+
TestWorkflow.update,
202+
UpdateInput(),
203+
wait_for_stage=WorkflowUpdateStage.ACCEPTED,
204+
start_workflow_operation=with_start,
205+
)
206+
_update_result: UpdateOutput = await _update_handle.result()
207+
208+
_wf_handle: WorkflowHandle[
209+
TestWorkflow, WorkflowOutput
210+
] = await with_start.workflow_handle()
211+
212+
_wf_result: WorkflowOutput = await _wf_handle.result()
213+
214+
# id_conflict_policy is required
215+
# assert-type-error-pyright: 'No overloads for "__init__" match'
216+
with_start = WithStartWorkflowOperation( # type: ignore
217+
TestWorkflow.run,
218+
WorkflowInput(),
219+
id="wid",
220+
task_queue="tq",
221+
)
222+
223+
# wait_for_stage is required
224+
# assert-type-error-pyright: 'No overloads for "start_update_with_start_workflow" match'
225+
await client.start_update_with_start_workflow( # type: ignore
226+
TestWorkflow.update, UpdateInput(), start_workflow_operation=with_start
227+
)
228+
229+
# Good
230+
_update_result_2: UpdateOutput = await client.execute_update_with_start_workflow(
231+
TestWorkflow.update,
232+
UpdateInput(),
233+
start_workflow_operation=with_start,
234+
)
235+
236+
# cannot supply wait_for_stage
237+
# assert-type-error-pyright: 'No overloads for "execute_update_with_start_workflow" match'
238+
await client.execute_update_with_start_workflow( # type: ignore
239+
TestWorkflow.update,
240+
UpdateInput(),
241+
start_workflow_operation=with_start,
242+
wait_for_stage=WorkflowUpdateStage.ACCEPTED,
243+
)

0 commit comments

Comments
 (0)