Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
95fc943
implement standalone nexus operations
VegetarianOrc Apr 16, 2026
30636bf
Move nexus operation polling to an interceptable client method. Add i…
VegetarianOrc Apr 17, 2026
9364c23
Add test demonstrating error chain. Ensure that failures are wrapped …
VegetarianOrc Apr 17, 2026
325d8bc
Run uv sync after rebase
VegetarianOrc Apr 17, 2026
a922015
Make result_type take precedence in get_nexus_operation_handle to mat…
VegetarianOrc Apr 20, 2026
ca355da
Add caching of failures for NexusOperationHandle
VegetarianOrc Apr 22, 2026
153a1f8
Consistency pass on models from proto. Expose long_poll_token
VegetarianOrc Apr 23, 2026
c06c023
expose user metadata. some type fixes
VegetarianOrc Apr 24, 2026
9b3aaa2
Address findings/suggestions from claude
VegetarianOrc Apr 24, 2026
4e4ebf5
merge main
VegetarianOrc Apr 29, 2026
4fb10ff
generate protos. Update bridge dependency to reference the right vers…
VegetarianOrc Apr 30, 2026
7ec5eb1
Merge branch 'main' into amazzeo/sano
VegetarianOrc Apr 30, 2026
8e36478
enable start_delay for SAA in test server config
VegetarianOrc Apr 30, 2026
046ab9c
Fix warning spam about invalid workflow event links by filtering nexu…
VegetarianOrc Apr 30, 2026
ca3ce68
merge main
VegetarianOrc Apr 30, 2026
96fe387
skip sano tests on the time skipping server
VegetarianOrc May 1, 2026
aff41de
Fix typo
VegetarianOrc May 1, 2026
3ccf191
Fix typo in docstring
VegetarianOrc May 1, 2026
de948fe
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 1, 2026
2a0fa88
Update docstring to not use parens
VegetarianOrc May 1, 2026
3a7b65c
Respect service decorator field 'name' in sano client. add test verif…
VegetarianOrc May 4, 2026
8de85fa
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 7, 2026
519dfb2
Remove dynamic config that isn't ready yet
VegetarianOrc May 11, 2026
06aa00e
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 11, 2026
c66a95d
forward long poll token to describe requests properly
VegetarianOrc May 11, 2026
d16eae8
Thread timeouts through sano
VegetarianOrc May 11, 2026
bc38a72
Remove overloads that allowed omission of operation input. Add some t…
VegetarianOrc May 11, 2026
b2aa8fb
run formatter
VegetarianOrc May 12, 2026
fa291b6
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 12, 2026
fee1d77
Define NexusServiceType in types.py and use in both workflow and clie…
VegetarianOrc May 12, 2026
63e1138
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 12, 2026
951e5b8
Fix some docstrings. Remove unecessary check for workflow event link …
VegetarianOrc May 13, 2026
7c90618
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 13, 2026
eeb34bc
Narrow assertions in sano describe test
VegetarianOrc May 13, 2026
52c9496
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 15, 2026
a5368b4
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 18, 2026
a5882cc
Update core to the commit that main is pointing at
VegetarianOrc May 18, 2026
3f811de
Remove kwarg requirement for endpoint arg in create_nexus_client
VegetarianOrc May 18, 2026
dac838a
Merge main
VegetarianOrc May 18, 2026
290d31f
merge main
VegetarianOrc May 18, 2026
f17fe28
run formatter and address linter
VegetarianOrc May 18, 2026
3eac09a
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 18, 2026
c5243b7
Remove unrelated changes to operation context and link conversion
VegetarianOrc May 19, 2026
b2bd5ea
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 19, 2026
7d02d62
Revert "Remove unrelated changes to operation context and link conver…
VegetarianOrc May 19, 2026
d528452
Add support for nexus operation links, include temporary filter to av…
VegetarianOrc May 19, 2026
3131d44
Merge branch 'main' into amazzeo/sano
VegetarianOrc May 19, 2026
fbc5a57
Add github issue link in link workaround. Remove long poll token from…
VegetarianOrc May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ lambda-worker-otel = [
"opentelemetry-semantic-conventions>=0.40b0,<1",
"opentelemetry-sdk-extension-aws>=2.0.0,<3",
]
aioboto3 = [
"aioboto3>=10.4.0",
"types-aioboto3[s3]>=10.4.0",
]
aioboto3 = ["aioboto3>=10.4.0", "types-aioboto3[s3]>=10.4.0"]

[project.urls]
Homepage = "https://github.com/temporalio/sdk-python"
Expand Down Expand Up @@ -86,6 +83,7 @@ dev = [
"opentelemetry-exporter-otlp-proto-grpc>=1.11.1,<2",
"opentelemetry-semantic-conventions>=0.40b0,<1",
"opentelemetry-sdk-extension-aws>=2.0.0,<3",
"pytest-flakefinder>=1.1.0",
"async-timeout>=4.0,<6; python_version < '3.11'",
]

Expand Down
34 changes: 34 additions & 0 deletions temporalio/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,22 +90,27 @@
from ._interceptor import (
BackfillScheduleInput,
CancelActivityInput,
CancelNexusOperationInput,
CancelWorkflowInput,
CompleteAsyncActivityInput,
CountActivitiesInput,
CountNexusOperationsInput,
CountWorkflowsInput,
CreateScheduleInput,
DeleteScheduleInput,
DescribeActivityInput,
DescribeNexusOperationInput,
DescribeScheduleInput,
DescribeWorkflowInput,
FailAsyncActivityInput,
FetchWorkflowHistoryEventsInput,
GetNexusOperationResultInput,
GetWorkerBuildIdCompatibilityInput,
GetWorkerTaskReachabilityInput,
HeartbeatAsyncActivityInput,
Interceptor,
ListActivitiesInput,
ListNexusOperationsInput,
ListSchedulesInput,
ListWorkflowsInput,
OutboundInterceptor,
Expand All @@ -114,10 +119,12 @@
ReportCancellationAsyncActivityInput,
SignalWorkflowInput,
StartActivityInput,
StartNexusOperationInput,
StartWorkflowInput,
StartWorkflowUpdateInput,
StartWorkflowUpdateWithStartInput,
TerminateActivityInput,
TerminateNexusOperationInput,
TerminateWorkflowInput,
TriggerScheduleInput,
UnpauseScheduleInput,
Expand All @@ -126,6 +133,17 @@
UpdateWithStartUpdateWorkflowInput,
UpdateWorkerBuildIdCompatibilityInput,
)
from ._nexus import (
NexusClient,
NexusOperationExecution,
NexusOperationExecutionAsyncIterator,
NexusOperationExecutionCancellationInfo,
NexusOperationExecutionCount,
NexusOperationExecutionCountAggregationGroup,
NexusOperationExecutionDescription,
NexusOperationFailureError,
NexusOperationHandle,
)
from ._plugin import (
Plugin,
)
Expand Down Expand Up @@ -213,6 +231,14 @@
"AsyncActivityIDReference",
"AsyncActivityHandle",
"ActivityHandle",
"NexusClient",
"NexusOperationExecution",
"NexusOperationExecutionAsyncIterator",
"NexusOperationExecutionCancellationInfo",
"NexusOperationExecutionCount",
"NexusOperationExecutionCountAggregationGroup",
"NexusOperationExecutionDescription",
"NexusOperationHandle",
"ScheduleHandle",
"ScheduleSpec",
"ScheduleRange",
Expand Down Expand Up @@ -248,6 +274,7 @@
"WorkflowUpdateRPCTimeoutOrCancelledError",
"ActivityFailureError",
"AsyncActivityCancelledError",
"NexusOperationFailureError",
"ScheduleAlreadyRunningError",
"StartWorkflowInput",
"CancelWorkflowInput",
Expand All @@ -264,6 +291,13 @@
"DescribeActivityInput",
"ListActivitiesInput",
"CountActivitiesInput",
"StartNexusOperationInput",
"DescribeNexusOperationInput",
"GetNexusOperationResultInput",
"CancelNexusOperationInput",
"TerminateNexusOperationInput",
"ListNexusOperationsInput",
"CountNexusOperationsInput",
"StartWorkflowUpdateInput",
"UpdateWithStartUpdateWorkflowInput",
"UpdateWithStartStartWorkflowInput",
Expand Down
169 changes: 165 additions & 4 deletions temporalio/client/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
overload,
)

import nexusrpc
from nexusrpc import OutputT
from typing_extensions import Required, Self, TypedDict

import temporalio.activity
Expand Down Expand Up @@ -47,6 +49,7 @@
MethodAsyncNoParam,
MethodAsyncSingleParam,
MultiParamSpec,
NexusServiceType,
ParamType,
ReturnType,
SelfType,
Expand All @@ -62,11 +65,13 @@
from ._impl import _ClientImpl
from ._interceptor import (
CountActivitiesInput,
CountNexusOperationsInput,
CountWorkflowsInput,
CreateScheduleInput,
GetWorkerBuildIdCompatibilityInput,
GetWorkerTaskReachabilityInput,
ListActivitiesInput,
ListNexusOperationsInput,
ListSchedulesInput,
ListWorkflowsInput,
OutboundInterceptor,
Expand All @@ -76,6 +81,13 @@
UpdateWithStartUpdateWorkflowInput,
UpdateWorkerBuildIdCompatibilityInput,
)
from ._nexus import (
NexusClient,
NexusOperationExecutionAsyncIterator,
NexusOperationExecutionCount,
NexusOperationHandle,
_NexusClient,
)
from ._schedule import (
Schedule,
ScheduleAsyncIterator,
Expand Down Expand Up @@ -541,9 +553,7 @@ async def start_workflow(
# are deliberately not exposed in overloads, and are not subject to any
# backwards compatibility guarantees.
callbacks: Sequence[Callback] = [],
workflow_event_links: Sequence[
temporalio.api.common.v1.Link.WorkflowEvent
] = [],
links: Sequence[temporalio.api.common.v1.Link] = [],
request_id: str | None = None,
stack_level: int = 2,
) -> WorkflowHandle[Any, Any]:
Expand Down Expand Up @@ -637,7 +647,7 @@ async def start_workflow(
request_eager_start=request_eager_start,
priority=priority,
callbacks=callbacks,
workflow_event_links=workflow_event_links,
links=links,
request_id=request_id,
)
)
Expand Down Expand Up @@ -2859,6 +2869,157 @@ async def get_worker_task_reachability(
)
)

def create_nexus_client(
self,
service: type[NexusServiceType] | str,
endpoint: str,
) -> NexusClient[NexusServiceType]:
"""Create a client for starting standalone Nexus operations.

.. warning::
This API is experimental and unstable.

Args:
service: The Nexus service type or service name string.
endpoint: Endpoint name, resolved to a URL via the cluster's
endpoint registry.

Returns:
A Nexus client for the given service and endpoint.
"""
return _NexusClient(client=self, service=service, endpoint=endpoint)

def list_nexus_operations(
self,
query: str,
*,
limit: int | None = None,
page_size: int = 1000,
next_page_token: bytes | None = None,
rpc_metadata: Mapping[str, str | bytes] = {},
rpc_timeout: timedelta | None = None,
) -> NexusOperationExecutionAsyncIterator:
"""List standalone Nexus operations.

.. warning::
This API is experimental and unstable.

This does not make a request until the first iteration is attempted.
Therefore any errors will not occur until then.

Args:
query: A Temporal visibility list filter for nexus operations. Required.
limit: Maximum number of operations to return. If unset, all
operations are returned. Only applies if using the
returned :py:class:`NexusOperationExecutionAsyncIterator`
as an async iterator.
page_size: Maximum number of results for each page.
next_page_token: A previously obtained next page token if doing
pagination. Usually not needed as the iterator automatically
starts from the beginning.
rpc_metadata: Headers used on each RPC call. Keys here override
client-level RPC metadata keys.
rpc_timeout: Optional RPC deadline to set for each RPC call.

Returns:
An async iterator that can be used with ``async for``.
"""
return self._impl.list_nexus_operations(
ListNexusOperationsInput(
query=query,
page_size=page_size,
next_page_token=next_page_token,
rpc_metadata=rpc_metadata,
rpc_timeout=rpc_timeout,
limit=limit,
)
)

async def count_nexus_operations(
self,
query: str | None = None,
*,
rpc_metadata: Mapping[str, str | bytes] = {},
rpc_timeout: timedelta | None = None,
) -> NexusOperationExecutionCount:
"""Count standalone Nexus operations.

.. warning::
This API is experimental and unstable.

Args:
query: A Temporal visibility filter for nexus operations.
rpc_metadata: Headers used on the RPC call. Keys here override
client-level RPC metadata keys.
rpc_timeout: Optional RPC deadline to set for the RPC call.

Returns:
Count of nexus operations.
"""
return await self._impl.count_nexus_operations(
CountNexusOperationsInput(
query=query, rpc_metadata=rpc_metadata, rpc_timeout=rpc_timeout
)
)

@overload
def get_nexus_operation_handle(
self,
operation_id: str,
*,
run_id: str | None = None,
) -> NexusOperationHandle[Any]: ...

@overload
def get_nexus_operation_handle(
self,
operation_id: str,
*,
run_id: str | None = None,
result_type: type[ReturnType],
) -> NexusOperationHandle[ReturnType]: ...

@overload
def get_nexus_operation_handle(
self,
operation_id: str,
*,
operation: nexusrpc.Operation[Any, OutputT],
run_id: str | None = None,
) -> NexusOperationHandle[OutputT]: ...

def get_nexus_operation_handle(
self,
operation_id: str,
*,
operation: nexusrpc.Operation[Any, Any] | None = None,
run_id: str | None = None,
result_type: type | None = None,
) -> NexusOperationHandle[Any]:
"""Get a handle to an existing standalone Nexus operation.

.. warning::
This API is experimental and unstable.

Args:
operation_id: The operation ID.
operation: A ``nexusrpc.Operation`` from which the result type
is extracted. If both ``operation`` and ``result_type`` are
provided, the ``result_type`` takes precedence.
run_id: The operation run ID. If not provided, targets the latest run.
result_type: The result type to deserialize into.

Returns:
A handle to the operation.
"""
result_type = result_type or (operation.output_type if operation else None)
return NexusOperationHandle(
self,
operation_id,
run_id=run_id,
result_type=result_type,
)


class ClientConnectConfig(TypedDict, total=False):
"""TypedDict of keyword arguments for :py:meth:`Client.connect`."""
Expand Down
Loading
Loading