Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
246956a
Set python test matrix to 3.14 to validate new version behavior
tconley1428 Jun 4, 2025
513c82b
Set python test matrix to 3.14 to validate new version behavior
tconley1428 Jun 4, 2025
47524f1
Set python test matrix to 3.14 to validate new version behavior
tconley1428 Jun 4, 2025
1d67642
Set python test matrix to 3.14 to validate new version behavior
tconley1428 Jun 4, 2025
5fb5223
Set ABI3 compat
tconley1428 Jun 5, 2025
73cf6b1
Merge branch 'main' into python_314_ci
tconley1428 Jun 17, 2025
c04bab9
Update ci.yml
tconley1428 Jun 17, 2025
ffe4c74
Merge remote-tracking branch 'origin/main' into python_314_ci
tconley1428 Sep 30, 2025
e690433
Update dependencies and skip litellm
tconley1428 Oct 15, 2025
9f1bb2c
Merge remote-tracking branch 'origin/main' into python_314_ci
tconley1428 Oct 15, 2025
25c1d48
Ignore new mypy errors
tconley1428 Oct 15, 2025
6fc134a
Formatting
tconley1428 Oct 15, 2025
06f867f
Fix runtime error with linecache changes
tconley1428 Oct 16, 2025
5de0afa
Fix type suppressions
tconley1428 Oct 16, 2025
176463f
Fix test
tconley1428 Oct 16, 2025
ccfe001
Merge remote-tracking branch 'origin/main' into python_314_ci
tconley1428 Oct 16, 2025
adcc6a6
Replace standard CI runs
tconley1428 Oct 16, 2025
4041c42
Remove 3.9 checks
tconley1428 Oct 16, 2025
6d763b8
Move proto generation to python 3.10
tconley1428 Oct 16, 2025
926898e
Remove commented out test matrix
tconley1428 Oct 20, 2025
c4b66ab
Update tests/contrib/openai_agents/test_openai.py
tconley1428 Oct 20, 2025
22cbbde
AI assisted conversion of typing imports
tconley1428 Oct 20, 2025
dfa82e8
Temp run build_binaries to validate
tconley1428 Oct 20, 2025
31a882d
Revert "AI assisted conversion of typing imports"
tconley1428 Oct 20, 2025
62c406b
Keep cibuildwheel change
tconley1428 Oct 20, 2025
7b1d773
Merge branch 'main' into python_314_ci
tconley1428 Oct 20, 2025
c6e1ffc
Bump py03 compat
tconley1428 Oct 20, 2025
ffc9b64
Remove build binaries
tconley1428 Oct 20, 2025
bb581ea
Removed PR trigger from the wrong run
tconley1428 Oct 20, 2025
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
23 changes: 4 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,24 @@ jobs:
strategy:
fail-fast: false
matrix:
python: ["3.9", "3.13"]
python: ["3.10", "3.14"]
os: [ubuntu-latest, ubuntu-arm, macos-intel, macos-arm, windows-latest]
include:
# On 3.9 there is a problem with import errors caused by pytests' loader that surface due
# to a bug in CPython (https://github.com/python/cpython/issues/91351), so we avoid using
# the assert rewriter.
- python: "3.9"
pytestExtraArgs: "--assert=plain"
- os: ubuntu-latest
python: "3.13"
python: "3.14"
docsTarget: true
cloudTestTarget: true
openaiTestTarget: true
clippyLinter: true
- os: ubuntu-latest
python: "3.9"
python: "3.10"
protoCheckTarget: true
- os: ubuntu-arm
runsOn: ubuntu-24.04-arm64-2-core
- os: macos-intel
runsOn: macos-15-intel
# On 3.13.3 there is some issue with macOS intel where it hangs after pytest with some
# test that may have a worker that cannot properly shutdown, but it does not occur on
# other versions, platforms, etc. See https://github.com/temporalio/sdk-python/issues/834.
- os: macos-intel
python: "3.13"
pythonOverride: "3.13.2"
- os: macos-arm
runsOn: macos-latest
# On 3.13.5, python3.lib is missing for the linker
- os: windows-latest
python: "3.13"
pythonOverride: "3.13.4"
runs-on: ${{ matrix.runsOn || matrix.os }}
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -113,7 +98,7 @@ jobs:
env:
TEMPORAL_TEST_PROTO3: 1
run: |
uv add --python 3.9 "protobuf<4"
uv add --python 3.10 "protobuf<4"
uv sync --all-extras
poe build-develop
poe gen-protos
Expand Down
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "temporalio"
version = "1.18.1"
description = "Temporal.io Python SDK"
authors = [{ name = "Temporal Technologies Inc", email = "[email protected]" }]
requires-python = ">=3.9"
requires-python = ">=3.10"
readme = "README.md"
license = { file = "LICENSE" }
keywords = ["temporal", "workflow"]
Expand All @@ -21,8 +21,7 @@ opentelemetry = ["opentelemetry-api>=1.11.1,<2", "opentelemetry-sdk>=1.11.1,<2"]
pydantic = ["pydantic>=2.0.0,<3"]
openai-agents = [
"openai-agents>=0.3,<0.4",
"eval-type-backport>=0.2.2; python_version < '3.10'",
"mcp>=1.9.4, <2; python_version >= '3.10'",
"mcp>=1.9.4, <2",
]

[project.urls]
Expand All @@ -35,7 +34,7 @@ Documentation = "https://docs.temporal.io/docs/python"
dev = [
"cibuildwheel>=2.22.0,<3",
"grpcio-tools>=1.48.2,<2",
"mypy==1.4.1",
"mypy==1.18.2",
"mypy-protobuf>=3.3.0,<4",
"psutil>=5.9.3,<6",
"pydocstyle>=6.3.0,<7",
Expand All @@ -51,7 +50,8 @@ dev = [
"pytest-cov>=6.1.1",
"httpx>=0.28.1",
"pytest-pretty>=1.3.0",
"openai-agents[litellm]>=0.3,<0.4",
"openai-agents>=0.3,<0.4; python_version >= '3.14'",
"openai-agents[litellm]>=0.3,<0.4; python_version < '3.14'",
"googleapis-common-protos==1.70.0",
]

Expand Down Expand Up @@ -112,7 +112,7 @@ filterwarnings = [

[tool.cibuildwheel]
before-all = "pip install protoc-wheel-0"
build = "cp39-win_amd64 cp39-manylinux_x86_64 cp39-manylinux_aarch64 cp39-macosx_x86_64 cp39-macosx_arm64"
build = "cp310-win_amd64 cp310-manylinux_x86_64 cp310-manylinux_aarch64 cp310-macosx_x86_64 cp310-macosx_arm64"
build-verbosity = 1

[tool.cibuildwheel.macos]
Expand Down
2 changes: 1 addition & 1 deletion temporalio/bridge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ futures = "0.3"
prost = "0.13"
pyo3 = { version = "0.25", features = [
"extension-module",
"abi3-py39",
"abi3-py310",
"anyhow",
"multiple-pymethods",
] }
Expand Down
8 changes: 4 additions & 4 deletions temporalio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ async def execute_update_with_start_workflow(
MultiParamSpec, LocalReturnType
],
*,
args: MultiParamSpec.args, # pyright: ignore
args: MultiParamSpec.args, # type: ignore
start_workflow_operation: WithStartWorkflowOperation[SelfType, Any],
id: Optional[str] = None,
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
Expand Down Expand Up @@ -1061,7 +1061,7 @@ async def start_update_with_start_workflow(
MultiParamSpec, LocalReturnType
],
*,
args: MultiParamSpec.args, # pyright: ignore
args: MultiParamSpec.args, # type: ignore
start_workflow_operation: WithStartWorkflowOperation[SelfType, Any],
wait_for_stage: WorkflowUpdateStage,
id: Optional[str] = None,
Expand Down Expand Up @@ -2252,7 +2252,7 @@ async def execute_update(
MultiParamSpec, LocalReturnType
],
*,
args: MultiParamSpec.args, # pyright: ignore
args: MultiParamSpec.args, # type: ignore
id: Optional[str] = None,
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
rpc_timeout: Optional[timedelta] = None,
Expand Down Expand Up @@ -2353,7 +2353,7 @@ async def start_update(
MultiParamSpec, LocalReturnType
],
*,
args: MultiParamSpec.args, # pyright: ignore
args: MultiParamSpec.args, # type: ignore
wait_for_stage: WorkflowUpdateStage,
id: Optional[str] = None,
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
Expand Down
13 changes: 4 additions & 9 deletions temporalio/contrib/openai_agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@
Use with caution in production environments.
"""

# Best Effort mcp, as it is not supported on Python 3.9
try:
from temporalio.contrib.openai_agents._mcp import (
StatefulMCPServerProvider,
StatelessMCPServerProvider,
)
except ImportError:
pass

from temporalio.contrib.openai_agents._mcp import (
StatefulMCPServerProvider,
StatelessMCPServerProvider,
)
from temporalio.contrib.openai_agents._model_parameters import ModelActivityParameters
from temporalio.contrib.openai_agents._temporal_openai_agents import (
OpenAIAgentsPlugin,
Expand Down
6 changes: 0 additions & 6 deletions temporalio/contrib/openai_agents/_temporal_openai_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@
from temporalio.worker import WorkflowRunner
from temporalio.worker.workflow_sandbox import SandboxedWorkflowRunner

# Unsupported on python 3.9
try:
from agents.mcp import MCPServer
except ImportError:
pass

if typing.TYPE_CHECKING:
from temporalio.contrib.openai_agents import (
StatefulMCPServerProvider,
Expand Down
16 changes: 9 additions & 7 deletions temporalio/worker/_workflow_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

import nexusrpc.handler
from nexusrpc import InputT, OutputT
from typing_extensions import Self, TypeAlias, TypedDict
from typing_extensions import Self, TypeAlias, TypedDict, TypeVarTuple, Unpack

import temporalio.activity
import temporalio.api.common.v1
Expand Down Expand Up @@ -2603,10 +2603,12 @@ def _timer_handle_cancelled(self, handle: asyncio.TimerHandle) -> None:
return
handle._apply_cancel_command(self._add_command())

_Ts = TypeVarTuple("_Ts")

def call_soon(
self,
callback: Callable[..., Any],
*args: Any,
callback: Callable[[Unpack[_Ts]], object],
*args: Unpack[_Ts],
context: Optional[contextvars.Context] = None,
) -> asyncio.Handle:
# We need to allow this during delete because this is how tasks schedule
Expand All @@ -2619,8 +2621,8 @@ def call_soon(
def call_later(
self,
delay: float,
callback: Callable[..., Any],
*args: Any,
callback: Callable[[Unpack[_Ts]], object],
*args: Unpack[_Ts],
context: Optional[contextvars.Context] = None,
) -> asyncio.TimerHandle:
options = _TimerOptionsCtxVar.get()
Expand All @@ -2629,8 +2631,8 @@ def call_later(
def call_at(
self,
when: float,
callback: Callable[..., Any],
*args: Any,
callback: Callable[[Unpack[_Ts]], object],
*args: Unpack[_Ts],
context: Optional[contextvars.Context] = None,
) -> asyncio.TimerHandle:
# We usually would not support fixed-future-time call (and we didn't
Expand Down
2 changes: 1 addition & 1 deletion temporalio/worker/workflow_sandbox/_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ def __or__(
) -> Dict[str, types.ModuleType]:
if sys.version_info < (3, 9):
raise NotImplementedError
return self.current.__or__(other)
return self.current.__or__(other) # type: ignore[operator]

def __ior__(
self, other: Mapping[str, types.ModuleType]
Expand Down
10 changes: 9 additions & 1 deletion temporalio/worker/workflow_sandbox/_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import math
import operator
import random
import sys
import types
import warnings
from copy import copy, deepcopy
Expand Down Expand Up @@ -646,11 +647,18 @@ def _public_callables(parent: Any, *, exclude: Set[str] = set()) -> Set[str]:
# "linecache": SandboxMatcher.all_uses,
# Restrict almost everything in OS at runtime
"os": SandboxMatcher(
# As of https://github.com/python/cpython/pull/132662 in python 3.14 we have to allow os.path calls
# which may occur during exception tracing. See https://github.com/python/cpython/issues/140228.
children={
"path": SandboxMatcher.none
if sys.version_info >= (3, 14)
else SandboxMatcher.all
},
access={"name"},
use={"*"},
# As of https://github.com/python/cpython/pull/112097, os.stat
# calls are now made when displaying errors
exclude={"stat"},
exclude={"stat", "path"} if sys.version_info >= (3, 14) else {"stat"},
# Only restricted at runtime
only_runtime=True,
),
Expand Down
21 changes: 5 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,11 @@ def event_loop():
try:
loop.close()
except TypeError:
# In 3.9 tests, loop closing fails for an unclear reason, but not in
# 3.13 tests
if sys.version_info >= (3, 10):
raise
finally:
# In 3.9 tests, the pytest-asyncio library finalizer that creates a new
# event loop fails, but not in 3.13 tests. So for now we will make a new
# policy that does not create the loop.
if sys.version_info < (3, 10):
asyncio.set_event_loop_policy(
NoEventLoopPolicy(asyncio.get_event_loop_policy())
)


class NoEventLoopPolicy(asyncio.AbstractEventLoopPolicy):
def __init__(self, underlying: asyncio.AbstractEventLoopPolicy):
raise


class NoEventLoopPolicy(asyncio.AbstractEventLoopPolicy): # type: ignore[name-defined]
def __init__(self, underlying: asyncio.AbstractEventLoopPolicy): # type: ignore[name-defined]
super().__init__()
self._underlying = underlying

Expand Down
29 changes: 5 additions & 24 deletions tests/contrib/openai_agents/test_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
TResponseOutputItem,
TResponseStreamEvent,
)
from agents.mcp import MCPServer, MCPServerStdio
from openai import APIStatusError, AsyncOpenAI, BaseModel
from openai.types.responses import (
EasyInputMessageParam,
Expand Down Expand Up @@ -92,6 +93,8 @@
from temporalio.contrib import openai_agents
from temporalio.contrib.openai_agents import (
ModelActivityParameters,
StatefulMCPServerProvider,
StatelessMCPServerProvider,
TestModel,
TestModelProvider,
)
Expand Down Expand Up @@ -1769,8 +1772,8 @@ async def check():
async def test_lite_llm(client: Client, env: WorkflowEnvironment):
if not os.environ.get("OPENAI_API_KEY"):
pytest.skip("No openai API key")
if sys.version_info < (3, 10):
pytest.skip("Lite LLM does not import below 3.10")
if sys.version_info >= (3, 14):
pytest.skip("Lite LLM does not yet support Python 3.14")

from agents.extensions.models.litellm_provider import LitellmProvider

Expand Down Expand Up @@ -2449,9 +2452,6 @@ async def test_mcp_server(
if not use_local_model and not os.environ.get("OPENAI_API_KEY"):
pytest.skip("No openai API key")

if sys.version_info < (3, 10):
pytest.skip("Mcp not supported on Python 3.9")

if stateful and caching:
pytest.skip("Caching is only supported for stateless MCP servers")

Expand Down Expand Up @@ -2552,19 +2552,6 @@ async def test_mcp_server(

@pytest.mark.parametrize("stateful", [True, False])
async def test_mcp_server_factory_argument(client: Client, stateful: bool):
if sys.version_info < (3, 10):
pytest.skip("Mcp not supported on Python 3.9")

from agents.mcp import MCPServer # type: ignore
from mcp import GetPromptResult, ListPromptsResult # type: ignore
from mcp import Tool as MCPTool # type: ignore
from mcp.types import CallToolResult, TextContent # type: ignore

from temporalio.contrib.openai_agents import (
StatefulMCPServerProvider,
StatelessMCPServerProvider,
)

def factory(args: Optional[Any]) -> MCPServer:
print("Invoking factory: ", args)
if args is not None:
Expand Down Expand Up @@ -2614,12 +2601,6 @@ def factory(args: Optional[Any]) -> MCPServer:


async def test_stateful_mcp_server_no_worker(client: Client):
if sys.version_info < (3, 10):
pytest.skip("Mcp not supported on Python 3.9")
from agents.mcp import MCPServerStdio

from temporalio.contrib.openai_agents import StatefulMCPServerProvider

server = StatefulMCPServerProvider(
"Filesystem-Server",
lambda _: MCPServerStdio(
Expand Down
6 changes: 1 addition & 5 deletions tests/contrib/test_opentelemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from datetime import timedelta
from typing import Iterable, List, Optional

import pytest
from opentelemetry.sdk.trace import ReadableSpan, TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
Expand All @@ -22,11 +23,6 @@
from temporalio.testing import WorkflowEnvironment
from temporalio.worker import UnsandboxedWorkflowRunner, Worker

# Passing through because Python 3.9 has an import bug at
# https://github.com/python/cpython/issues/91351
with workflow.unsafe.imports_passed_through():
import pytest


@dataclass
class TracingActivityParam:
Expand Down
6 changes: 1 addition & 5 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from unittest import mock

import google.protobuf.any_pb2
import pytest
from google.protobuf import json_format

import temporalio.api.common.v1
Expand Down Expand Up @@ -101,11 +102,6 @@
KSWorkflowParams,
)

# Passing through because Python 3.9 has an import bug at
# https://github.com/python/cpython/issues/91351
with workflow.unsafe.imports_passed_through():
import pytest


async def test_start_id_reuse(
client: Client, worker: ExternalWorker, env: WorkflowEnvironment
Expand Down
Loading
Loading