Skip to content

Commit f327fdf

Browse files
authored
Merge branch 'main' into add-nightly-throughput-stress-workflow
2 parents 4d8edc7 + 5994a45 commit f327fdf

28 files changed

+2192
-2039
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

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: 4 additions & 4 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]] = {},

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: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
import opentelemetry.trace.propagation.tracecontext
2727
import opentelemetry.util.types
2828
from opentelemetry.context import Context
29-
from opentelemetry.trace import Span, SpanKind, Status, StatusCode, _Links
30-
from opentelemetry.util import types
29+
from opentelemetry.trace import Status, StatusCode
3130
from typing_extensions import Protocol, TypeAlias, TypedDict
3231

3332
import temporalio.activity
@@ -473,7 +472,12 @@ async def handle_query(self, input: temporalio.worker.HandleQueryInput) -> Any:
473472
)
474473
return await super().handle_query(input)
475474
finally:
476-
opentelemetry.context.detach(token)
475+
# In some exceptional cases this finally is executed with a
476+
# different contextvars.Context than the one the token was created
477+
# on. As such we do a best effort detach to avoid using a mismatched
478+
# token.
479+
if context is opentelemetry.context.get_current():
480+
opentelemetry.context.detach(token)
477481

478482
def handle_update_validator(
479483
self, input: temporalio.worker.HandleUpdateInput
@@ -545,6 +549,7 @@ def _top_level_workflow_context(
545549
exception: Optional[Exception] = None
546550
# Run under this context
547551
token = opentelemetry.context.attach(context)
552+
548553
try:
549554
yield None
550555
success = True
@@ -561,7 +566,13 @@ def _top_level_workflow_context(
561566
exception=exception,
562567
kind=opentelemetry.trace.SpanKind.INTERNAL,
563568
)
564-
opentelemetry.context.detach(token)
569+
570+
# In some exceptional cases this finally is executed with a
571+
# different contextvars.Context than the one the token was created
572+
# on. As such we do a best effort detach to avoid using a mismatched
573+
# token.
574+
if context is opentelemetry.context.get_current():
575+
opentelemetry.context.detach(token)
565576

566577
def _context_to_headers(
567578
self, headers: Mapping[str, temporalio.api.common.v1.Payload]

temporalio/worker/_worker.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,11 @@ def __init__(
203203
interceptors already on the client that also implement
204204
:py:class:`Interceptor` are prepended to this list and should
205205
not be explicitly given here.
206-
build_id: Unique identifier for the current runtime. This is best
207-
set as a hash of all code and should change only when code does.
208-
If unset, a best-effort identifier is generated.
206+
build_id: A unique identifier for the current runtime, ideally provided as a
207+
representation of the complete source code. If not explicitly set, the system
208+
automatically generates a best-effort identifier by traversing and computing
209+
hashes of all modules in the codebase. In very large codebases this automatic
210+
process may significantly increase initialization time.
209211
Exclusive with `deployment_config`.
210212
WARNING: Deprecated. Use `deployment_config` instead.
211213
identity: Identity for this worker client. If unset, the client

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

temporalio/worker/workflow_sandbox/_importer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def __or__(
454454
) -> Dict[str, types.ModuleType]:
455455
if sys.version_info < (3, 9):
456456
raise NotImplementedError
457-
return self.current.__or__(other)
457+
return self.current.__or__(other) # type: ignore[operator]
458458

459459
def __ior__(
460460
self, other: Mapping[str, types.ModuleType]

0 commit comments

Comments
 (0)