Skip to content

Commit e1120d9

Browse files
authored
Merge branch 'main' into openai/context_detach
2 parents d01159f + 778fc9a commit e1120d9

File tree

24 files changed

+1976
-1932
lines changed

24 files changed

+1976
-1932
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: 6 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"]
@@ -21,8 +21,7 @@ opentelemetry = ["opentelemetry-api>=1.11.1,<2", "opentelemetry-sdk>=1.11.1,<2"]
2121
pydantic = ["pydantic>=2.0.0,<3"]
2222
openai-agents = [
2323
"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'",
24+
"mcp>=1.9.4, <2",
2625
]
2726

2827
[project.urls]
@@ -35,7 +34,7 @@ Documentation = "https://docs.temporal.io/docs/python"
3534
dev = [
3635
"cibuildwheel>=2.22.0,<3",
3736
"grpcio-tools>=1.48.2,<2",
38-
"mypy==1.4.1",
37+
"mypy==1.18.2",
3938
"mypy-protobuf>=3.3.0,<4",
4039
"psutil>=5.9.3,<6",
4140
"pydocstyle>=6.3.0,<7",
@@ -51,7 +50,8 @@ dev = [
5150
"pytest-cov>=6.1.1",
5251
"httpx>=0.28.1",
5352
"pytest-pretty>=1.3.0",
54-
"openai-agents[litellm]>=0.3,<0.4",
53+
"openai-agents>=0.3,<0.4; python_version >= '3.14'",
54+
"openai-agents[litellm]>=0.3,<0.4; python_version < '3.14'",
5555
"googleapis-common-protos==1.70.0",
5656
]
5757

@@ -112,7 +112,7 @@ filterwarnings = [
112112

113113
[tool.cibuildwheel]
114114
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"
115+
build = "cp310-win_amd64 cp310-manylinux_x86_64 cp310-manylinux_aarch64 cp310-macosx_x86_64 cp310-macosx_arm64"
116116
build-verbosity = 1
117117

118118
[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/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]

temporalio/worker/workflow_sandbox/_restrictions.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import math
1515
import operator
1616
import random
17+
import sys
1718
import types
1819
import warnings
1920
from copy import copy, deepcopy
@@ -646,11 +647,18 @@ def _public_callables(parent: Any, *, exclude: Set[str] = set()) -> Set[str]:
646647
# "linecache": SandboxMatcher.all_uses,
647648
# Restrict almost everything in OS at runtime
648649
"os": SandboxMatcher(
650+
# As of https://github.com/python/cpython/pull/132662 in python 3.14 we have to allow os.path calls
651+
# which may occur during exception tracing. See https://github.com/python/cpython/issues/140228.
652+
children={
653+
"path": SandboxMatcher.none
654+
if sys.version_info >= (3, 14)
655+
else SandboxMatcher.all
656+
},
649657
access={"name"},
650658
use={"*"},
651659
# As of https://github.com/python/cpython/pull/112097, os.stat
652660
# calls are now made when displaying errors
653-
exclude={"stat"},
661+
exclude={"stat", "path"} if sys.version_info >= (3, 14) else {"stat"},
654662
# Only restricted at runtime
655663
only_runtime=True,
656664
),

tests/conftest.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,11 @@ def event_loop():
6464
try:
6565
loop.close()
6666
except TypeError:
67-
# In 3.9 tests, loop closing fails for an unclear reason, but not in
68-
# 3.13 tests
69-
if sys.version_info >= (3, 10):
70-
raise
71-
finally:
72-
# In 3.9 tests, the pytest-asyncio library finalizer that creates a new
73-
# event loop fails, but not in 3.13 tests. So for now we will make a new
74-
# policy that does not create the loop.
75-
if sys.version_info < (3, 10):
76-
asyncio.set_event_loop_policy(
77-
NoEventLoopPolicy(asyncio.get_event_loop_policy())
78-
)
79-
80-
81-
class NoEventLoopPolicy(asyncio.AbstractEventLoopPolicy):
82-
def __init__(self, underlying: asyncio.AbstractEventLoopPolicy):
67+
raise
68+
69+
70+
class NoEventLoopPolicy(asyncio.AbstractEventLoopPolicy): # type: ignore[name-defined]
71+
def __init__(self, underlying: asyncio.AbstractEventLoopPolicy): # type: ignore[name-defined]
8372
super().__init__()
8473
self._underlying = underlying
8574

0 commit comments

Comments
 (0)