Skip to content

Commit 6dd586c

Browse files
authored
Merge branch 'main' into docker-gen-protos-stderr
2 parents 0892325 + f03ddc2 commit 6dd586c

27 files changed

+2121
-1939
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,24 @@ jobs:
1616
strategy:
1717
fail-fast: false
1818
matrix:
19-
python: ["3.9", "3.13"]
19+
python: ["3.10", "3.14"]
2020
os: [ubuntu-latest, ubuntu-arm, macos-intel, macos-arm, windows-latest]
2121
include:
22-
# On 3.9 there is a problem with import errors caused by pytests' loader that surface due
23-
# to a bug in CPython (https://github.com/python/cpython/issues/91351), so we avoid using
24-
# the assert rewriter.
25-
- python: "3.9"
26-
pytestExtraArgs: "--assert=plain"
2722
- os: ubuntu-latest
28-
python: "3.13"
23+
python: "3.14"
2924
docsTarget: true
3025
cloudTestTarget: true
3126
openaiTestTarget: true
3227
clippyLinter: true
3328
- os: ubuntu-latest
34-
python: "3.9"
29+
python: "3.10"
3530
protoCheckTarget: true
3631
- os: ubuntu-arm
3732
runsOn: ubuntu-24.04-arm64-2-core
3833
- os: macos-intel
3934
runsOn: macos-15-intel
40-
# On 3.13.3 there is some issue with macOS intel where it hangs after pytest with some
41-
# test that may have a worker that cannot properly shutdown, but it does not occur on
42-
# other versions, platforms, etc. See https://github.com/temporalio/sdk-python/issues/834.
43-
- os: macos-intel
44-
python: "3.13"
45-
pythonOverride: "3.13.2"
4635
- os: macos-arm
4736
runsOn: macos-latest
48-
# On 3.13.5, python3.lib is missing for the linker
49-
- os: windows-latest
50-
python: "3.13"
51-
pythonOverride: "3.13.4"
5237
runs-on: ${{ matrix.runsOn || matrix.os }}
5338
steps:
5439
- uses: actions/checkout@v4
@@ -113,7 +98,7 @@ jobs:
11398
env:
11499
TEMPORAL_TEST_PROTO3: 1
115100
run: |
116-
uv add --python 3.9 "protobuf<4"
101+
uv add --python 3.10 "protobuf<4"
117102
uv sync --all-extras
118103
poe build-develop
119104
poe gen-protos

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,8 +1676,8 @@ worker = Worker(
16761676
### Workflow Replay
16771677

16781678
Given a workflow's history, it can be replayed locally to check for things like non-determinism errors. For example,
1679-
assuming `history_str` is populated with a JSON string history either exported from the web UI or from `tctl`, the
1680-
following function will replay it:
1679+
assuming `history_str` is populated with a JSON string history either exported from the web UI or from the
1680+
`Temporal CLI`, the following function will replay it:
16811681

16821682
```python
16831683
from temporalio.client import WorkflowHistory

pyproject.toml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "temporalio"
33
version = "1.18.1"
44
description = "Temporal.io Python SDK"
55
authors = [{ name = "Temporal Technologies Inc", email = "[email protected]" }]
6-
requires-python = ">=3.9"
6+
requires-python = ">=3.10"
77
readme = "README.md"
88
license = { file = "LICENSE" }
99
keywords = ["temporal", "workflow"]
@@ -14,15 +14,22 @@ dependencies = [
1414
"types-protobuf>=3.20",
1515
"typing-extensions>=4.2.0,<5",
1616
]
17+
classifiers = [
18+
"License :: OSI Approved :: MIT License",
19+
"Programming Language :: Python :: 3.10",
20+
"Programming Language :: Python :: 3.11",
21+
"Programming Language :: Python :: 3.12",
22+
"Programming Language :: Python :: 3.13",
23+
"Programming Language :: Python :: 3.14",
24+
]
1725

1826
[project.optional-dependencies]
1927
grpc = ["grpcio>=1.48.2,<2"]
2028
opentelemetry = ["opentelemetry-api>=1.11.1,<2", "opentelemetry-sdk>=1.11.1,<2"]
2129
pydantic = ["pydantic>=2.0.0,<3"]
2230
openai-agents = [
2331
"openai-agents>=0.3,<0.4",
24-
"eval-type-backport>=0.2.2; python_version < '3.10'",
25-
"mcp>=1.9.4, <2; python_version >= '3.10'",
32+
"mcp>=1.9.4, <2",
2633
]
2734

2835
[project.urls]
@@ -35,7 +42,7 @@ Documentation = "https://docs.temporal.io/docs/python"
3542
dev = [
3643
"cibuildwheel>=2.22.0,<3",
3744
"grpcio-tools>=1.48.2,<2",
38-
"mypy==1.4.1",
45+
"mypy==1.18.2",
3946
"mypy-protobuf>=3.3.0,<4",
4047
"psutil>=5.9.3,<6",
4148
"pydocstyle>=6.3.0,<7",
@@ -51,7 +58,8 @@ dev = [
5158
"pytest-cov>=6.1.1",
5259
"httpx>=0.28.1",
5360
"pytest-pretty>=1.3.0",
54-
"openai-agents[litellm]>=0.3,<0.4",
61+
"openai-agents>=0.3,<0.4; python_version >= '3.14'",
62+
"openai-agents[litellm]>=0.3,<0.4; python_version < '3.14'",
5563
"googleapis-common-protos==1.70.0",
5664
]
5765

@@ -112,7 +120,7 @@ filterwarnings = [
112120

113121
[tool.cibuildwheel]
114122
before-all = "pip install protoc-wheel-0"
115-
build = "cp39-win_amd64 cp39-manylinux_x86_64 cp39-manylinux_aarch64 cp39-macosx_x86_64 cp39-macosx_arm64"
123+
build = "cp310-win_amd64 cp310-manylinux_x86_64 cp310-manylinux_aarch64 cp310-macosx_x86_64 cp310-macosx_arm64"
116124
build-verbosity = 1
117125

118126
[tool.cibuildwheel.macos]

temporalio/bridge/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ futures = "0.3"
2222
prost = "0.13"
2323
pyo3 = { version = "0.25", features = [
2424
"extension-module",
25-
"abi3-py39",
25+
"abi3-py310",
2626
"anyhow",
2727
"multiple-pymethods",
2828
] }

temporalio/client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ async def execute_update_with_start_workflow(
942942
MultiParamSpec, LocalReturnType
943943
],
944944
*,
945-
args: MultiParamSpec.args, # pyright: ignore
945+
args: MultiParamSpec.args, # type: ignore
946946
start_workflow_operation: WithStartWorkflowOperation[SelfType, Any],
947947
id: Optional[str] = None,
948948
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
@@ -1061,7 +1061,7 @@ async def start_update_with_start_workflow(
10611061
MultiParamSpec, LocalReturnType
10621062
],
10631063
*,
1064-
args: MultiParamSpec.args, # pyright: ignore
1064+
args: MultiParamSpec.args, # type: ignore
10651065
start_workflow_operation: WithStartWorkflowOperation[SelfType, Any],
10661066
wait_for_stage: WorkflowUpdateStage,
10671067
id: Optional[str] = None,
@@ -2252,7 +2252,7 @@ async def execute_update(
22522252
MultiParamSpec, LocalReturnType
22532253
],
22542254
*,
2255-
args: MultiParamSpec.args, # pyright: ignore
2255+
args: MultiParamSpec.args, # type: ignore
22562256
id: Optional[str] = None,
22572257
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
22582258
rpc_timeout: Optional[timedelta] = None,
@@ -2353,7 +2353,7 @@ async def start_update(
23532353
MultiParamSpec, LocalReturnType
23542354
],
23552355
*,
2356-
args: MultiParamSpec.args, # pyright: ignore
2356+
args: MultiParamSpec.args, # type: ignore
23572357
wait_for_stage: WorkflowUpdateStage,
23582358
id: Optional[str] = None,
23592359
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
@@ -3355,7 +3355,7 @@ def from_json(
33553355
) -> WorkflowHistory:
33563356
"""Construct a WorkflowHistory from an ID and a json dump of history.
33573357
3358-
This is built to work both with Temporal UI/tctl JSON as well as
3358+
This is built to work both with Temporal UI/CLI JSON as well as
33593359
:py:meth:`to_json` even though they are slightly different.
33603360
33613361
Args:

temporalio/contrib/openai_agents/__init__.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,10 @@
88
Use with caution in production environments.
99
"""
1010

11-
# Best Effort mcp, as it is not supported on Python 3.9
12-
try:
13-
from temporalio.contrib.openai_agents._mcp import (
14-
StatefulMCPServerProvider,
15-
StatelessMCPServerProvider,
16-
)
17-
except ImportError:
18-
pass
19-
11+
from temporalio.contrib.openai_agents._mcp import (
12+
StatefulMCPServerProvider,
13+
StatelessMCPServerProvider,
14+
)
2015
from temporalio.contrib.openai_agents._model_parameters import ModelActivityParameters
2116
from temporalio.contrib.openai_agents._temporal_openai_agents import (
2217
OpenAIAgentsPlugin,

temporalio/contrib/openai_agents/_temporal_openai_agents.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,6 @@
4747
from temporalio.worker import WorkflowRunner
4848
from temporalio.worker.workflow_sandbox import SandboxedWorkflowRunner
4949

50-
# Unsupported on python 3.9
51-
try:
52-
from agents.mcp import MCPServer
53-
except ImportError:
54-
pass
55-
5650
if typing.TYPE_CHECKING:
5751
from temporalio.contrib.openai_agents import (
5852
StatefulMCPServerProvider,

temporalio/contrib/opentelemetry.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,30 @@ async def start_workflow_update(
292292
):
293293
return await super().start_workflow_update(input)
294294

295+
async def start_update_with_start_workflow(
296+
self, input: temporalio.client.StartWorkflowUpdateWithStartInput
297+
) -> temporalio.client.WorkflowUpdateHandle[Any]:
298+
attrs = {
299+
"temporalWorkflowID": input.start_workflow_input.id,
300+
}
301+
if input.update_workflow_input.update_id is not None:
302+
attrs["temporalUpdateID"] = input.update_workflow_input.update_id
303+
304+
with self.root._start_as_current_span(
305+
f"StartUpdateWithStartWorkflow:{input.start_workflow_input.workflow}",
306+
attributes=attrs,
307+
input=input.start_workflow_input,
308+
kind=opentelemetry.trace.SpanKind.CLIENT,
309+
):
310+
otel_header = input.start_workflow_input.headers.get(self.root.header_key)
311+
if otel_header:
312+
input.update_workflow_input.headers = {
313+
**input.update_workflow_input.headers,
314+
self.root.header_key: otel_header,
315+
}
316+
317+
return await super().start_update_with_start_workflow(input)
318+
295319

296320
class _TracingActivityInboundInterceptor(temporalio.worker.ActivityInboundInterceptor):
297321
def __init__(

temporalio/worker/_replayer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ async def replay_workflow(
112112
Args:
113113
history: The history to replay. Can be fetched directly, or use
114114
:py:meth:`temporalio.client.WorkflowHistory.from_json` to parse
115-
a history downloaded via ``tctl`` or the web UI.
115+
a history downloaded via ``Temporal CLI`` or the web UI.
116116
raise_on_replay_failure: If ``True`` (the default), this will raise
117117
a :py:attr:`WorkflowReplayResult.replay_failure` if it is
118118
present.

temporalio/worker/_workflow_instance.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
import nexusrpc.handler
4747
from nexusrpc import InputT, OutputT
48-
from typing_extensions import Self, TypeAlias, TypedDict
48+
from typing_extensions import Self, TypeAlias, TypedDict, TypeVarTuple, Unpack
4949

5050
import temporalio.activity
5151
import temporalio.api.common.v1
@@ -2603,10 +2603,12 @@ def _timer_handle_cancelled(self, handle: asyncio.TimerHandle) -> None:
26032603
return
26042604
handle._apply_cancel_command(self._add_command())
26052605

2606+
_Ts = TypeVarTuple("_Ts")
2607+
26062608
def call_soon(
26072609
self,
2608-
callback: Callable[..., Any],
2609-
*args: Any,
2610+
callback: Callable[[Unpack[_Ts]], object],
2611+
*args: Unpack[_Ts],
26102612
context: Optional[contextvars.Context] = None,
26112613
) -> asyncio.Handle:
26122614
# We need to allow this during delete because this is how tasks schedule
@@ -2619,8 +2621,8 @@ def call_soon(
26192621
def call_later(
26202622
self,
26212623
delay: float,
2622-
callback: Callable[..., Any],
2623-
*args: Any,
2624+
callback: Callable[[Unpack[_Ts]], object],
2625+
*args: Unpack[_Ts],
26242626
context: Optional[contextvars.Context] = None,
26252627
) -> asyncio.TimerHandle:
26262628
options = _TimerOptionsCtxVar.get()
@@ -2629,8 +2631,8 @@ def call_later(
26292631
def call_at(
26302632
self,
26312633
when: float,
2632-
callback: Callable[..., Any],
2633-
*args: Any,
2634+
callback: Callable[[Unpack[_Ts]], object],
2635+
*args: Unpack[_Ts],
26342636
context: Optional[contextvars.Context] = None,
26352637
) -> asyncio.TimerHandle:
26362638
# We usually would not support fixed-future-time call (and we didn't

0 commit comments

Comments
 (0)