Skip to content

Commit edcd5b9

Browse files
committed
Fix circular import: do not import temporalio.client in temporalio.nexus
1 parent 1fec723 commit edcd5b9

File tree

7 files changed

+46
-43
lines changed

7 files changed

+46
-43
lines changed

temporalio/client.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import temporalio.common
5656
import temporalio.converter
5757
import temporalio.exceptions
58+
import temporalio.nexus
5859
import temporalio.runtime
5960
import temporalio.service
6061
import temporalio.workflow
@@ -7319,23 +7320,8 @@ def api_key(self, value: Optional[str]) -> None:
73197320
self.service_client.update_api_key(value)
73207321

73217322

7322-
@dataclass(frozen=True)
7323-
class NexusCallback:
7324-
"""Nexus callback to attach to events such as workflow completion.
7325-
7326-
.. warning::
7327-
This API is experimental and unstable.
7328-
"""
7329-
7330-
url: str
7331-
"""Callback URL."""
7332-
7333-
headers: Mapping[str, str]
7334-
"""Header to attach to callback request."""
7335-
7336-
73377323
# Intended to become a union of callback types
7338-
Callback = NexusCallback
7324+
Callback = temporalio.nexus.NexusCallback
73397325

73407326

73417327
async def _encode_user_metadata(

temporalio/nexus/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from ._decorators import workflow_run_operation as workflow_run_operation
1010
from ._operation_context import Info as Info
1111
from ._operation_context import LoggerAdapter as LoggerAdapter
12+
from ._operation_context import NexusCallback as NexusCallback
1213
from ._operation_context import (
1314
WorkflowRunOperationContext as WorkflowRunOperationContext,
1415
)

temporalio/nexus/_decorators.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,10 @@
1616
StartOperationContext,
1717
)
1818

19-
from temporalio.nexus._operation_context import (
20-
WorkflowRunOperationContext,
21-
)
22-
from temporalio.nexus._operation_handlers import (
23-
WorkflowRunOperationHandler,
24-
)
25-
from temporalio.nexus._token import (
26-
WorkflowHandle,
27-
)
28-
from temporalio.nexus._util import (
19+
from ._operation_context import WorkflowRunOperationContext
20+
from ._operation_handlers import WorkflowRunOperationHandler
21+
from ._token import WorkflowHandle
22+
from ._util import (
2923
get_callable_name,
3024
get_workflow_run_start_method_input_and_output_type_annotations,
3125
set_operation_factory,

temporalio/nexus/_link_conversion.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import urllib.parse
66
from typing import (
7+
TYPE_CHECKING,
78
Any,
89
Optional,
910
)
@@ -12,7 +13,9 @@
1213

1314
import temporalio.api.common.v1
1415
import temporalio.api.enums.v1
15-
import temporalio.client
16+
17+
if TYPE_CHECKING:
18+
import temporalio.client
1619

1720
logger = logging.getLogger(__name__)
1821

temporalio/nexus/_operation_context.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from dataclasses import dataclass
88
from datetime import timedelta
99
from typing import (
10+
TYPE_CHECKING,
1011
Any,
1112
Callable,
1213
Optional,
@@ -19,7 +20,6 @@
1920

2021
import temporalio.api.common.v1
2122
import temporalio.api.workflowservice.v1
22-
import temporalio.client
2323
import temporalio.common
2424
from temporalio.nexus import _link_conversion
2525
from temporalio.nexus._token import WorkflowHandle
@@ -32,6 +32,9 @@
3232
SelfType,
3333
)
3434

35+
if TYPE_CHECKING:
36+
import temporalio.client
37+
3538
# The Temporal Nexus worker always builds a nexusrpc StartOperationContext or
3639
# CancelOperationContext and passes it as the first parameter to the nexusrpc operation
3740
# handler. In addition, it sets one of the following context vars.
@@ -122,7 +125,7 @@ def _get_callbacks(
122125
ctx = self.nexus_context
123126
return (
124127
[
125-
temporalio.client.NexusCallback(
128+
NexusCallback(
126129
url=ctx.callback_url,
127130
headers=ctx.callback_headers,
128131
)
@@ -449,6 +452,21 @@ async def start_workflow(
449452
return WorkflowHandle[ReturnType]._unsafe_from_client_workflow_handle(wf_handle)
450453

451454

455+
@dataclass(frozen=True)
456+
class NexusCallback:
457+
"""Nexus callback to attach to events such as workflow completion.
458+
459+
.. warning::
460+
This API is experimental and unstable.
461+
"""
462+
463+
url: str
464+
"""Callback URL."""
465+
466+
headers: Mapping[str, str]
467+
"""Header to attach to callback request."""
468+
469+
452470
@dataclass(frozen=True)
453471
class _TemporalCancelOperationContext:
454472
"""Context for a Nexus cancel operation being handled by a Temporal Nexus Worker."""

temporalio/nexus/_operation_handlers.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
StartOperationResultAsync,
2525
)
2626

27-
from temporalio import client
2827
from temporalio.nexus._operation_context import (
2928
_temporal_cancel_operation_context,
3029
)
@@ -73,15 +72,14 @@ async def start(
7372
"""Start the operation, by starting a workflow and completing asynchronously."""
7473
handle = await self._start(ctx, input)
7574
if not isinstance(handle, WorkflowHandle):
76-
if isinstance(handle, client.WorkflowHandle):
77-
raise RuntimeError(
78-
f"Expected {handle} to be a nexus.WorkflowHandle, but got a client.WorkflowHandle. "
79-
f"You must use WorkflowRunOperationContext.start_workflow "
80-
"to start a workflow that will deliver the result of the Nexus operation, "
81-
"not client.Client.start_workflow."
82-
)
8375
raise RuntimeError(
8476
f"Expected {handle} to be a nexus.WorkflowHandle, but got {type(handle)}. "
77+
f"When using @workflow_run_operation you must use "
78+
"WorkflowRunOperationContext.start_workflow() "
79+
"to start a workflow that will deliver the result of the Nexus operation, "
80+
"and you must return the nexus.WorkflowHandle that it returns. "
81+
"It is not possible to use client.Client.start_workflow() and client.WorkflowHandle "
82+
"for this purpose."
8583
)
8684
return StartOperationResultAsync(handle.to_token())
8785

temporalio/nexus/_token.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
import base64
44
import json
55
from dataclasses import dataclass
6-
from typing import Any, Generic, Literal, Optional, Type
6+
from typing import TYPE_CHECKING, Any, Generic, Literal, Optional
77

88
from nexusrpc import OutputT
99

10-
from temporalio import client
11-
1210
OperationTokenType = Literal[1]
1311
OPERATION_TOKEN_TYPE_WORKFLOW: OperationTokenType = 1
1412

13+
if TYPE_CHECKING:
14+
import temporalio.client
15+
1516

1617
@dataclass(frozen=True)
1718
class WorkflowHandle(Generic[OutputT]):
@@ -32,8 +33,10 @@ class WorkflowHandle(Generic[OutputT]):
3233
version: Optional[int] = None
3334

3435
def _to_client_workflow_handle(
35-
self, client: client.Client, result_type: Optional[Type[OutputT]] = None
36-
) -> client.WorkflowHandle[Any, OutputT]:
36+
self,
37+
client: temporalio.client.Client,
38+
result_type: Optional[type[OutputT]] = None,
39+
) -> temporalio.client.WorkflowHandle[Any, OutputT]:
3740
"""Create a :py:class:`temporalio.client.WorkflowHandle` from the token."""
3841
if client.namespace != self.namespace:
3942
raise ValueError(
@@ -46,7 +49,7 @@ def _to_client_workflow_handle(
4649
# handle type.
4750
@classmethod
4851
def _unsafe_from_client_workflow_handle(
49-
cls, workflow_handle: client.WorkflowHandle[Any, OutputT]
52+
cls, workflow_handle: temporalio.client.WorkflowHandle[Any, OutputT]
5053
) -> WorkflowHandle[OutputT]:
5154
"""Create a :py:class:`WorkflowHandle` from a :py:class:`temporalio.client.WorkflowHandle`.
5255

0 commit comments

Comments
 (0)