diff --git a/pyproject.toml b/pyproject.toml index 6b294b3c7..d660bfb46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ Documentation = "https://docs.temporal.io/docs/python" [dependency-groups] dev = [ + "basedpyright==1.34.0", "cibuildwheel>=2.22.0,<3", "grpcio-tools>=1.48.2,<2", "mypy==1.18.2", @@ -96,6 +97,7 @@ lint-docs = "uv run pydocstyle --ignore-decorators=overload" lint-types = [ { cmd = "uv run pyright" }, { cmd = "uv run mypy --namespace-packages --check-untyped-defs ." }, + { cmd = "uv run basedpyright" } ] run-bench = "uv run python scripts/run_bench.py" test = "uv run pytest" @@ -200,11 +202,13 @@ reportUnknownVariableType = "none" reportUnnecessaryIsInstance = "none" reportUnnecessaryTypeIgnoreComment = "none" reportUnusedCallResult = "none" +reportUnknownLambdaType = "none" include = ["temporalio", "tests"] exclude = [ # Exclude auto generated files "temporalio/api", "temporalio/bridge/proto", + "temporalio/bridge/_visitor.py", "tests/worker/workflow_sandbox/testmodules/proto", ] diff --git a/scripts/gen_protos.py b/scripts/gen_protos.py index 131f094f4..c1d5360b5 100644 --- a/scripts/gen_protos.py +++ b/scripts/gen_protos.py @@ -7,7 +7,6 @@ from collections.abc import Mapping from functools import partial from pathlib import Path -from typing import List base_dir = Path(__file__).parent.parent proto_dir = ( diff --git a/temporalio/activity.py b/temporalio/activity.py index ea6ce6458..ff46bdea8 100644 --- a/temporalio/activity.py +++ b/temporalio/activity.py @@ -22,12 +22,7 @@ from typing import ( TYPE_CHECKING, Any, - List, NoReturn, - Optional, - Tuple, - Type, - Union, overload, ) @@ -593,7 +588,7 @@ def _apply_to_callable( if hasattr(fn, "__temporal_activity_definition"): raise ValueError("Function already contains activity definition") elif not callable(fn): - raise TypeError("Activity is not callable") + raise TypeError("Activity is not callable") # type:ignore[reportUnreachable] # We do not allow keyword only arguments in activities sig = inspect.signature(fn) for param in sig.parameters.values(): diff --git a/temporalio/bridge/client.py b/temporalio/bridge/client.py index d89b330fb..564005ef0 100644 --- a/temporalio/bridge/client.py +++ b/temporalio/bridge/client.py @@ -8,13 +8,15 @@ from collections.abc import Mapping from dataclasses import dataclass from datetime import timedelta -from typing import Optional, Tuple, Type, TypeVar, Union +from typing import TypeVar import google.protobuf.message import temporalio.bridge.runtime import temporalio.bridge.temporal_sdk_bridge -from temporalio.bridge.temporal_sdk_bridge import RPCError +from temporalio.bridge.temporal_sdk_bridge import ( + RPCError, # type:ignore[reportUnusedImport] +) @dataclass diff --git a/temporalio/bridge/metric.py b/temporalio/bridge/metric.py index 6bccb82cc..4b8d7453d 100644 --- a/temporalio/bridge/metric.py +++ b/temporalio/bridge/metric.py @@ -6,7 +6,6 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Optional, Union import temporalio.bridge.runtime import temporalio.bridge.temporal_sdk_bridge diff --git a/temporalio/bridge/runtime.py b/temporalio/bridge/runtime.py index 6d718fe03..fa7fb275d 100644 --- a/temporalio/bridge/runtime.py +++ b/temporalio/bridge/runtime.py @@ -7,7 +7,7 @@ from collections.abc import Callable, Mapping, Sequence from dataclasses import dataclass -from typing import Any, Dict, Optional, Type +from typing import Any from typing_extensions import Protocol diff --git a/temporalio/bridge/testing.py b/temporalio/bridge/testing.py index 8db2edc2a..9f0db3098 100644 --- a/temporalio/bridge/testing.py +++ b/temporalio/bridge/testing.py @@ -7,7 +7,6 @@ from collections.abc import Sequence from dataclasses import dataclass -from typing import Optional import temporalio.bridge.runtime import temporalio.bridge.temporal_sdk_bridge diff --git a/temporalio/bridge/worker.py b/temporalio/bridge/worker.py index ea6820865..f37c76f19 100644 --- a/temporalio/bridge/worker.py +++ b/temporalio/bridge/worker.py @@ -8,16 +8,9 @@ from collections.abc import Awaitable, Callable, MutableSequence, Sequence from dataclasses import dataclass from typing import ( - List, - Optional, - Set, - Tuple, TypeAlias, - Union, ) -import temporalio.api.common.v1 -import temporalio.api.history.v1 import temporalio.bridge.client import temporalio.bridge.proto import temporalio.bridge.proto.activity_task @@ -27,7 +20,6 @@ import temporalio.bridge.runtime import temporalio.bridge.temporal_sdk_bridge import temporalio.converter -import temporalio.exceptions from temporalio.api.common.v1.message_pb2 import Payload from temporalio.bridge._visitor import VisitorFunctions from temporalio.bridge.temporal_sdk_bridge import ( @@ -80,10 +72,7 @@ class PollerBehaviorAutoscaling: initial: int -PollerBehavior: TypeAlias = Union[ - PollerBehaviorSimpleMaximum, - PollerBehaviorAutoscaling, -] +PollerBehavior: TypeAlias = PollerBehaviorSimpleMaximum | PollerBehaviorAutoscaling @dataclass @@ -118,11 +107,11 @@ class WorkerVersioningStrategyLegacyBuildIdBased: build_id_with_versioning: str -WorkerVersioningStrategy: TypeAlias = Union[ - WorkerVersioningStrategyNone, - WorkerDeploymentOptions, - WorkerVersioningStrategyLegacyBuildIdBased, -] +WorkerVersioningStrategy: TypeAlias = ( + WorkerVersioningStrategyNone + | WorkerDeploymentOptions + | WorkerVersioningStrategyLegacyBuildIdBased +) @dataclass @@ -150,11 +139,9 @@ class FixedSizeSlotSupplier: num_slots: int -SlotSupplier: TypeAlias = Union[ - FixedSizeSlotSupplier, - ResourceBasedSlotSupplier, - BridgeCustomSlotSupplier, -] +SlotSupplier: TypeAlias = ( + FixedSizeSlotSupplier | ResourceBasedSlotSupplier | BridgeCustomSlotSupplier +) @dataclass diff --git a/temporalio/client.py b/temporalio/client.py index 07ccdc6b2..b4d5af0fa 100644 --- a/temporalio/client.py +++ b/temporalio/client.py @@ -28,14 +28,7 @@ from typing import ( Any, Concatenate, - Dict, - FrozenSet, Generic, - Optional, - Text, - Tuple, - Type, - Union, cast, overload, ) @@ -205,7 +198,9 @@ async def connect( http_connect_proxy_config=http_connect_proxy_config, ) - def make_lambda(plugin, next): + def make_lambda( + plugin: Plugin, next: Callable[[ConnectConfig], Awaitable[ServiceClient]] + ): return lambda config: plugin.connect_service_client(config, next) next_function = ServiceClient.connect @@ -3397,7 +3392,7 @@ def next_page_token(self) -> bytes | None: """Token for the next page request if any.""" return self._next_page_token - async def fetch_next_page(self, *, page_size: int | None = None) -> None: + async def fetch_next_page(self, *, page_size: int | None = None) -> None: # type:ignore[reportUnusedParameter] # https://github.com/temporalio/sdk-python/issues/1239 """Fetch the next page if any. Args: @@ -4148,7 +4143,7 @@ def __init__( raise ValueError("Cannot schedule dynamic workflow explicitly") workflow = defn.name elif not isinstance(workflow, str): - raise TypeError("Workflow must be a string or callable") + raise TypeError("Workflow must be a string or callable") # type:ignore[reportUnreachable] self.workflow = workflow self.args = temporalio.common._arg_or_args(arg, args) self.id = id @@ -6032,9 +6027,9 @@ async def _populate_start_workflow_execution_request( req.user_metadata.CopyFrom(metadata) if input.start_delay is not None: req.workflow_start_delay.FromTimedelta(input.start_delay) - if input.headers is not None: + if input.headers is not None: # type:ignore[reportUnnecessaryComparison] await self._apply_headers(input.headers, req.header.fields) - if input.priority is not None: + if input.priority is not None: # type:ignore[reportUnnecessaryComparison] req.priority.CopyFrom(input.priority._to_proto()) if input.versioning_override is not None: req.versioning_override.CopyFrom(input.versioning_override._to_proto()) @@ -6130,7 +6125,7 @@ async def query_workflow(self, input: QueryWorkflowInput) -> Any: req.query.query_args.payloads.extend( await data_converter.encode(input.args) ) - if input.headers is not None: + if input.headers is not None: # type:ignore[reportUnnecessaryComparison] await self._apply_headers(input.headers, req.query.header.fields) try: resp = await self._client.workflow_service.query_workflow( @@ -6178,7 +6173,7 @@ async def signal_workflow(self, input: SignalWorkflowInput) -> None: ) if input.args: req.input.payloads.extend(await data_converter.encode(input.args)) - if input.headers is not None: + if input.headers is not None: # type:ignore[reportUnnecessaryComparison] await self._apply_headers(input.headers, req.header.fields) await self._client.workflow_service.signal_workflow_execution( req, retry=True, metadata=input.rpc_metadata, timeout=input.rpc_timeout @@ -6299,7 +6294,7 @@ async def _build_update_workflow_execution_request( req.request.input.args.payloads.extend( await data_converter.encode(input.args) ) - if input.headers is not None: + if input.headers is not None: # type:ignore[reportUnnecessaryComparison] await self._apply_headers(input.headers, req.request.input.header.fields) return req diff --git a/temporalio/common.py b/temporalio/common.py index a4bb5f60a..b6dd67a4e 100644 --- a/temporalio/common.py +++ b/temporalio/common.py @@ -14,14 +14,8 @@ Any, ClassVar, Generic, - List, - Optional, - Text, - Tuple, - Type, TypeAlias, TypeVar, - Union, get_origin, get_type_hints, overload, @@ -198,13 +192,13 @@ def __setstate__(self, state: object) -> None: # We choose to make this a list instead of an sequence so we can catch if people # are not sending lists each time but maybe accidentally sending a string (which # is a sequence) -SearchAttributeValues: TypeAlias = Union[ - list[str], list[int], list[float], list[bool], list[datetime] -] +SearchAttributeValues: TypeAlias = ( + list[str] | list[int] | list[float] | list[bool] | list[datetime] +) SearchAttributes: TypeAlias = Mapping[str, SearchAttributeValues] -SearchAttributeValue: TypeAlias = Union[str, int, float, bool, datetime, Sequence[str]] +SearchAttributeValue: TypeAlias = str | int | float | bool | datetime | Sequence[str] SearchAttributeValueType = TypeVar( "SearchAttributeValueType", str, int, float, bool, datetime, Sequence[str] @@ -492,7 +486,7 @@ def __contains__(self, key: object) -> bool: This uses key equality so the key must be the same name and type. """ - return any(k == key for k, v in self) + return any(k == key for k, _v in self) @overload def get( @@ -544,7 +538,7 @@ def updated(self, *search_attributes: SearchAttributePair) -> TypedSearchAttribu TypedSearchAttributes.empty = TypedSearchAttributes(search_attributes=[]) -def _warn_on_deprecated_search_attributes( +def _warn_on_deprecated_search_attributes( # type:ignore[reportUnusedFunction] attributes: SearchAttributes | Any | None, stack_level: int = 2, ) -> None: @@ -556,7 +550,7 @@ def _warn_on_deprecated_search_attributes( ) -MetricAttributes: TypeAlias = Mapping[str, Union[str, int, float, bool]] +MetricAttributes: TypeAlias = Mapping[str, str | int | float | bool] class MetricMeter(ABC): @@ -1157,7 +1151,7 @@ def _to_proto(self) -> temporalio.api.workflow.v1.VersioningOverride: _arg_unset = object() -def _arg_or_args(arg: Any, args: Sequence[Any]) -> Sequence[Any]: +def _arg_or_args(arg: Any, args: Sequence[Any]) -> Sequence[Any]: # type:ignore[reportUnusedFunction] if arg is not _arg_unset: if args: raise ValueError("Cannot have arg and args") @@ -1165,7 +1159,7 @@ def _arg_or_args(arg: Any, args: Sequence[Any]) -> Sequence[Any]: return args -def _apply_headers( +def _apply_headers( # type:ignore[reportUnusedFunction] source: Mapping[str, temporalio.api.common.v1.Payload] | None, dest: google.protobuf.internal.containers.MessageMap[ str, temporalio.api.common.v1.Payload @@ -1192,7 +1186,7 @@ def _apply_headers( ) -def _type_hints_from_func( +def _type_hints_from_func( # type:ignore[reportUnusedFunction] func: Callable, ) -> tuple[list[type] | None, type | None]: """Extracts the type hints from the function. diff --git a/temporalio/contrib/openai_agents/__init__.py b/temporalio/contrib/openai_agents/__init__.py index d49733e8b..eeefbff8c 100644 --- a/temporalio/contrib/openai_agents/__init__.py +++ b/temporalio/contrib/openai_agents/__init__.py @@ -17,9 +17,6 @@ OpenAIAgentsPlugin, OpenAIPayloadConverter, ) -from temporalio.contrib.openai_agents._trace_interceptor import ( - OpenAIAgentsTracingInterceptor, -) from temporalio.contrib.openai_agents.workflow import AgentsWorkflowError from . import testing, workflow diff --git a/temporalio/contrib/openai_agents/_heartbeat_decorator.py b/temporalio/contrib/openai_agents/_heartbeat_decorator.py index 2fae11d7d..4baff6706 100644 --- a/temporalio/contrib/openai_agents/_heartbeat_decorator.py +++ b/temporalio/contrib/openai_agents/_heartbeat_decorator.py @@ -8,7 +8,7 @@ F = TypeVar("F", bound=Callable[..., Awaitable[Any]]) -def _auto_heartbeater(fn: F) -> F: +def _auto_heartbeater(fn: F) -> F: # type:ignore[reportUnusedClass] # Propagate type hints from the original callable. @wraps(fn) async def wrapper(*args: Any, **kwargs: Any) -> Any: diff --git a/temporalio/contrib/openai_agents/_invoke_model_activity.py b/temporalio/contrib/openai_agents/_invoke_model_activity.py index f03458c32..945a05ec6 100644 --- a/temporalio/contrib/openai_agents/_invoke_model_activity.py +++ b/temporalio/contrib/openai_agents/_invoke_model_activity.py @@ -4,10 +4,9 @@ """ import enum -import json from dataclasses import dataclass from datetime import timedelta -from typing import Any, Optional, Union +from typing import Any from agents import ( AgentOutputSchemaBase, @@ -33,10 +32,9 @@ AsyncOpenAI, ) from openai.types.responses.tool_param import Mcp -from pydantic_core import to_json from typing_extensions import Required, TypedDict -from temporalio import activity, workflow +from temporalio import activity from temporalio.contrib.openai_agents._heartbeat_decorator import _auto_heartbeater from temporalio.exceptions import ApplicationError @@ -75,14 +73,14 @@ class HostedMCPToolInput: tool_config: Mcp -ToolInput = Union[ - FunctionToolInput, - FileSearchTool, - WebSearchTool, - ImageGenerationTool, - CodeInterpreterTool, - HostedMCPToolInput, -] +ToolInput = ( + FunctionToolInput + | FileSearchTool + | WebSearchTool + | ImageGenerationTool + | CodeInterpreterTool + | HostedMCPToolInput +) @dataclass @@ -165,11 +163,13 @@ async def invoke_model_activity(self, input: ActivityModelInput) -> ModelRespons """Activity that invokes a model with the given input.""" model = self._model_provider.get_model(input.get("model_name")) - async def empty_on_invoke_tool(ctx: RunContextWrapper[Any], input: str) -> str: + async def empty_on_invoke_tool( + _ctx: RunContextWrapper[Any], _input: str + ) -> str: return "" async def empty_on_invoke_handoff( - ctx: RunContextWrapper[Any], input: str + _ctx: RunContextWrapper[Any], _input: str ) -> Any: return None @@ -197,7 +197,7 @@ def make_tool(tool: ToolInput) -> Tool: strict_json_schema=tool.strict_json_schema, ) else: - raise UserError(f"Unknown tool type: {tool.name}") + raise UserError(f"Unknown tool type: {tool.name}") # type:ignore[reportUnreachable] tools = [make_tool(x) for x in input.get("tools", [])] handoffs: list[Handoff[Any, Any]] = [ diff --git a/temporalio/contrib/openai_agents/_mcp.py b/temporalio/contrib/openai_agents/_mcp.py index 76d558b82..c9d1f87ea 100644 --- a/temporalio/contrib/openai_agents/_mcp.py +++ b/temporalio/contrib/openai_agents/_mcp.py @@ -1,4 +1,3 @@ -import abc import asyncio import dataclasses import functools @@ -7,7 +6,8 @@ from collections.abc import Callable, Sequence from contextlib import AbstractAsyncContextManager from datetime import timedelta -from typing import Any, Optional, Union, cast +from types import TracebackType +from typing import Any, cast from agents import AgentBase, RunContextWrapper from agents.mcp import MCPServer @@ -23,7 +23,6 @@ from temporalio.exceptions import ( ActivityError, ApplicationError, - CancelledError, is_cancelled_exception, ) from temporalio.worker import PollerBehaviorSimpleMaximum, Worker @@ -56,7 +55,7 @@ class _StatelessGetPromptArguments: factory_argument: Any | None -class _StatelessMCPServerReference(MCPServer): +class _StatelessMCPServerReference(MCPServer): # type:ignore[reportUnusedClass] def __init__( self, server: str, @@ -163,7 +162,7 @@ def __init__( def _create_server(self, factory_argument: Any | None) -> MCPServer: if self._server_accepts_arguments: - return cast(Callable[[Optional[Any]], MCPServer], self._server_factory)( + return cast(Callable[[Any | None], MCPServer], self._server_factory)( factory_argument ) else: @@ -241,9 +240,9 @@ async def get_prompt_deprecated( ) -def _handle_worker_failure(func): +def _handle_worker_failure(func: Callable) -> Callable: @functools.wraps(func) - async def wrapper(*args, **kwargs): + async def wrapper(*args: Any, **kwargs: Any): try: return await func(*args, **kwargs) except ActivityError as e: @@ -289,7 +288,7 @@ class _StatefulServerSessionArguments: factory_argument: Any | None -class _StatefulMCPServerReference(MCPServer, AbstractAsyncContextManager): +class _StatefulMCPServerReference(MCPServer, AbstractAsyncContextManager): # type:ignore[reportUnusedClass] def __init__( self, server: str, @@ -336,7 +335,12 @@ async def __aenter__(self): await self.connect() return self - async def __aexit__(self, exc_type, exc_value, traceback): + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: await self.cleanup() @_handle_worker_failure diff --git a/temporalio/contrib/openai_agents/_model_parameters.py b/temporalio/contrib/openai_agents/_model_parameters.py index 3cab91c27..55827e0d5 100644 --- a/temporalio/contrib/openai_agents/_model_parameters.py +++ b/temporalio/contrib/openai_agents/_model_parameters.py @@ -1,10 +1,9 @@ """Parameters for configuring Temporal activity execution for model calls.""" from abc import ABC, abstractmethod -from collections.abc import Callable from dataclasses import dataclass from datetime import timedelta -from typing import Any, Optional, Union +from typing import Any from agents import Agent, TResponseInputItem diff --git a/temporalio/contrib/openai_agents/_openai_runner.py b/temporalio/contrib/openai_agents/_openai_runner.py index 7e7853fbd..e782124c0 100644 --- a/temporalio/contrib/openai_agents/_openai_runner.py +++ b/temporalio/contrib/openai_agents/_openai_runner.py @@ -1,6 +1,6 @@ import dataclasses import typing -from typing import Any, Optional, Union +from typing import Any from agents import ( Agent, diff --git a/temporalio/contrib/openai_agents/_temporal_model_stub.py b/temporalio/contrib/openai_agents/_temporal_model_stub.py index f84488541..f55821309 100644 --- a/temporalio/contrib/openai_agents/_temporal_model_stub.py +++ b/temporalio/contrib/openai_agents/_temporal_model_stub.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from typing import Optional from temporalio import workflow from temporalio.contrib.openai_agents._model_parameters import ModelActivityParameters @@ -9,7 +8,7 @@ logger = logging.getLogger(__name__) from collections.abc import AsyncIterator -from typing import Any, Union, cast +from typing import Any from agents import ( Agent, @@ -44,7 +43,7 @@ ) -class _TemporalModelStub(Model): +class _TemporalModelStub(Model): # type:ignore[reportUnusedClass] """A stub that allows invoking models as Temporal activities.""" def __init__( @@ -197,34 +196,3 @@ def stream_response( prompt: ResponsePromptParam | None, ) -> AsyncIterator[TResponseStreamEvent]: raise NotImplementedError("Temporal model doesn't support streams yet") - - -def _extract_summary(input: str | list[TResponseInputItem]) -> str: - ### Activity summary shown in the UI - try: - max_size = 100 - if isinstance(input, str): - return input[:max_size] - elif isinstance(input, list): - # Find all message inputs, which are reasonably summarizable - messages: list[TResponseInputItem] = [ - item for item in input if item.get("type", "message") == "message" - ] - if not messages: - return "" - - content: Any = messages[-1].get("content", "") - - # In the case of multiple contents, take the last one - if isinstance(content, list): - if not content: - return "" - content = content[-1] - - # Take the text field from the content if present - if isinstance(content, dict) and content.get("text") is not None: - content = content.get("text") - return str(content)[:max_size] - except Exception as e: - logger.error(f"Error getting summary: {e}") - return "" diff --git a/temporalio/contrib/openai_agents/_temporal_openai_agents.py b/temporalio/contrib/openai_agents/_temporal_openai_agents.py index 41ae419f7..c1ace7a55 100644 --- a/temporalio/contrib/openai_agents/_temporal_openai_agents.py +++ b/temporalio/contrib/openai_agents/_temporal_openai_agents.py @@ -5,7 +5,6 @@ from collections.abc import AsyncIterator, Callable, Sequence from contextlib import asynccontextmanager, contextmanager from datetime import timedelta -from typing import Optional, Union from agents import ModelProvider, set_trace_provider from agents.run import get_default_agent_runner, set_default_agent_runner @@ -179,7 +178,7 @@ def __init__( model_params: ModelActivityParameters | None = None, model_provider: ModelProvider | None = None, mcp_server_providers: Sequence[ - Union["StatelessMCPServerProvider", "StatefulMCPServerProvider"] + "StatelessMCPServerProvider | StatefulMCPServerProvider" ] = (), register_activities: bool = True, ) -> None: diff --git a/temporalio/contrib/openai_agents/_temporal_trace_provider.py b/temporalio/contrib/openai_agents/_temporal_trace_provider.py index 37fe33eca..8ea6cadcb 100644 --- a/temporalio/contrib/openai_agents/_temporal_trace_provider.py +++ b/temporalio/contrib/openai_agents/_temporal_trace_provider.py @@ -2,7 +2,7 @@ import uuid from types import TracebackType -from typing import Any, Optional, cast +from typing import Any, cast from agents import SpanData, Trace, TracingProcessor from agents.tracing import ( diff --git a/temporalio/contrib/openai_agents/_trace_interceptor.py b/temporalio/contrib/openai_agents/_trace_interceptor.py index ffa22cc16..d099ae09b 100644 --- a/temporalio/contrib/openai_agents/_trace_interceptor.py +++ b/temporalio/contrib/openai_agents/_trace_interceptor.py @@ -6,7 +6,7 @@ import uuid from collections.abc import Mapping from contextlib import contextmanager -from typing import Any, Optional, Protocol, Type +from typing import Any, Protocol from agents import CustomSpanData, custom_span, get_current_span, trace from agents.tracing import ( @@ -138,6 +138,7 @@ def __init__( payload_converter: The payload converter to use for serializing/deserializing trace context. Defaults to the default Temporal payload converter. """ + super().__init__() self._payload_converter = payload_converter def intercept_client( diff --git a/temporalio/contrib/openai_agents/testing.py b/temporalio/contrib/openai_agents/testing.py index 4acab196a..c4fea60cb 100644 --- a/temporalio/contrib/openai_agents/testing.py +++ b/temporalio/contrib/openai_agents/testing.py @@ -1,7 +1,7 @@ """Testing utilities for OpenAI agents.""" from collections.abc import AsyncIterator, Callable, Sequence -from typing import Optional, Union +from typing import Any from agents import ( AgentOutputSchemaBase, @@ -161,7 +161,7 @@ async def get_response( output_schema: AgentOutputSchemaBase | None, handoffs: list[Handoff], tracing: ModelTracing, - **kwargs, + **kwargs: Any, ) -> ModelResponse: """Get a response from the mocked model, by calling the callable passed to the constructor.""" return self.fn() @@ -175,7 +175,7 @@ def stream_response( output_schema: AgentOutputSchemaBase | None, handoffs: list[Handoff], tracing: ModelTracing, - **kwargs, + **kwargs: Any, ) -> AsyncIterator[TResponseStreamEvent]: """Get a streamed response from the model. Unimplemented.""" raise NotImplementedError() @@ -268,7 +268,7 @@ async def __aenter__(self) -> "AgentEnvironment": return self - async def __aexit__(self, *args) -> None: + async def __aexit__(self, *args: Any) -> None: """Exit the async context manager.""" # No cleanup needed currently pass diff --git a/temporalio/contrib/openai_agents/workflow.py b/temporalio/contrib/openai_agents/workflow.py index 19d6621ad..772bf4555 100644 --- a/temporalio/contrib/openai_agents/workflow.py +++ b/temporalio/contrib/openai_agents/workflow.py @@ -7,7 +7,7 @@ from collections.abc import Callable from contextlib import AbstractAsyncContextManager from datetime import timedelta -from typing import Any, Optional, Type +from typing import Any import nexusrpc from agents import ( @@ -203,7 +203,7 @@ def nexus_operation_as_tool( >>> # Use tool with an OpenAI agent """ - def operation_callable(input): + def operation_callable(input: Any): # type: ignore[reportUnusedParameter] raise NotImplementedError("This function definition is used as a type only") operation_callable.__annotations__ = { @@ -214,7 +214,7 @@ def operation_callable(input): schema = function_schema(operation_callable) - async def run_operation(ctx: RunContextWrapper[Any], input: str) -> Any: + async def run_operation(_ctx: RunContextWrapper[Any], input: str) -> Any: try: json_data = json.loads(input) except Exception as e: diff --git a/temporalio/contrib/pydantic.py b/temporalio/contrib/pydantic.py index 5de19f180..c5f2deb41 100644 --- a/temporalio/contrib/pydantic.py +++ b/temporalio/contrib/pydantic.py @@ -14,7 +14,7 @@ """ from dataclasses import dataclass -from typing import Any, Optional, Type +from typing import Any from pydantic import TypeAdapter from pydantic_core import SchemaSerializer, to_json diff --git a/temporalio/converter.py b/temporalio/converter.py index 8af1e1dc6..3849a47f4 100644 --- a/temporalio/converter.py +++ b/temporalio/converter.py @@ -10,6 +10,7 @@ import json import sys import traceback +import typing import uuid import warnings from abc import ABC, abstractmethod @@ -22,20 +23,13 @@ from typing import ( Any, ClassVar, - Dict, - List, Literal, NewType, - Optional, - Tuple, - Type, TypeVar, - Union, get_type_hints, overload, ) -import google.protobuf.duration_pb2 import google.protobuf.json_format import google.protobuf.message import google.protobuf.symbol_database @@ -46,7 +40,6 @@ import temporalio.api.common.v1 import temporalio.api.enums.v1 import temporalio.api.failure.v1 -import temporalio.api.sdk.v1 import temporalio.common import temporalio.exceptions import temporalio.types @@ -56,7 +49,7 @@ from dateutil import parser # type: ignore # StrEnum is available in 3.11+ if sys.version_info >= (3, 11): - from enum import StrEnum + from enum import StrEnum # type: ignore[reportUnreachable] from types import UnionType @@ -151,7 +144,7 @@ class WithSerializationContext(ABC): to_payload/from_payload, etc) to use the context. """ - def with_context(self, context: SerializationContext) -> Self: + def with_context(self, context: SerializationContext) -> Self: # type: ignore[reportUnusedParameter] """Return a copy of this object configured to use the given context. Args: @@ -549,7 +542,7 @@ def to_payload(self, value: Any) -> temporalio.api.common.v1.Payload | None: """See base class.""" if ( isinstance(value, google.protobuf.message.Message) - and value.DESCRIPTOR is not None + and value.DESCRIPTOR is not None # type:ignore[reportUnnecessaryComparison] ): # We have to convert to dict then to JSON because MessageToJson does # not have a compact option removing spaces and newlines @@ -599,7 +592,7 @@ def to_payload(self, value: Any) -> temporalio.api.common.v1.Payload | None: """See base class.""" if ( isinstance(value, google.protobuf.message.Message) - and value.DESCRIPTOR is not None + and value.DESCRIPTOR is not None # type:ignore[reportUnnecessaryComparison] ): return temporalio.api.common.v1.Payload( metadata={ @@ -1476,7 +1469,7 @@ def encode_search_attribute_values( vals: List of values to convert. """ if not isinstance(vals, list): - raise TypeError("Search attribute values must be lists") + raise TypeError("Search attribute values must be lists") # type:ignore[reportUnreachable] # Confirm all types are the same val_type: type | None = None # Convert dates to strings @@ -1502,7 +1495,7 @@ def encode_search_attribute_values( return default().payload_converter.to_payloads([safe_vals])[0] -def _encode_maybe_typed_search_attributes( +def _encode_maybe_typed_search_attributes( # type:ignore[reportUnusedFunction] non_typed_attributes: temporalio.common.SearchAttributes | None, typed_attributes: temporalio.common.TypedSearchAttributes | None, api: temporalio.api.common.v1.SearchAttributes, @@ -1524,10 +1517,10 @@ def _get_iso_datetime_parser() -> Callable[[str], datetime]: A callable to parse date strings into datetimes. """ if sys.version_info >= (3, 11): - return datetime.fromisoformat # noqa + return datetime.fromisoformat # type:ignore[reportUnreachable] # noqa else: # Isolate import for py > 3.11, as dependency only installed for < 3.11 - return parser.isoparse + return parser.isoparse # type:ignore[reportUnreachable] def decode_search_attributes( @@ -1607,7 +1600,7 @@ def decode_typed_search_attributes( return temporalio.common.TypedSearchAttributes(pairs) -def _decode_search_attribute_value( +def _decode_search_attribute_value( # type:ignore[reportUnusedFunction] payload: temporalio.api.common.v1.Payload, ) -> temporalio.common.SearchAttributeValue: val = default().payload_converter.from_payload(payload) @@ -1698,7 +1691,7 @@ def value_to_type( raise TypeError(f"Value {value} not in literal values {type_args}") return value - is_union = origin is Union + is_union = origin is typing.Union # type:ignore[reportDeprecated] is_union = is_union or isinstance(origin, UnionType) # Union @@ -1837,7 +1830,7 @@ def value_to_type( # StrEnum, available in 3.11+ if sys.version_info >= (3, 11): - if inspect.isclass(hint) and issubclass(hint, StrEnum): + if inspect.isclass(hint) and issubclass(hint, StrEnum): # type:ignore[reportUnreachable] if not isinstance(value, str): raise TypeError( f"Cannot convert to enum {hint}, value not a string, value is {type(value)}" diff --git a/temporalio/envconfig.py b/temporalio/envconfig.py index 34078ddfe..1406270a2 100644 --- a/temporalio/envconfig.py +++ b/temporalio/envconfig.py @@ -9,16 +9,16 @@ from collections.abc import Mapping from dataclasses import dataclass, field from pathlib import Path -from typing import Any, Dict, Literal, Optional, TypeAlias, Union, cast +from typing import Any, Literal, TypeAlias, cast from typing_extensions import Self, TypedDict import temporalio.service from temporalio.bridge.temporal_sdk_bridge import envconfig as _bridge_envconfig -DataSource: TypeAlias = Union[ - Path, str, bytes -] # str represents a file contents, bytes represents raw data +DataSource: TypeAlias = ( + Path | str | bytes +) # str represents a file contents, bytes represents raw data # We define typed dictionaries for what these configs look like as TOML. @@ -76,7 +76,7 @@ def _source_to_path_and_data( elif isinstance(source, bytes): data = source elif source is not None: - raise TypeError( + raise TypeError( # type: ignore[reportUnreachable] "config_source must be one of pathlib.Path, str, bytes, or None, " f"but got {type(source).__name__}" ) @@ -93,7 +93,7 @@ def _read_source(source: DataSource | None) -> bytes | None: return source.encode("utf-8") if isinstance(source, bytes): return source - raise TypeError( + raise TypeError( # type: ignore[reportUnreachable] f"Source must be one of pathlib.Path, str, or bytes, but got {type(source).__name__}" ) @@ -248,7 +248,7 @@ def to_client_connect_config(self) -> ClientConnectConfig: config["rpc_metadata"] = self.grpc_meta # Cast to ClientConnectConfig - this is safe because we've only included non-None values - return cast(ClientConnectConfig, config) + return cast(ClientConnectConfig, config) # type: ignore[reportInvalidCast] @staticmethod def load( diff --git a/temporalio/exceptions.py b/temporalio/exceptions.py index 61c04166d..f8f8ca20c 100644 --- a/temporalio/exceptions.py +++ b/temporalio/exceptions.py @@ -4,9 +4,8 @@ from collections.abc import Sequence from datetime import timedelta from enum import IntEnum -from typing import Any, Optional, Tuple +from typing import Any -import temporalio.api.common.v1 import temporalio.api.enums.v1 import temporalio.api.failure.v1 diff --git a/temporalio/nexus/_decorators.py b/temporalio/nexus/_decorators.py index dfdecc89c..795bf3383 100644 --- a/temporalio/nexus/_decorators.py +++ b/temporalio/nexus/_decorators.py @@ -2,9 +2,7 @@ from collections.abc import Awaitable, Callable from typing import ( - Optional, TypeVar, - Union, overload, ) diff --git a/temporalio/nexus/_link_conversion.py b/temporalio/nexus/_link_conversion.py index b2a219f96..a47c002a9 100644 --- a/temporalio/nexus/_link_conversion.py +++ b/temporalio/nexus/_link_conversion.py @@ -6,7 +6,6 @@ from typing import ( TYPE_CHECKING, Any, - Optional, ) import nexusrpc @@ -74,6 +73,8 @@ def workflow_event_to_nexus_link( query_params = _request_id_reference_to_query_params( workflow_event.request_id_ref ) + case _: + pass # urllib will omit '//' from the url if netloc is empty so we add the scheme manually url = f"{scheme}://{urllib.parse.urlunparse(('', '', path, '', query_params, ''))}" diff --git a/temporalio/nexus/_operation_context.py b/temporalio/nexus/_operation_context.py index 335e70960..8786be00b 100644 --- a/temporalio/nexus/_operation_context.py +++ b/temporalio/nexus/_operation_context.py @@ -134,7 +134,7 @@ def _nexus_backing_workflow_start_context() -> Generator[None]: _temporal_nexus_backing_workflow_start_context.reset(token) -def _in_nexus_backing_workflow_start_context() -> bool: +def _in_nexus_backing_workflow_start_context() -> bool: # type:ignore[reportUnusedClass] return _temporal_nexus_backing_workflow_start_context.get(False) diff --git a/temporalio/nexus/_token.py b/temporalio/nexus/_token.py index a19d26d05..51e668baa 100644 --- a/temporalio/nexus/_token.py +++ b/temporalio/nexus/_token.py @@ -3,7 +3,7 @@ import base64 import json from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Generic, Literal, Optional +from typing import TYPE_CHECKING, Any, Generic, Literal from nexusrpc import OutputT diff --git a/temporalio/nexus/_util.py b/temporalio/nexus/_util.py index 6817e8f02..48d3ad644 100644 --- a/temporalio/nexus/_util.py +++ b/temporalio/nexus/_util.py @@ -7,8 +7,6 @@ from collections.abc import Awaitable, Callable from typing import ( Any, - Optional, - Type, TypeVar, ) diff --git a/temporalio/plugin.py b/temporalio/plugin.py index 9202bc1f3..db917e337 100644 --- a/temporalio/plugin.py +++ b/temporalio/plugin.py @@ -8,10 +8,8 @@ from contextlib import AbstractAsyncContextManager, asynccontextmanager from typing import ( Any, - Optional, - Type, + TypeAlias, TypeVar, - Union, cast, ) @@ -31,7 +29,7 @@ T = TypeVar("T") -PluginParameter = Union[None, T, Callable[[Optional[T]], T]] +PluginParameter: TypeAlias = None | T | Callable[[T | None], T] class SimplePlugin(temporalio.client.Plugin, temporalio.worker.Plugin): @@ -234,7 +232,7 @@ def _resolve_parameter(existing: T | None, parameter: PluginParameter[T]) -> T | if parameter is None: return existing elif callable(parameter): - return cast(Callable[[Optional[T]], Optional[T]], parameter)(existing) + return cast(Callable[[T | None], T | None], parameter)(existing) else: return parameter @@ -245,8 +243,8 @@ def _resolve_append_parameter( if parameter is None: return existing elif callable(parameter): - return cast( - Callable[[Optional[Sequence[T]]], Optional[Sequence[T]]], parameter - )(existing) + return cast(Callable[[Sequence[T] | None], Sequence[T] | None], parameter)( + existing + ) else: return list(existing or []) + list(parameter) diff --git a/temporalio/runtime.py b/temporalio/runtime.py index f0fc7ec30..b151f96f0 100644 --- a/temporalio/runtime.py +++ b/temporalio/runtime.py @@ -12,9 +12,7 @@ ClassVar, Generic, NewType, - Optional, TypeVar, - Union, ) from typing_extensions import Protocol, Self @@ -38,7 +36,6 @@ def default(self) -> Runtime: "Cannot create default Runtime after Runtime.prevent_default has been called" ) self._default_runtime = Runtime(telemetry=TelemetryConfig()) - self._default_created = True return self._default_runtime def prevent_default(self): diff --git a/temporalio/service.py b/temporalio/service.py index 465003628..78a21821b 100644 --- a/temporalio/service.py +++ b/temporalio/service.py @@ -12,7 +12,7 @@ from dataclasses import dataclass, field from datetime import timedelta from enum import IntEnum -from typing import ClassVar, Optional, Tuple, Type, TypeVar, Union +from typing import ClassVar, TypeVar import google.protobuf.message @@ -22,6 +22,7 @@ import temporalio.bridge.services_generated import temporalio.exceptions import temporalio.runtime +from temporalio.bridge.client import RPCError as BridgeRPCError __version__ = "1.21.1" @@ -376,7 +377,7 @@ async def _rpc_call( if LOG_PROTOS: logger.debug("Service %s response from %s: %s", service, rpc, resp) return resp - except temporalio.bridge.client.RPCError as err: + except BridgeRPCError as err: # Intentionally swallowing the cause instead of using "from" status, message, details = err.args raise RPCError(message, RPCStatusCode(status), details) diff --git a/temporalio/testing/_activity.py b/temporalio/testing/_activity.py index 99150381c..0098a91e1 100644 --- a/temporalio/testing/_activity.py +++ b/temporalio/testing/_activity.py @@ -8,7 +8,7 @@ from collections.abc import Callable from contextlib import contextmanager from datetime import datetime, timedelta, timezone -from typing import Any, Optional, Set, TypeVar +from typing import Any, TypeVar from typing_extensions import ParamSpec @@ -182,7 +182,7 @@ def __init__( ) self.task: asyncio.Task | None = None - def run(self, *args, **kwargs) -> Any: + def run(self, *args: Any, **kwargs: Any) -> Any: if self.cancel_thread_raiser: thread_id = threading.current_thread().ident if thread_id is not None: diff --git a/temporalio/testing/_workflow.py b/temporalio/testing/_workflow.py index e651876e9..62da91b6e 100644 --- a/temporalio/testing/_workflow.py +++ b/temporalio/testing/_workflow.py @@ -9,10 +9,6 @@ from datetime import datetime, timedelta, timezone from typing import ( Any, - List, - Optional, - Type, - Union, cast, ) @@ -27,7 +23,6 @@ import temporalio.exceptions import temporalio.runtime import temporalio.service -import temporalio.types import temporalio.worker logger = logging.getLogger(__name__) @@ -79,10 +74,10 @@ async def start_local( plugins: Sequence[temporalio.client.Plugin] = [], default_workflow_query_reject_condition: None | (temporalio.common.QueryRejectCondition) = None, - retry_config: temporalio.client.RetryConfig | None = None, + retry_config: temporalio.service.RetryConfig | None = None, rpc_metadata: Mapping[str, str | bytes] = {}, identity: str | None = None, - tls: bool | temporalio.client.TLSConfig = False, + tls: bool | temporalio.service.TLSConfig = False, ip: str = "127.0.0.1", port: int | None = None, download_dest_dir: str | None = None, @@ -224,7 +219,7 @@ async def start_local( try: await server.shutdown() except: - logger.warn( + logger.warning( "Failed stopping local server on client connection failure", exc_info=True, ) @@ -239,7 +234,7 @@ async def start_time_skipping( plugins: Sequence[temporalio.client.Plugin] = [], default_workflow_query_reject_condition: None | (temporalio.common.QueryRejectCondition) = None, - retry_config: temporalio.client.RetryConfig | None = None, + retry_config: temporalio.service.RetryConfig | None = None, rpc_metadata: Mapping[str, str | bytes] = {}, identity: str | None = None, port: int | None = None, @@ -344,7 +339,7 @@ async def start_time_skipping( try: await server.shutdown() except: - logger.warn( + logger.warning( "Failed stopping test server on client connection failure", exc_info=True, ) @@ -362,7 +357,7 @@ async def __aenter__(self) -> WorkflowEnvironment: """Noop for ``async with`` support.""" return self - async def __aexit__(self, *args) -> None: + async def __aexit__(self, *args: Any) -> None: """For ``async with`` support to just call :py:meth:`shutdown`.""" await self.shutdown() diff --git a/temporalio/types.py b/temporalio/types.py index c8d7824e3..4b217ea23 100644 --- a/temporalio/types.py +++ b/temporalio/types.py @@ -1,7 +1,7 @@ """Advanced types.""" from collections.abc import Awaitable, Callable -from typing import Any, Type, TypeVar, Union +from typing import Any, TypeVar from typing_extensions import ParamSpec, Protocol @@ -15,11 +15,11 @@ CallableAsyncType = TypeVar("CallableAsyncType", bound=Callable[..., Awaitable[Any]]) CallableSyncOrAsyncType = TypeVar( "CallableSyncOrAsyncType", - bound=Callable[..., Union[Any, Awaitable[Any]]], + bound=Callable[..., Any | Awaitable[Any]], ) CallableSyncOrAsyncReturnNoneType = TypeVar( "CallableSyncOrAsyncReturnNoneType", - bound=Callable[..., Union[None, Awaitable[None]]], + bound=Callable[..., None | Awaitable[None]], ) MultiParamSpec = ParamSpec("MultiParamSpec") diff --git a/temporalio/worker/__init__.py b/temporalio/worker/__init__.py index 8388be24d..55966b35d 100644 --- a/temporalio/worker/__init__.py +++ b/temporalio/worker/__init__.py @@ -1,5 +1,6 @@ """Worker for processing Temporal workflows and/or activities.""" +from ..common import WorkerDeploymentVersion from ._activity import SharedHeartbeatSender, SharedStateManager from ._interceptor import ( ActivityInboundInterceptor, @@ -55,7 +56,6 @@ Worker, WorkerConfig, WorkerDeploymentConfig, - WorkerDeploymentVersion, ) from ._workflow_instance import ( UnsandboxedWorkflowRunner, diff --git a/temporalio/worker/_activity.py b/temporalio/worker/_activity.py index f74ee7872..93249fad5 100644 --- a/temporalio/worker/_activity.py +++ b/temporalio/worker/_activity.py @@ -21,8 +21,6 @@ from typing import ( Any, NoReturn, - Optional, - Union, ) import google.protobuf.duration_pb2 @@ -627,7 +625,7 @@ async def _execute_activity( impl.init(_ActivityOutboundImpl(self, running_activity.info)) return await impl.execute_activity(input) - def assert_activity_valid(self, activity) -> None: + def assert_activity_valid(self, activity: str) -> None: if self._dynamic_activity: return activity_def = self._activities.get(activity) diff --git a/temporalio/worker/_command_aware_visitor.py b/temporalio/worker/_command_aware_visitor.py index 2301f6ed6..2d7f3990b 100644 --- a/temporalio/worker/_command_aware_visitor.py +++ b/temporalio/worker/_command_aware_visitor.py @@ -4,7 +4,6 @@ from collections.abc import Iterator from contextlib import contextmanager from dataclasses import dataclass -from typing import Optional from temporalio.api.enums.v1.command_type_pb2 import CommandType from temporalio.bridge._visitor import PayloadVisitor, VisitorFunctions diff --git a/temporalio/worker/_interceptor.py b/temporalio/worker/_interceptor.py index d3b838679..d0d83da20 100644 --- a/temporalio/worker/_interceptor.py +++ b/temporalio/worker/_interceptor.py @@ -9,14 +9,10 @@ from typing import ( Any, Generic, - List, NoReturn, - Optional, - Type, - Union, ) -import nexusrpc.handler +import nexusrpc from nexusrpc import InputT, OutputT import temporalio.activity @@ -49,7 +45,8 @@ def intercept_activity( return next def workflow_interceptor_class( - self, input: WorkflowInterceptorClassInput + self, + input: WorkflowInterceptorClassInput, # type:ignore[reportUnusedParameter] ) -> type[WorkflowInboundInterceptor] | None: """Class that will be instantiated and used to intercept workflows. diff --git a/temporalio/worker/_nexus.py b/temporalio/worker/_nexus.py index bc06fbd4a..8f6226ea3 100644 --- a/temporalio/worker/_nexus.py +++ b/temporalio/worker/_nexus.py @@ -33,6 +33,7 @@ import temporalio.common import temporalio.converter import temporalio.nexus +from temporalio.bridge.worker import PollShutdownError from temporalio.exceptions import ( ApplicationError, WorkflowAlreadyStartedError, @@ -60,7 +61,7 @@ def cancel(self, reason: str): self.task.cancel() -class _NexusWorker: +class _NexusWorker: # type:ignore[reportUnusedClass] def __init__( self, *, @@ -165,7 +166,7 @@ async def raise_from_exception_queue() -> NoReturn: else: raise NotImplementedError(f"Invalid Nexus task: {nexus_task}") - except temporalio.bridge.worker.PollShutdownError: + except PollShutdownError: exception_task.cancel() return @@ -183,7 +184,7 @@ async def drain_poll_queue(self) -> None: ) completion.error.failure.message = "Worker shutting down" await self._bridge_worker().complete_nexus_task(completion) - except temporalio.bridge.worker.PollShutdownError: + except PollShutdownError: return # Only call this after run()/drain_poll_queue() have returned. This will not @@ -460,14 +461,14 @@ class _DummyPayloadSerializer: data_converter: temporalio.converter.DataConverter payload: temporalio.api.common.v1.Payload - async def serialize(self, value: Any) -> nexusrpc.Content: + async def serialize(self, value: Any) -> nexusrpc.Content: # type:ignore[reportUnusedParameter] raise NotImplementedError( "The serialize method of the Serializer is not used by handlers" ) async def deserialize( self, - content: nexusrpc.Content, + content: nexusrpc.Content, # type:ignore[reportUnusedParameter] as_type: type[Any] | None = None, ) -> Any: try: diff --git a/temporalio/worker/_replayer.py b/temporalio/worker/_replayer.py index 26c5961d4..7c93a453b 100644 --- a/temporalio/worker/_replayer.py +++ b/temporalio/worker/_replayer.py @@ -8,7 +8,6 @@ from collections.abc import AsyncIterator, Mapping, Sequence from contextlib import AbstractAsyncContextManager, asynccontextmanager from dataclasses import dataclass -from typing import Dict, Optional, Type from typing_extensions import TypedDict @@ -180,7 +179,7 @@ def workflow_replay_iterator( replayed. """ - def make_lambda(plugin, next): + def make_lambda(plugin, next): # type: ignore[reportMissingParameterType] return lambda r, hs: plugin.run_replayer(r, hs, next) next_function = lambda r, hs: r._workflow_replay_iterator(hs) @@ -204,7 +203,7 @@ async def _workflow_replay_iterator( # Create eviction hook def on_eviction_hook( - run_id: str, + _run_id: str, remove_job: temporalio.bridge.proto.workflow_activation.RemoveFromCache, ) -> None: nonlocal last_replay_failure diff --git a/temporalio/worker/_tuning.py b/temporalio/worker/_tuning.py index 381be6960..39ab8343a 100644 --- a/temporalio/worker/_tuning.py +++ b/temporalio/worker/_tuning.py @@ -6,11 +6,10 @@ from collections.abc import Callable from dataclasses import dataclass from datetime import timedelta -from typing import Any, Literal, Optional, Protocol, TypeAlias, Union, runtime_checkable - -from typing_extensions import Self +from typing import Any, Literal, Protocol, TypeAlias, runtime_checkable import temporalio.bridge.worker +from temporalio.bridge.worker import BridgeCustomSlotSupplier from temporalio.common import WorkerDeploymentVersion _DEFAULT_RESOURCE_SLOTS_MAX = 500 @@ -131,9 +130,9 @@ class NexusSlotInfo(Protocol): operation: str -SlotInfo: TypeAlias = Union[ - WorkflowSlotInfo, ActivitySlotInfo, LocalActivitySlotInfo, NexusSlotInfo -] +SlotInfo: TypeAlias = ( + WorkflowSlotInfo | ActivitySlotInfo | LocalActivitySlotInfo | NexusSlotInfo +) # WARNING: This must match Rust worker::SlotMarkUsedCtx @@ -222,9 +221,9 @@ def release_slot(self, ctx: SlotReleaseContext) -> None: ... -SlotSupplier: TypeAlias = Union[ - FixedSizeSlotSupplier, ResourceBasedSlotSupplier, CustomSlotSupplier -] +SlotSupplier: TypeAlias = ( + FixedSizeSlotSupplier | ResourceBasedSlotSupplier | CustomSlotSupplier +) class _BridgeSlotSupplierWrapper: @@ -301,11 +300,9 @@ def _to_bridge_slot_supplier( ), ) elif isinstance(slot_supplier, CustomSlotSupplier): - return temporalio.bridge.worker.BridgeCustomSlotSupplier( - _BridgeSlotSupplierWrapper(slot_supplier) - ) + return BridgeCustomSlotSupplier(_BridgeSlotSupplierWrapper(slot_supplier)) else: - raise TypeError(f"Unknown slot supplier type: {slot_supplier}") + raise TypeError(f"Unknown slot supplier type: {slot_supplier}") # type:ignore[reportUnreachable] class WorkerTuner(ABC): diff --git a/temporalio/worker/_worker.py b/temporalio/worker/_worker.py index bbe02c54e..f664c0877 100644 --- a/temporalio/worker/_worker.py +++ b/temporalio/worker/_worker.py @@ -13,11 +13,7 @@ from datetime import timedelta from typing import ( Any, - List, - Optional, - Type, TypeAlias, - Union, cast, ) @@ -82,10 +78,7 @@ def _to_bridge(self) -> temporalio.bridge.worker.PollerBehavior: ) -PollerBehavior: TypeAlias = Union[ - PollerBehaviorSimpleMaximum, - PollerBehaviorAutoscaling, -] +PollerBehavior: TypeAlias = PollerBehaviorSimpleMaximum | PollerBehaviorAutoscaling class Worker: @@ -471,7 +464,7 @@ def _init_from_config(self, client: temporalio.client.Client, config: WorkerConf == temporalio.common.VersioningBehavior.UNSPECIFIED ) - def check_activity(activity): + def check_activity(activity: str): if self._activity_worker is None: raise ValueError( f"Activity function {activity} " @@ -711,7 +704,7 @@ async def run(self) -> None: explicit shutdown instead. """ - def make_lambda(plugin, next): + def make_lambda(plugin: Plugin, next: Callable[[Worker], Awaitable[None]]): return lambda w: plugin.run_worker(w, next) next_function = lambda w: w._run() @@ -865,7 +858,7 @@ async def run(): self._async_context_run_task = asyncio.create_task(run()) return self - async def __aexit__(self, exc_type: type[BaseException] | None, *args) -> None: + async def __aexit__(self, exc_type: type[BaseException] | None, *args: Any) -> None: """Same as :py:meth:`shutdown` for use by ``async with``. Note, this will raise the worker fatal error if one occurred and the @@ -1077,7 +1070,7 @@ def _extract_bridge_client_for_worker( elif hasattr(client.service_client, "worker_service_client"): bridge_client = client.service_client.worker_service_client if not isinstance(bridge_client, temporalio.service._BridgeServiceClient): - raise TypeError( + raise TypeError( # type: ignore[reportUnreachable] "Client's worker_service_client cannot be used for a worker" ) else: diff --git a/temporalio/worker/_workflow.py b/temporalio/worker/_workflow.py index 09c429c30..16e0de5e8 100644 --- a/temporalio/worker/_workflow.py +++ b/temporalio/worker/_workflow.py @@ -12,27 +12,17 @@ from dataclasses import dataclass from datetime import timezone from types import TracebackType -from typing import ( - Dict, - List, - Optional, - Set, - Type, -) -import temporalio.activity import temporalio.api.common.v1 -import temporalio.bridge._visitor -import temporalio.bridge.client import temporalio.bridge.proto.workflow_activation import temporalio.bridge.proto.workflow_completion import temporalio.bridge.runtime import temporalio.bridge.worker -import temporalio.client import temporalio.common import temporalio.converter import temporalio.exceptions import temporalio.workflow +from temporalio.bridge.worker import PollShutdownError from . import _command_aware_visitor from ._interceptor import ( @@ -53,7 +43,7 @@ LOG_PROTOS = False -class _WorkflowWorker: +class _WorkflowWorker: # type:ignore[reportUnusedClass] def __init__( self, *, @@ -71,12 +61,10 @@ def __init__( debug_mode: bool, disable_eager_activity_execution: bool, metric_meter: temporalio.common.MetricMeter, - on_eviction_hook: None - | ( - Callable[ - [str, temporalio.bridge.proto.workflow_activation.RemoveFromCache], None - ] - ), + on_eviction_hook: Callable[ + [str, temporalio.bridge.proto.workflow_activation.RemoveFromCache], None + ] + | None, disable_safe_eviction: bool, should_enforce_versioning_behavior: bool, assert_local_activity_valid: Callable[[str], None], @@ -186,7 +174,7 @@ async def run(self) -> None: # when done. task = asyncio.create_task(self._handle_activation(act)) setattr(task, "__temporal_task_tag", task_tag) - except temporalio.bridge.worker.PollShutdownError: + except PollShutdownError: pass except Exception as err: raise RuntimeError("Workflow worker failed") from err @@ -224,7 +212,7 @@ async def drain_poll_queue(self) -> None: ) completion.failed.failure.message = "Worker shutting down" await self._bridge_worker().complete_workflow_activation(completion) - except temporalio.bridge.worker.PollShutdownError: + except PollShutdownError: return async def _handle_activation( diff --git a/temporalio/worker/_workflow_instance.py b/temporalio/worker/_workflow_instance.py index 1139be042..10fd594fd 100644 --- a/temporalio/worker/_workflow_instance.py +++ b/temporalio/worker/_workflow_instance.py @@ -14,6 +14,7 @@ import traceback import warnings from abc import ABC, abstractmethod +from collections import deque from collections.abc import ( Awaitable, Callable, @@ -31,22 +32,14 @@ from enum import IntEnum from typing import ( Any, - Deque, - Dict, Generic, - List, NoReturn, - Optional, - Set, - Tuple, - Type, TypeAlias, TypeVar, - Union, cast, ) -import nexusrpc.handler +import nexusrpc from nexusrpc import InputT, OutputT from typing_extensions import Self, TypedDict, TypeVarTuple, Unpack @@ -124,7 +117,8 @@ def create_instance(self, det: WorkflowInstanceDetails) -> WorkflowInstance: raise NotImplementedError def set_worker_level_failure_exception_types( - self, types: Sequence[type[BaseException]] + self, + types: Sequence[type[BaseException]], # type:ignore[reportUnusedParameter] ) -> None: """Set worker-level failure exception types that will be used to validate in the sandbox when calling ``prepare_workflow``. @@ -260,7 +254,7 @@ def __init__(self, det: WorkflowInstanceDetails) -> None: # Lazily loaded self._untyped_converted_memo: MutableMapping[str, Any] | None = None # Handles which are ready to run on the next event loop iteration - self._ready: Deque[asyncio.Handle] = collections.deque() + self._ready: deque[asyncio.Handle] = collections.deque() self._conditions: list[tuple[Callable[[], bool], asyncio.Future]] = [] # Keyed by seq self._pending_timers: dict[int, _TimerHandle] = {} @@ -511,7 +505,9 @@ def activate( ) self._current_completion.failed.failure.application_failure_info.SetInParent() - def is_completion(command): + def is_completion( + command: temporalio.bridge.proto.workflow_commands.workflow_commands_pb2.WorkflowCommand, + ): return ( command.HasField("complete_workflow_execution") or command.HasField("continue_as_new_workflow_execution") @@ -571,7 +567,7 @@ def _apply( raise RuntimeError(f"Unrecognized job: {job.WhichOneof('variant')}") def _apply_cancel_workflow( - self, job: temporalio.bridge.proto.workflow_activation.CancelWorkflow + self, _job: temporalio.bridge.proto.workflow_activation.CancelWorkflow ) -> None: self._cancel_requested = True # TODO(cretz): Details or cancel message or whatever? @@ -772,7 +768,7 @@ def _apply_notify_has_patch( self._patches_notified.add(job.patch_id) def _apply_remove_from_cache( - self, job: temporalio.bridge.proto.workflow_activation.RemoveFromCache + self, _job: temporalio.bridge.proto.workflow_activation.RemoveFromCache ) -> None: self._deleting = True self._cancel_requested = True @@ -1040,7 +1036,7 @@ def _apply_signal_workflow( self._process_signal_job(signal_defn, job) def _apply_initialize_workflow( - self, job: temporalio.bridge.proto.workflow_activation.InitializeWorkflow + self, _job: temporalio.bridge.proto.workflow_activation.InitializeWorkflow ) -> None: # Async call to run on the scheduler thread. This will be wrapped in # another function which applies exception handling. @@ -1135,7 +1131,7 @@ def workflow_continue_as_new( name = defn.name arg_types = defn.arg_types elif workflow is not None: - raise TypeError("Workflow must be None, a string, or callable") + raise TypeError("Workflow must be None, a string, or callable") # type:ignore[reportUnreachable] self._outbound.continue_as_new( ContinueAsNewInput( @@ -1152,8 +1148,6 @@ def workflow_continue_as_new( versioning_intent=versioning_intent, ) ) - # TODO(cretz): Why can't MyPy infer the above never returns? - raise RuntimeError("Unreachable") def workflow_extern_functions(self) -> Mapping[str, Callable]: return self._extern_functions @@ -2308,7 +2302,7 @@ def _process_signal_job( job.signal_name, defn.unfinished_policy ) - def done_callback(f): + def done_callback(_f: Any): self._in_progress_signals.pop(id, None) task = self.create_task( @@ -2943,9 +2937,6 @@ def cancel(self, msg: Any | None = None) -> bool: # the cancel (i.e. cancelled before started) if not self._started and not self.done(): self._apply_cancel_command(self._instance._add_command()) - # Message not supported in older versions - if sys.version_info < (3, 9): - return super().cancel() return super().cancel(msg) def _resolve_success(self, result: Any) -> None: diff --git a/temporalio/worker/workflow_sandbox/_importer.py b/temporalio/worker/workflow_sandbox/_importer.py index 8dde47254..010c0c082 100644 --- a/temporalio/worker/workflow_sandbox/_importer.py +++ b/temporalio/worker/workflow_sandbox/_importer.py @@ -19,12 +19,7 @@ from contextlib import ExitStack, contextmanager from typing import ( Any, - Dict, Generic, - List, - Optional, - Set, - Tuple, TypeVar, no_type_check, ) @@ -79,7 +74,7 @@ def __init__( ) if builtin_matcher: - def restrict_built_in(name: str, orig: Any, *args, **kwargs): + def restrict_built_in(name: str, orig: Any, *args: Any, **kwargs: Any): # Check if restricted against matcher if ( builtin_matcher @@ -147,7 +142,9 @@ def applied(self) -> Iterator[None]: try: with _thread_local_sys_modules.applied(sys, "modules", self.new_modules): with _thread_local_import.applied( - builtins, "__import__", self.import_func + builtins, + "__import__", + self.import_func, # type: ignore[reportArgumentType] ): with self._builtins_restricted(): yield None @@ -480,15 +477,11 @@ def __setitem__(self, key: str, value: types.ModuleType) -> None: def __or__( self, other: Mapping[str, types.ModuleType] ) -> dict[str, types.ModuleType]: - if sys.version_info < (3, 9): - raise NotImplementedError return self.current.__or__(other) # type: ignore[operator] def __ior__( self, other: Mapping[str, types.ModuleType] ) -> dict[str, types.ModuleType]: - if sys.version_info < (3, 9): - raise NotImplementedError return self.current.__ior__(other) __ror__ = __or__ @@ -497,7 +490,7 @@ def copy(self) -> dict[str, types.ModuleType]: return self.current.copy() @classmethod - def fromkeys(cls, *args, **kwargs) -> Any: + def fromkeys(cls, *args: Any, **kwargs: Any) -> Any: return dict.fromkeys(*args, **kwargs) def _lazily_passthrough_if_available(self, key: str) -> types.ModuleType | None: diff --git a/temporalio/worker/workflow_sandbox/_in_sandbox.py b/temporalio/worker/workflow_sandbox/_in_sandbox.py index 3756749ca..eea8f6940 100644 --- a/temporalio/worker/workflow_sandbox/_in_sandbox.py +++ b/temporalio/worker/workflow_sandbox/_in_sandbox.py @@ -6,7 +6,7 @@ import dataclasses import logging -from typing import Any, Optional, Type +from typing import Any import temporalio.bridge.proto.workflow_activation import temporalio.bridge.proto.workflow_completion diff --git a/temporalio/worker/workflow_sandbox/_restrictions.py b/temporalio/worker/workflow_sandbox/_restrictions.py index 34f517de1..126b1cf5a 100644 --- a/temporalio/worker/workflow_sandbox/_restrictions.py +++ b/temporalio/worker/workflow_sandbox/_restrictions.py @@ -23,11 +23,6 @@ from typing import ( Any, ClassVar, - Dict, - Optional, - Set, - Tuple, - Type, TypeVar, cast, ) @@ -38,7 +33,7 @@ HAVE_PYDANTIC = True except ImportError: - HAVE_PYDANTIC = False + HAVE_PYDANTIC = False # type: ignore[reportConstantRedefinition] import temporalio.exceptions import temporalio.workflow @@ -873,7 +868,7 @@ def __init__( if hasattr(access_func, "__get__"): # A Python function, can be turned into a bound method. - def _bind_func(instance: _RestrictedProxy, obj: Any) -> Callable: + def _bind_func(_instance: _RestrictedProxy, obj: Any) -> Callable: return access_func.__get__(obj, type(obj)) # type: ignore bind_func = _bind_func @@ -881,7 +876,7 @@ def _bind_func(instance: _RestrictedProxy, obj: Any) -> Callable: elif access_func is not None: # A C function, use partial to bind the first argument. - def _bind_func(instance: _RestrictedProxy, obj: Any) -> Callable: + def _bind_func(_instance: _RestrictedProxy, obj: Any) -> Callable: return functools.partial(access_func, obj) # type: ignore bind_func = _bind_func @@ -896,12 +891,12 @@ def _bind_func(instance: _RestrictedProxy, obj: Any) -> Callable: self.is_attr = is_attr def __set_name__(self, owner: _RestrictedProxy, name: str) -> None: - self.name = name + self.name = name # type: ignore[reportUninitializedInstanceVariable] def __get__(self, instance: _RestrictedProxy, owner: type | None = None) -> Any: - if instance is None: - if self.class_value is not None: - return self.class_value + if instance is None: # type: ignore[reportUninitializedInstanceVariable] + if self.class_value is not None: # type: ignore[reportUnreachable] + return self.class_value # type: ignore[reportUnreachable] return self @@ -989,7 +984,7 @@ def _is_restrictable(v: Any) -> bool: class _RestrictedProxy: - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: # When we instantiate this class, we have the signature of: # __init__( # self, @@ -1037,7 +1032,7 @@ def __setattr__(self, __name: str, __value: Any) -> None: state.assert_child_not_restricted(__name) setattr(state.obj, __name, __value) - def __call__(self, *args, **kwargs) -> _RestrictedProxy: + def __call__(self, *args: Any, **kwargs: Any) -> _RestrictedProxy: state = _RestrictionState.from_proxy(self) _trace("__call__ on %s", state.name) state.assert_child_not_restricted("__call__") diff --git a/temporalio/worker/workflow_sandbox/_runner.py b/temporalio/worker/workflow_sandbox/_runner.py index 35023f141..31514e33b 100644 --- a/temporalio/worker/workflow_sandbox/_runner.py +++ b/temporalio/worker/workflow_sandbox/_runner.py @@ -10,7 +10,7 @@ from collections.abc import Sequence from dataclasses import dataclass, field from datetime import datetime, timedelta, timezone -from typing import Any, Optional, Type +from typing import Any import temporalio.bridge.proto.workflow_activation import temporalio.bridge.proto.workflow_completion diff --git a/temporalio/workflow.py b/temporalio/workflow.py index 72e42e2fb..225dd0ac4 100644 --- a/temporalio/workflow.py +++ b/temporalio/workflow.py @@ -31,16 +31,10 @@ TYPE_CHECKING, Any, Concatenate, - Dict, Generic, - List, Literal, NoReturn, - Optional, - Tuple, - Type, TypeVar, - Union, cast, overload, ) @@ -58,7 +52,6 @@ import temporalio.bridge.proto.child_workflow import temporalio.bridge.proto.common import temporalio.bridge.proto.nexus -import temporalio.bridge.proto.workflow_activation import temporalio.bridge.proto.workflow_commands import temporalio.common import temporalio.converter @@ -914,7 +907,7 @@ def workflow_last_failure(self) -> BaseException | None: ... ) -def _set_current_update_info(info: UpdateInfo) -> None: +def _set_current_update_info(info: UpdateInfo) -> None: # type: ignore[reportUnusedFunction] _current_update_info.set(info) @@ -1688,7 +1681,7 @@ def get_name_and_result_type( raise ValueError("Cannot invoke dynamic workflow explicitly") return defn.name, defn.ret_type else: - raise TypeError("Workflow must be a string or callable") + raise TypeError("Workflow must be a string or callable") # type: ignore[reportUnreachable] @staticmethod def _apply_to_class( @@ -1893,7 +1886,7 @@ def _bind_method(obj: Any, fn: Callable[..., Any]) -> Callable[..., Any]: # considered an inspect.iscoroutinefunction fn = cast(Callable[..., Awaitable[Any]], fn) - async def with_object(*args, **kwargs) -> Any: + async def with_object(*args: Any, **kwargs: Any) -> Any: return await fn(obj, *args, **kwargs) return with_object @@ -2529,7 +2522,7 @@ async def execute_activity( # Overload for async no-param activity @overload def start_activity_class( - activity: Type[CallableAsyncNoParam[ReturnType]], + activity: type[CallableAsyncNoParam[ReturnType]], *, task_queue: str | None = None, schedule_to_close_timeout: timedelta | None = None, @@ -2548,7 +2541,7 @@ def start_activity_class( # Overload for sync no-param activity @overload def start_activity_class( - activity: Type[CallableSyncNoParam[ReturnType]], + activity: type[CallableSyncNoParam[ReturnType]], *, task_queue: str | None = None, schedule_to_close_timeout: timedelta | None = None, @@ -2567,7 +2560,7 @@ def start_activity_class( # Overload for async single-param activity @overload def start_activity_class( - activity: Type[CallableAsyncSingleParam[ParamType, ReturnType]], + activity: type[CallableAsyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, task_queue: str | None = None, @@ -2587,7 +2580,7 @@ def start_activity_class( # Overload for sync single-param activity @overload def start_activity_class( - activity: Type[CallableSyncSingleParam[ParamType, ReturnType]], + activity: type[CallableSyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, task_queue: str | None = None, @@ -2607,7 +2600,7 @@ def start_activity_class( # Overload for async multi-param activity @overload def start_activity_class( - activity: Type[Callable[..., Awaitable[ReturnType]]], + activity: type[Callable[..., Awaitable[ReturnType]]], # type: ignore[reportOverlappingOverload] *, args: Sequence[Any], task_queue: str | None = None, @@ -2626,8 +2619,8 @@ def start_activity_class( # Overload for sync multi-param activity @overload -def start_activity_class( - activity: Type[Callable[..., ReturnType]], +def start_activity_class( # type: ignore[reportOverlappingOverload] + activity: type[Callable[..., ReturnType]], # type: ignore[reportOverlappingOverload] *, args: Sequence[Any], task_queue: str | None = None, @@ -2645,7 +2638,7 @@ def start_activity_class( def start_activity_class( - activity: Type[Callable], + activity: type[Callable], # type: ignore[reportOverlappingOverload] arg: Any = temporalio.common._arg_unset, *, args: Sequence[Any] = [], @@ -2686,7 +2679,7 @@ def start_activity_class( # Overload for async no-param activity @overload async def execute_activity_class( - activity: Type[CallableAsyncNoParam[ReturnType]], + activity: type[CallableAsyncNoParam[ReturnType]], *, task_queue: str | None = None, schedule_to_close_timeout: timedelta | None = None, @@ -2705,7 +2698,7 @@ async def execute_activity_class( # Overload for sync no-param activity @overload async def execute_activity_class( - activity: Type[CallableSyncNoParam[ReturnType]], + activity: type[CallableSyncNoParam[ReturnType]], *, task_queue: str | None = None, schedule_to_close_timeout: timedelta | None = None, @@ -2724,7 +2717,7 @@ async def execute_activity_class( # Overload for async single-param activity @overload async def execute_activity_class( - activity: Type[CallableAsyncSingleParam[ParamType, ReturnType]], + activity: type[CallableAsyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, task_queue: str | None = None, @@ -2744,7 +2737,7 @@ async def execute_activity_class( # Overload for sync single-param activity @overload async def execute_activity_class( - activity: Type[CallableSyncSingleParam[ParamType, ReturnType]], + activity: type[CallableSyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, task_queue: str | None = None, @@ -2764,7 +2757,7 @@ async def execute_activity_class( # Overload for async multi-param activity @overload async def execute_activity_class( - activity: Type[Callable[..., Awaitable[ReturnType]]], + activity: type[Callable[..., Awaitable[ReturnType]]], # type: ignore[reportOverlappingOverload] *, args: Sequence[Any], task_queue: str | None = None, @@ -2784,7 +2777,7 @@ async def execute_activity_class( # Overload for sync multi-param activity @overload async def execute_activity_class( - activity: Type[Callable[..., ReturnType]], + activity: type[Callable[..., ReturnType]], # type: ignore[reportOverlappingOverload] *, args: Sequence[Any], task_queue: str | None = None, @@ -2802,7 +2795,7 @@ async def execute_activity_class( async def execute_activity_class( - activity: Type[Callable], + activity: type[Callable], # type: ignore[reportOverlappingOverload] arg: Any = temporalio.common._arg_unset, *, args: Sequence[Any] = [], @@ -3571,7 +3564,7 @@ def start_local_activity_class( # Overload for async multi-param activity @overload def start_local_activity_class( - activity: Type[Callable[..., Awaitable[ReturnType]]], + activity: type[Callable[..., Awaitable[ReturnType]]], # type: ignore[reportInvalidTypeForm] *, args: Sequence[Any], schedule_to_close_timeout: timedelta | None = None, @@ -3586,8 +3579,8 @@ def start_local_activity_class( # Overload for sync multi-param activity @overload -def start_local_activity_class( - activity: Type[Callable[..., ReturnType]], +def start_local_activity_class( # type: ignore[reportOverlappingOverload] + activity: type[Callable[..., ReturnType]], # type: ignore[reportInvalidTypeForm] *, args: Sequence[Any], schedule_to_close_timeout: timedelta | None = None, @@ -3601,7 +3594,7 @@ def start_local_activity_class( def start_local_activity_class( - activity: Type[Callable], + activity: type[Callable], # type: ignore[reportInvalidTypeForm] arg: Any = temporalio.common._arg_unset, *, args: Sequence[Any] = [], @@ -3636,7 +3629,7 @@ def start_local_activity_class( # Overload for async no-param activity @overload async def execute_local_activity_class( - activity: Type[CallableAsyncNoParam[ReturnType]], + activity: type[CallableAsyncNoParam[ReturnType]], *, schedule_to_close_timeout: timedelta | None = None, schedule_to_start_timeout: timedelta | None = None, @@ -3652,7 +3645,7 @@ async def execute_local_activity_class( # Overload for sync no-param activity @overload async def execute_local_activity_class( - activity: Type[CallableSyncNoParam[ReturnType]], + activity: type[CallableSyncNoParam[ReturnType]], *, schedule_to_close_timeout: timedelta | None = None, schedule_to_start_timeout: timedelta | None = None, @@ -3668,7 +3661,7 @@ async def execute_local_activity_class( # Overload for async single-param activity @overload async def execute_local_activity_class( - activity: Type[CallableAsyncSingleParam[ParamType, ReturnType]], + activity: type[CallableAsyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, schedule_to_close_timeout: timedelta | None = None, @@ -3685,7 +3678,7 @@ async def execute_local_activity_class( # Overload for sync single-param activity @overload async def execute_local_activity_class( - activity: Type[CallableSyncSingleParam[ParamType, ReturnType]], + activity: type[CallableSyncSingleParam[ParamType, ReturnType]], arg: ParamType, *, schedule_to_close_timeout: timedelta | None = None, @@ -3701,8 +3694,8 @@ async def execute_local_activity_class( # Overload for async multi-param activity @overload -async def execute_local_activity_class( - activity: Type[Callable[..., Awaitable[ReturnType]]], +async def execute_local_activity_class( # type: ignore[reportOverlappingOverload] + activity: type[Callable[..., Awaitable[ReturnType]]], # type: ignore[reportInvalidTypeForm] *, args: Sequence[Any], schedule_to_close_timeout: timedelta | None = None, @@ -3719,7 +3712,7 @@ async def execute_local_activity_class( # Overload for sync multi-param activity @overload async def execute_local_activity_class( - activity: Type[Callable[..., ReturnType]], + activity: type[Callable[..., ReturnType]], # type: ignore[reportInvalidTypeForm] *, args: Sequence[Any], schedule_to_close_timeout: timedelta | None = None, @@ -3734,7 +3727,7 @@ async def execute_local_activity_class( async def execute_local_activity_class( - activity: Type[Callable], + activity: type[Callable], # type: ignore[reportInvalidTypeForm] arg: Any = temporalio.common._arg_unset, *, args: Sequence[Any] = [], @@ -4086,10 +4079,10 @@ async def signal( async def signal( self, - signal: str | Callable, - arg: Any = temporalio.common._arg_unset, + signal: str | Callable, # type: ignore[reportUnusedParameter] + arg: Any = temporalio.common._arg_unset, # type: ignore[reportUnusedParameter] *, - args: Sequence[Any] = [], + args: Sequence[Any] = [], # type: ignore[reportUnusedParameter] ) -> None: """Signal this child workflow. @@ -4598,10 +4591,10 @@ async def signal( async def signal( self, - signal: str | Callable, - arg: Any = temporalio.common._arg_unset, + signal: str | Callable, # type: ignore[reportUnusedParameter] + arg: Any = temporalio.common._arg_unset, # type: ignore[reportUnusedParameter] *, - args: Sequence[Any] = [], + args: Sequence[Any] = [], # type: ignore[reportUnusedParameter] ) -> None: """Signal this external workflow. @@ -4642,9 +4635,8 @@ def get_external_workflow_handle( def get_external_workflow_handle_for( - workflow: ( - MethodAsyncNoParam[SelfType, Any] | MethodAsyncSingleParam[SelfType, Any, Any] - ), + workflow: MethodAsyncNoParam[SelfType, Any] # type: ignore[reportUnusedParameter] + | MethodAsyncSingleParam[SelfType, Any, Any], workflow_id: str, *, run_id: str | None = None, @@ -5040,7 +5032,7 @@ def _on_timeout(): done.put_nowait(None) # Queue a dummy value for _wait_for_one(). todo.clear() # Can't do todo.remove(f) in the loop. - def _on_completion(f): + def _on_completion(f): # type:ignore[reportMissingParameterType] if not todo: return # _on_timeout() was here first. todo.remove(f) @@ -5139,7 +5131,7 @@ async def _wait( timeout_handle = loop.call_later(timeout, _release_waiter, waiter) counter = len(fs) # type: ignore[arg-type] - def _on_completion(f): + def _on_completion(f): # type:ignore[reportMissingParameterType] nonlocal counter counter -= 1 if ( @@ -5173,7 +5165,7 @@ def _on_completion(f): return done, pending -def _release_waiter(waiter: asyncio.Future[Any], *args) -> None: +def _release_waiter(waiter: asyncio.Future[Any], *_args: Any) -> None: # Taken almost verbatim from # https://github.com/python/cpython/blob/v3.12.3/Lib/asyncio/tasks.py#L467 @@ -5190,19 +5182,6 @@ def _is_unbound_method_on_cls(fn: Callable[..., Any], cls: type) -> bool: ) -class _UnexpectedEvictionError(temporalio.exceptions.TemporalError): - def __init__( - self, - reason: temporalio.bridge.proto.workflow_activation.RemoveFromCache.EvictionReason.ValueType, - message: str, - ) -> None: - self.reason = temporalio.bridge.proto.workflow_activation.RemoveFromCache.EvictionReason.Name( - reason - ) - self.message = message - super().__init__(f"{self.reason}: {message}") - - class NondeterminismError(temporalio.exceptions.TemporalError): """Error that can be thrown during replay for non-deterministic workflow.""" diff --git a/tests/api/test_grpc_stub.py b/tests/api/test_grpc_stub.py index ba00774e0..64ac90256 100644 --- a/tests/api/test_grpc_stub.py +++ b/tests/api/test_grpc_stub.py @@ -1,7 +1,7 @@ import re from collections.abc import Mapping from datetime import timedelta -from typing import Any, Union, cast +from typing import Any, cast import pytest from google.protobuf.empty_pb2 import Empty diff --git a/tests/bridge/test_runtime.py b/tests/bridge/test_runtime.py index de6622f04..2a1c48834 100644 --- a/tests/bridge/test_runtime.py +++ b/tests/bridge/test_runtime.py @@ -1,6 +1,5 @@ from threading import Event, Thread from time import sleep -from typing import Optional from temporalio.bridge.runtime import Runtime diff --git a/tests/conftest.py b/tests/conftest.py index 41f8e1f38..f5935613e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -44,13 +44,13 @@ ), f"Expected protobuf 4.x/5.x/6.x, got {protobuf_version}" -def pytest_runtest_setup(item): +def pytest_runtest_setup(item): # type: ignore[reportMissingParameterType] """Print a newline so that custom printed output starts on new line.""" if item.config.getoption("-s"): print() -def pytest_addoption(parser): +def pytest_addoption(parser): # type: ignore[reportMissingParameterType] parser.addoption( "-E", "--workflow-environment", @@ -61,7 +61,7 @@ def pytest_addoption(parser): @pytest.fixture(scope="session") def event_loop(): - loop = asyncio.get_event_loop_policy().new_event_loop() + loop = asyncio.get_event_loop_policy().new_event_loop() # type: ignore[reportDeprecated] yield loop try: loop.close() @@ -77,17 +77,17 @@ def __init__(self, underlying: asyncio.AbstractEventLoopPolicy): # type: ignore def get_event_loop(self): return self._underlying.get_event_loop() - def set_event_loop(self, loop): + def set_event_loop(self, loop): # type: ignore[reportMissingParameterType] return self._underlying.set_event_loop(loop) def new_event_loop(self): # type: ignore[reportIncompatibleMethodOverride] return None def get_child_watcher(self): - return self._underlying.get_child_watcher() + return self._underlying.get_child_watcher() # type: ignore[reportDeprecated] - def set_child_watcher(self, watcher): - return self._underlying.set_child_watcher(watcher) + def set_child_watcher(self, watcher): # type: ignore[reportMissingParameterType] + return self._underlying.set_child_watcher(watcher) # type: ignore[reportDeprecated] @pytest.fixture(scope="session") @@ -95,7 +95,7 @@ def env_type(request: pytest.FixtureRequest) -> str: return request.config.getoption("--workflow-environment") # type: ignore[reportReturnType] -@pytest_asyncio.fixture(scope="session") +@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator] async def env(env_type: str) -> AsyncGenerator[WorkflowEnvironment, None]: if env_type == "local": http_port = 7243 @@ -163,12 +163,12 @@ def mp_fork_ctx() -> Iterator[multiprocessing.context.BaseContext | None]: p.join() -@pytest_asyncio.fixture +@pytest_asyncio.fixture # type: ignore[reportUntypedFunctionDecorator] async def client(env: WorkflowEnvironment) -> Client: return env.client -@pytest_asyncio.fixture(scope="session") +@pytest_asyncio.fixture(scope="session") # type: ignore[reportUntypedFunctionDecorator] async def worker( env: WorkflowEnvironment, ) -> AsyncGenerator[ExternalWorker, None]: @@ -182,7 +182,7 @@ async def worker( # hook forcefully kills the process as success when the exit code from pytest # is a success. @pytest.hookimpl(hookwrapper=True, trylast=True) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config): # type: ignore[reportMissingParameterType, reportUnusedParameter] result = yield if result.get_result() == 0: os._exit(0) diff --git a/tests/contrib/openai_agents/test_openai.py b/tests/contrib/openai_agents/test_openai.py index 381a213cd..2cfafef4d 100644 --- a/tests/contrib/openai_agents/test_openai.py +++ b/tests/contrib/openai_agents/test_openai.py @@ -8,8 +8,6 @@ from datetime import timedelta from typing import ( Any, - Optional, - Union, cast, ) @@ -57,25 +55,17 @@ HandoffOutputItem, ToolCallItem, ToolCallOutputItem, - TResponseOutputItem, TResponseStreamEvent, ) from agents.mcp import MCPServer, MCPServerStdio from openai import APIStatusError, AsyncOpenAI, BaseModel from openai.types.responses import ( - EasyInputMessageParam, ResponseCodeInterpreterToolCall, ResponseFileSearchToolCall, - ResponseFunctionToolCall, - ResponseFunctionToolCallParam, ResponseFunctionWebSearch, - ResponseInputTextParam, - ResponseOutputMessage, - ResponseOutputText, ) from openai.types.responses.response_file_search_tool_call import Result from openai.types.responses.response_function_web_search import ActionSearch -from openai.types.responses.response_input_item_param import Message from openai.types.responses.response_output_item import ( ImageGenerationCall, McpApprovalRequest, @@ -96,7 +86,6 @@ from temporalio.contrib.openai_agents._model_parameters import ModelSummaryProvider from temporalio.contrib.openai_agents._openai_runner import _convert_agent from temporalio.contrib.openai_agents._temporal_model_stub import ( - _extract_summary, _TemporalModelStub, ) from temporalio.contrib.openai_agents.testing import ( @@ -174,7 +163,7 @@ async def get_weather(city: str) -> Weather: @activity.defn -async def get_weather_country(city: str, country: str) -> Weather: +async def get_weather_country(city: str, country: str) -> Weather: # type: ignore[reportUnusedParameter] """ Get the weather for a given city in a country. """ @@ -224,7 +213,9 @@ class WeatherService: class WeatherServiceHandler: @nexusrpc.handler.sync_operation async def get_weather_nexus_operation( - self, ctx: nexusrpc.handler.StartOperationContext, input: WeatherInput + self, + ctx: nexusrpc.handler.StartOperationContext, # type: ignore[reportUnusedParameter] + input: WeatherInput, # type: ignore[reportUnusedParameter] ) -> Weather: return Weather( city=input.city, temperature_range="14-20C", conditions="Sunny with wind." @@ -429,7 +420,7 @@ async def test_tool_workflow(client: Client, use_local_model: bool): @activity.defn -async def get_weather_failure(city: str) -> Weather: +async def get_weather_failure(city: str) -> Weather: # type: ignore[reportUnusedParameter] """ Get the weather for a given city. """ @@ -468,7 +459,7 @@ async def test_tool_failure_workflow(client: Client): execution_timeout=timedelta(seconds=2), ) with pytest.raises(WorkflowFailureError) as e: - result = await workflow_handle.result() + await workflow_handle.result() cause = e.value.cause assert isinstance(cause, ApplicationError) assert "Workflow failure exception in Agents Framework" in cause.message @@ -938,7 +929,7 @@ def __init__(self, input_items: list[TResponseInputItem] = []): self.input_items = input_items @workflow.run - async def run(self, input_items: list[TResponseInputItem] = []): + async def run(self, _input_items: list[TResponseInputItem] = []): await workflow.wait_condition(lambda: False) workflow.continue_as_new(self.input_items) @@ -1166,7 +1157,7 @@ class MathHomeworkOutput(BaseModel): @input_guardrail async def math_guardrail( context: RunContextWrapper[None], - agent: Agent, + _agent: Agent, input: str | list[TResponseInputItem], ) -> GuardrailFunctionOutput: """This is an input guardrail function, which happens to call an agent to check if the input @@ -1284,7 +1275,7 @@ class MessageOutput(BaseModel): @output_guardrail async def sensitive_data_check( - context: RunContextWrapper, agent: Agent, output: MessageOutput + _context: RunContextWrapper, _agent: Agent, output: MessageOutput ) -> GuardrailFunctionOutput: phone_number_in_response = "650" in output.response phone_number_in_reasoning = "650" in output.reasoning @@ -1416,7 +1407,7 @@ async def test_response_serialization(): usage=Usage(), response_id="", ) - encoded = await pydantic_data_converter.encode([model_response]) + await pydantic_data_converter.encode([model_response]) async def assert_status_retry_behavior(status: int, client: Client, should_retry: bool): @@ -1451,7 +1442,7 @@ def status_error(status: int): task_queue=worker.task_queue, execution_timeout=timedelta(seconds=10), ) - with pytest.raises(WorkflowFailureError) as e: + with pytest.raises(WorkflowFailureError): await workflow_handle.result() found = False @@ -1517,7 +1508,7 @@ async def get_response( output_schema: AgentOutputSchemaBase | None, handoffs: list[Handoff], tracing: ModelTracing, - **kwargs, + **kwargs, # type:ignore[reportMissingParameterType] ) -> ModelResponse: activity.logger.info("Waiting") await asyncio.sleep(1.0) @@ -1533,7 +1524,7 @@ def stream_response( output_schema: AgentOutputSchemaBase | None, handoffs: list[Handoff], tracing: ModelTracing, - **kwargs, + **kwargs, # type:ignore[reportMissingParameterType] ) -> AsyncIterator[TResponseStreamEvent]: raise NotImplementedError() @@ -1606,40 +1597,6 @@ async def test_heartbeat(client: Client, env: WorkflowEnvironment): await workflow_handle.result() -def test_summary_extraction(): - input: list[TResponseInputItem] = [ - EasyInputMessageParam( - content="First message", - role="user", - ) - ] - - assert _extract_summary(input) == "First message" - - input.append( - Message( - content=[ - ResponseInputTextParam( - text="Second message", - type="input_text", - ) - ], - role="user", - ) - ) - assert _extract_summary(input) == "Second message" - - input.append( - ResponseFunctionToolCallParam( - arguments="", - call_id="", - name="", - type="function_call", - ) - ) - assert _extract_summary(input) == "Second message" - - @workflow.defn class SessionWorkflow: @workflow.run @@ -1685,13 +1642,15 @@ async def check(): await assert_eventually(check) -async def test_lite_llm(client: Client, env: WorkflowEnvironment): +async def test_lite_llm(client: Client): if not os.environ.get("OPENAI_API_KEY"): pytest.skip("No openai API key") if sys.version_info >= (3, 14): - pytest.skip("Lite LLM does not yet support Python 3.14") + pytest.skip("Lite LLM does not yet support Python 3.14") # type:ignore[reportUnreachable] - from agents.extensions.models.litellm_provider import LitellmProvider + from agents.extensions.models.litellm_provider import ( + LitellmProvider, # type:ignore[reportUnreachable] + ) async with AgentEnvironment( model_provider=LitellmProvider(), @@ -1699,13 +1658,13 @@ async def test_lite_llm(client: Client, env: WorkflowEnvironment): start_to_close_timeout=timedelta(seconds=30), ), ) as agent_env: - client = agent_env.applied_on_client(client) + client = agent_env.applied_on_client(client) # type:ignore[reportUnreachable] async with new_worker( client, HelloWorldAgent, ) as worker: - workflow_handle = await client.start_workflow( + workflow_handle = await client.start_workflow( # type:ignore[reportUnreachable] HelloWorldAgent.run, "Tell me about recursion in programming", id=f"lite-llm-{uuid.uuid4()}", @@ -1766,7 +1725,7 @@ async def run(self, question: str) -> str: @pytest.mark.parametrize("use_local_model", [True, False]) -async def test_file_search_tool(client: Client, use_local_model): +async def test_file_search_tool(client: Client, use_local_model: bool): if not use_local_model and not os.environ.get("OPENAI_API_KEY"): pytest.skip("No openai API key") @@ -1840,7 +1799,7 @@ async def run(self, question: str) -> str: # Can't currently validate against real server, we aren't verified for image generation @pytest.mark.parametrize("use_local_model", [True]) -async def test_image_generation_tool(client: Client, use_local_model): +async def test_image_generation_tool(client: Client, use_local_model: bool): if not use_local_model and not os.environ.get("OPENAI_API_KEY"): pytest.skip("No openai API key") @@ -1864,7 +1823,7 @@ async def test_image_generation_tool(client: Client, use_local_model): task_queue=worker.task_queue, execution_timeout=timedelta(seconds=30), ) - result = await workflow_handle.result() + await workflow_handle.result() def code_interpreter_mock_model(): @@ -2099,7 +2058,7 @@ async def test_multiple_models(client: Client): task_queue=worker.task_queue, execution_timeout=timedelta(seconds=10), ) - result = await workflow_handle.result() + await workflow_handle.result() assert provider.model_names == {None, "gpt-4o-mini"} @@ -2124,7 +2083,7 @@ async def test_run_config_models(client: Client): task_queue=worker.task_queue, execution_timeout=timedelta(seconds=10), ) - result = await workflow_handle.result() + await workflow_handle.result() # Only the model from the runconfig override is used assert provider.model_names == {"gpt-4o"} @@ -2160,7 +2119,7 @@ def provide( task_queue=worker.task_queue, execution_timeout=timedelta(seconds=10), ) - result = await workflow_handle.result() + await workflow_handle.result() async for e in workflow_handle.fetch_history_events(): if e.HasField("activity_task_scheduled_event_attributes"): assert e.user_metadata.summary.data == b'"My summary"' @@ -2225,7 +2184,7 @@ async def test_output_type(client: Client): class McpServerWorkflow: @workflow.run async def run(self, caching: bool, factory_argument: Any | None) -> str: - from agents.mcp import MCPServer + from agents.mcp import MCPServer # type: ignore[reportUnusedImport] server: MCPServer = openai_agents.workflow.stateless_mcp_server( "HelloServer", cache_tools_list=caching, factory_argument=factory_argument @@ -2477,7 +2436,7 @@ def factory(args: Any | None) -> MCPServer: client, McpServerStatefulWorkflow, McpServerWorkflow ) as worker: if stateful: - result = await client.execute_workflow( + await client.execute_workflow( McpServerStatefulWorkflow.run, args=[timedelta(seconds=30), headers], id=f"mcp-server-{uuid.uuid4()}", @@ -2485,7 +2444,7 @@ def factory(args: Any | None) -> MCPServer: execution_timeout=timedelta(seconds=30), ) else: - result = await client.execute_workflow( + await client.execute_workflow( McpServerWorkflow.run, args=[False, headers], id=f"mcp-server-{uuid.uuid4()}", @@ -2624,9 +2583,7 @@ async def test_split_workers(client: Client): new_config["plugins"] = [activity_plugin] activity_client = Client(**new_config) # Activity Worker - async with new_worker( - activity_client, task_queue=worker.task_queue - ) as activity_worker: + async with new_worker(activity_client, task_queue=worker.task_queue): result = await activity_client.execute_workflow( HelloWorldAgent.run, "Tell me about recursion in programming.", diff --git a/tests/contrib/openai_agents/test_openai_tracing.py b/tests/contrib/openai_agents/test_openai_tracing.py index f0a98c2b6..39d1cc6f0 100644 --- a/tests/contrib/openai_agents/test_openai_tracing.py +++ b/tests/contrib/openai_agents/test_openai_tracing.py @@ -60,7 +60,7 @@ async def test_tracing(client: Client): task_queue=worker.task_queue, execution_timeout=timedelta(seconds=120), ) - result = await workflow_handle.result() + await workflow_handle.result() # There is one closed root trace assert len(processor.trace_events) == 2 diff --git a/tests/contrib/pydantic/activities.py b/tests/contrib/pydantic/activities.py index 4b5a83d5b..7cd4abd30 100644 --- a/tests/contrib/pydantic/activities.py +++ b/tests/contrib/pydantic/activities.py @@ -1,5 +1,4 @@ from datetime import datetime -from typing import List from uuid import UUID from temporalio import activity diff --git a/tests/contrib/pydantic/models.py b/tests/contrib/pydantic/models.py index 97e2694db..dddeb5d7e 100644 --- a/tests/contrib/pydantic/models.py +++ b/tests/contrib/pydantic/models.py @@ -7,12 +7,8 @@ from typing import ( Annotated, Any, - Dict, Generic, - List, - Tuple, TypeVar, - Union, cast, ) @@ -370,21 +366,21 @@ def _assert_timedelta_validity(td: timedelta): assert issubclass(td.__class__, timedelta) -PydanticModels = Union[ - StandardTypesModel, - StrictStandardTypesModel, - ComplexTypesModel, - SpecialTypesModel, - StrictSpecialTypesModel, - ParentModel, - FieldFeaturesModel, - AnnotatedFieldsModel, - GenericModel[Any], - UnionModel, - PydanticDatetimeModel, - PydanticDateModel, - PydanticTimedeltaModel, -] +PydanticModels = ( + StandardTypesModel + | StrictStandardTypesModel + | ComplexTypesModel + | SpecialTypesModel + | StrictSpecialTypesModel + | ParentModel + | FieldFeaturesModel + | AnnotatedFieldsModel + | GenericModel[Any] + | UnionModel + | PydanticDatetimeModel + | PydanticDateModel + | PydanticTimedeltaModel +) def make_list_of_pydantic_objects() -> list[PydanticModels]: @@ -419,7 +415,7 @@ def make_dataclass_objects() -> list[MyDataClass]: ComplexCustomType = tuple[list[MyDataClass], list[PydanticModels]] -ComplexCustomUnionType = list[Union[MyDataClass, PydanticModels]] +ComplexCustomUnionType = list[MyDataClass | PydanticModels] class PydanticModelWithStrictField(BaseModel): diff --git a/tests/contrib/pydantic/models_2.py b/tests/contrib/pydantic/models_2.py index decec56df..4794f95a4 100644 --- a/tests/contrib/pydantic/models_2.py +++ b/tests/contrib/pydantic/models_2.py @@ -7,13 +7,7 @@ from re import Pattern from typing import ( Any, - Dict, - List, NamedTuple, - Optional, - Set, - Tuple, - Union, cast, ) diff --git a/tests/contrib/pydantic/test_pydantic.py b/tests/contrib/pydantic/test_pydantic.py index c70eee56f..69a723a56 100644 --- a/tests/contrib/pydantic/test_pydantic.py +++ b/tests/contrib/pydantic/test_pydantic.py @@ -16,6 +16,10 @@ SandboxMatcher, _RestrictedProxy, ) +from tests.contrib.pydantic.activities import ( + misc_objects_activity, + pydantic_objects_activity, +) from tests.contrib.pydantic.models import ( PydanticModels, PydanticModelWithStrictField, @@ -35,8 +39,6 @@ RoundTripPydanticObjectsWorkflow, _test_pydantic_model_with_strict_field, clone_objects, - misc_objects_activity, - pydantic_objects_activity, ) diff --git a/tests/contrib/pydantic/workflows.py b/tests/contrib/pydantic/workflows.py index d67e7db42..4733dec4c 100644 --- a/tests/contrib/pydantic/workflows.py +++ b/tests/contrib/pydantic/workflows.py @@ -1,6 +1,5 @@ import dataclasses from datetime import datetime, timedelta -from typing import List from uuid import UUID from pydantic import BaseModel, create_model @@ -26,7 +25,7 @@ def clone_objects(objects: list[PydanticModels]) -> list[PydanticModels]: new_objects = [] for o in objects: fields = {} - for name, f in o.model_fields.items(): + for name, f in o.model_fields.items(): # type: ignore[reportDeprecated] fields[name] = (f.annotation, f) model = create_model(o.__class__.__name__, **fields) # type: ignore new_objects.append(model(**o.model_dump(by_alias=True))) @@ -171,5 +170,5 @@ async def run( @workflow.defn class NoTypeAnnotationsWorkflow: @workflow.run - async def run(self, arg): + async def run(self, arg): # type: ignore[reportMissingParameterType] return arg diff --git a/tests/contrib/test_opentelemetry.py b/tests/contrib/test_opentelemetry.py index c85cf1d1f..7e21c8935 100644 --- a/tests/contrib/test_opentelemetry.py +++ b/tests/contrib/test_opentelemetry.py @@ -11,7 +11,7 @@ from contextlib import contextmanager from dataclasses import dataclass from datetime import timedelta -from typing import Dict, List, Optional, cast +from typing import Any, cast import nexusrpc import opentelemetry.context @@ -96,7 +96,7 @@ class TracingWorkflowActionContinueAsNew: @workflow.defn class ExpectCancelNexusWorkflow: @workflow.run - async def run(self, input: str): + async def run(self, _input: str): try: await asyncio.wait_for(asyncio.Future(), 2) except asyncio.TimeoutError: @@ -705,9 +705,7 @@ async def run(self) -> dict[str, str]: ) -async def test_opentelemetry_baggage_propagation_basic( - client_with_tracing: Client, env: WorkflowEnvironment -): +async def test_opentelemetry_baggage_propagation_basic(client_with_tracing: Client): task_queue = f"task_queue_{uuid.uuid4()}" async with Worker( client_with_tracing, @@ -732,13 +730,10 @@ async def test_opentelemetry_baggage_propagation_basic( @activity.defn async def read_baggage_local_activity() -> dict[str, str]: - return cast( - dict[str, str], - { - "user_id": get_baggage_value("user.id"), - "tenant_id": get_baggage_value("tenant.id"), - }, - ) + return { + "user_id": get_baggage_value("user.id"), + "tenant_id": get_baggage_value("tenant.id"), + } @workflow.defn @@ -752,7 +747,7 @@ async def run(self) -> dict[str, str]: async def test_opentelemetry_baggage_propagation_local_activity( - client_with_tracing: Client, env: WorkflowEnvironment + client_with_tracing: Client, ): task_queue = f"task_queue_{uuid.uuid4()}" async with Worker( @@ -799,7 +794,7 @@ async def run(self) -> None: async def test_opentelemetry_baggage_propagation_with_retries( - client_with_tracing: Client, env: WorkflowEnvironment + client_with_tracing: Client, ) -> None: global retry_attempt_baggage_values retry_attempt_baggage_values = [] @@ -855,7 +850,6 @@ async def run(self) -> None: ) async def test_opentelemetry_context_restored_after_activity( client_with_tracing: Client, - env: WorkflowEnvironment, activity: Callable[[], None], expect_failure: bool, ) -> None: @@ -864,12 +858,12 @@ async def test_opentelemetry_context_restored_after_activity( original_attach = context.attach original_detach = context.detach - def tracked_attach(ctx): + def tracked_attach(ctx): # type:ignore[reportMissingParameterType] nonlocal attach_count attach_count += 1 return original_attach(ctx) - def tracked_detach(token): + def tracked_detach(token): # type:ignore[reportMissingParameterType] nonlocal detach_count detach_count += 1 return original_detach(token) @@ -924,7 +918,7 @@ async def run(self) -> str: async def test_opentelemetry_interceptor_works_if_no_context( - client_with_tracing: Client, env: WorkflowEnvironment + client_with_tracing: Client, ): task_queue = f"task_queue_{uuid.uuid4()}" async with Worker( @@ -952,13 +946,13 @@ async def test_opentelemetry_interceptor_works_if_no_context( def test_opentelemetry_safe_detach(): class _fake_self: - def _load_workflow_context_carrier(*args): + def _load_workflow_context_carrier(*_args): return None - def _set_on_context(self, ctx): + def _set_on_context(self, ctx: Any): return opentelemetry.context.set_value("test-key", "test-value", ctx) - def _completed_span(*args, **kwargs): + def _completed_span(*args: Any, **_kwargs: Any): pass # create a context manager and force enter to happen on this thread diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py index 09bc61b45..e407b7d1d 100644 --- a/tests/helpers/__init__.py +++ b/tests/helpers/__init__.py @@ -11,11 +11,7 @@ from datetime import datetime, timedelta, timezone from typing import ( Any, - List, - Optional, - Type, TypeVar, - Union, cast, ) @@ -53,7 +49,7 @@ def new_worker( workflow_runner: WorkflowRunner = SandboxedWorkflowRunner(), max_cached_workflows: int = 1000, workflow_failure_exception_types: Sequence[type[BaseException]] = [], - **kwargs, + **kwargs, # type:ignore[reportMissingParameterType] ) -> Worker: return Worker( client, @@ -187,7 +183,7 @@ async def admitted_update_task( handle: WorkflowHandle, update_method: UpdateMethodMultiParam, id: str, - **kwargs, + **kwargs, # type:ignore[reportMissingParameterType] ) -> asyncio.Task: """ Return an asyncio.Task for an update after waiting for it to be admitted. diff --git a/tests/helpers/external_coroutine.py b/tests/helpers/external_coroutine.py index 72fa8f25a..9af6e85ec 100644 --- a/tests/helpers/external_coroutine.py +++ b/tests/helpers/external_coroutine.py @@ -2,8 +2,6 @@ File used in conjunction with external_stack_trace.py to test filenames in multi-file workflows. """ -from typing import List - from temporalio import workflow diff --git a/tests/helpers/fork.py b/tests/helpers/fork.py index e6d84652f..d465a4808 100644 --- a/tests/helpers/fork.py +++ b/tests/helpers/fork.py @@ -3,7 +3,6 @@ import asyncio import multiprocessing import multiprocessing.context -import sys from dataclasses import dataclass from typing import Any @@ -40,8 +39,8 @@ def assertion_error(message: str) -> _ForkTestResult: ) -class _TestFork: - _expected: _ForkTestResult +class _TestFork: # type:ignore[reportUnusedClass] + _expected: _ForkTestResult # type:ignore[reportUninitializedInstanceVariable] async def coro(self) -> Any: raise NotImplementedError() @@ -66,7 +65,7 @@ def run(self, mp_fork_context: multiprocessing.context.BaseContext | None): if not mp_fork_context or not process_factory: pytest.skip("fork context not available") - self._parent_conn, self._child_conn = mp_fork_context.Pipe(duplex=False) + self._parent_conn, self._child_conn = mp_fork_context.Pipe(duplex=False) # type:ignore[reportUninitializedInstanceVariable] # start fork child_process = process_factory(target=self.entry, args=(), daemon=False) child_process.start() diff --git a/tests/helpers/nexus.py b/tests/helpers/nexus.py index 63dde9621..904b4422a 100644 --- a/tests/helpers/nexus.py +++ b/tests/helpers/nexus.py @@ -1,7 +1,7 @@ import dataclasses from collections.abc import Mapping from dataclasses import dataclass -from typing import Any, Optional +from typing import Any from urllib.parse import urlparse import temporalio.api.failure.v1 @@ -122,7 +122,7 @@ def __post_init__(self) -> None: ) def _instantiate_exception( - self, error_type: str, details: dict[str, Any] | None + self, error_type: str, _details: dict[str, Any] | None ) -> BaseException: proto = { "temporal.api.failure.v1.Failure": temporalio.api.failure.v1.Failure, diff --git a/tests/helpers/worker.py b/tests/helpers/worker.py index 5c6e6898c..b21be3b36 100644 --- a/tests/helpers/worker.py +++ b/tests/helpers/worker.py @@ -12,7 +12,7 @@ from collections.abc import Sequence from dataclasses import dataclass from datetime import timedelta -from typing import Any, Optional, Tuple +from typing import Any import temporalio.converter from temporalio import workflow @@ -132,7 +132,7 @@ async def handle_action( elif action.signal: signal_event = asyncio.Event() - def signal_handler(arg: Any | None = None) -> None: + def signal_handler(_arg: Any | None = None) -> None: signal_event.set() workflow.set_signal_handler(action.signal.name, signal_handler) diff --git a/tests/nexus/test_dynamic_creation_of_user_handler_classes.py b/tests/nexus/test_dynamic_creation_of_user_handler_classes.py index bc4eacd27..95ff1c986 100644 --- a/tests/nexus/test_dynamic_creation_of_user_handler_classes.py +++ b/tests/nexus/test_dynamic_creation_of_user_handler_classes.py @@ -110,8 +110,8 @@ def make_incrementer_user_service_definition_and_service_handler_classes( # @sync_operation async def _increment_op( - self, - ctx: nexusrpc.handler.StartOperationContext, + _self, # type:ignore[reportMissingParameterType] + _ctx: nexusrpc.handler.StartOperationContext, input: int, ) -> int: return input + 1 diff --git a/tests/nexus/test_handler.py b/tests/nexus/test_handler.py index 2bb10ae43..407e61caf 100644 --- a/tests/nexus/test_handler.py +++ b/tests/nexus/test_handler.py @@ -22,7 +22,7 @@ from concurrent.futures.thread import ThreadPoolExecutor from dataclasses import dataclass, field from types import MappingProxyType -from typing import Any, Optional, Union +from typing import Any import httpx import nexusrpc @@ -146,13 +146,13 @@ async def echo_renamed(self, ctx: StartOperationContext, input: Input) -> Output return await self.echo(ctx, input) @sync_operation - async def hang(self, ctx: StartOperationContext, input: Input) -> Output: + async def hang(self, _ctx: StartOperationContext, _input: Input) -> Output: await asyncio.Future() return Output(value="won't reach here") @sync_operation async def non_retryable_application_error( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, _input: Input ) -> Output: raise ApplicationError( "non-retryable application error", @@ -164,7 +164,7 @@ async def non_retryable_application_error( @sync_operation async def retryable_application_error( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, _input: Input ) -> Output: raise ApplicationError( "retryable application error", @@ -175,7 +175,7 @@ async def retryable_application_error( @sync_operation async def handler_error_internal( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, _input: Input ) -> Output: raise HandlerError( message="deliberate internal handler error", @@ -185,7 +185,7 @@ async def handler_error_internal( @sync_operation async def operation_error_failed( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, _input: Input ) -> Output: raise OperationError( message="deliberate operation error", @@ -202,7 +202,7 @@ async def check_operation_timeout_header( ) @sync_operation - async def log(self, ctx: StartOperationContext, input: Input) -> Output: + async def log(self, _ctx: StartOperationContext, input: Input) -> Output: nexus.logger.info( "Logging from start method", extra={"input_value": input.value} ) @@ -222,7 +222,7 @@ async def workflow_run_operation_happy_path( @sync_operation async def sync_operation_with_non_async_def( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, input: Input ) -> Output: return Output( value=f"from start method on {self.__class__.__name__}: {input.value}" @@ -267,13 +267,13 @@ def operation_returning_unwrapped_result_at_runtime_error( @sync_operation async def idempotency_check( - self, ctx: StartOperationContext, input: None + self, ctx: StartOperationContext, _input: None ) -> Output: return Output(value=f"request_id: {ctx.request_id}") @sync_operation async def non_serializable_output( - self, ctx: StartOperationContext, input: Input + self, _ctx: StartOperationContext, _input: Input ) -> NonSerializableOutput: return NonSerializableOutput() @@ -318,11 +318,11 @@ class UnsuccessfulResponse: class _TestCase: - operation: str + operation: str # type:ignore[reportUninitializedInstanceVariable] service_defn: str = "MyService" input: Input = Input("") headers: dict[str, str] = {} - expected: SuccessfulResponse + expected: SuccessfulResponse # type:ignore[reportUninitializedInstanceVariable] expected_without_service_definition: SuccessfulResponse | None = None skip = "" @@ -677,7 +677,7 @@ class MyServiceWithOperationsWithoutTypeAnnotations: class MyServiceHandlerWithOperationsWithoutTypeAnnotations: @sync_operation - async def sync_operation_without_type_annotations(self, ctx, input): + async def sync_operation_without_type_annotations(self, ctx, input): # type:ignore[reportMissingParameterType] # Despite the lack of type annotations, the input type from the op definition in # the service definition is used to deserialize the input. return Output( @@ -685,7 +685,7 @@ async def sync_operation_without_type_annotations(self, ctx, input): ) @workflow_run_operation - async def workflow_run_operation_without_type_annotations(self, ctx, input): + async def workflow_run_operation_without_type_annotations(self, ctx, input): # type:ignore[reportMissingParameterType] return await ctx.start_workflow( WorkflowWithoutTypeAnnotations.run, input, @@ -847,7 +847,7 @@ def echo(self, ctx: StartOperationContext, input: Input) -> Output: @service_handler(service=EchoService) class DefaultCancelHandler: @sync_operation - async def echo(self, ctx: StartOperationContext, input: Input) -> Output: + async def echo(self, _ctx: StartOperationContext, input: Input) -> Output: return Output( value=f"from start method on {self.__class__.__name__}: {input.value}" ) diff --git a/tests/nexus/test_handler_async_operation.py b/tests/nexus/test_handler_async_operation.py index 76aef59f6..d25c8a072 100644 --- a/tests/nexus/test_handler_async_operation.py +++ b/tests/nexus/test_handler_async_operation.py @@ -10,7 +10,7 @@ import uuid from collections.abc import Coroutine from dataclasses import dataclass, field -from typing import Any, Type, Union +from typing import Any import pytest from nexusrpc.handler import ( diff --git a/tests/nexus/test_handler_interface_implementation.py b/tests/nexus/test_handler_interface_implementation.py index 58a139ad8..35289e188 100644 --- a/tests/nexus/test_handler_interface_implementation.py +++ b/tests/nexus/test_handler_interface_implementation.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, Optional +from typing import Any import nexusrpc import nexusrpc.handler diff --git a/tests/nexus/test_handler_operation_definitions.py b/tests/nexus/test_handler_operation_definitions.py index a9e9cb454..e975a8fc8 100644 --- a/tests/nexus/test_handler_operation_definitions.py +++ b/tests/nexus/test_handler_operation_definitions.py @@ -4,7 +4,7 @@ """ from dataclasses import dataclass -from typing import Any, Type +from typing import Any import nexusrpc.handler import pytest @@ -35,7 +35,7 @@ class NotCalled(_TestCase): class Service: @workflow_run_operation async def my_workflow_run_operation_handler( - self, ctx: WorkflowRunOperationContext, input: Input + self, _ctx: WorkflowRunOperationContext, _input: Input ) -> nexus.WorkflowHandle[Output]: raise NotImplementedError @@ -54,7 +54,7 @@ class CalledWithoutArgs(_TestCase): class Service: @workflow_run_operation async def my_workflow_run_operation_handler( - self, ctx: WorkflowRunOperationContext, input: Input + self, _ctx: WorkflowRunOperationContext, _input: Input ) -> nexus.WorkflowHandle[Output]: raise NotImplementedError @@ -66,7 +66,7 @@ class CalledWithNameOverride(_TestCase): class Service: @workflow_run_operation(name="operation-name") async def workflow_run_operation_with_name_override( - self, ctx: WorkflowRunOperationContext, input: Input + self, _ctx: WorkflowRunOperationContext, _input: Input ) -> nexus.WorkflowHandle[Output]: raise NotImplementedError diff --git a/tests/nexus/test_use_existing_conflict_policy.py b/tests/nexus/test_use_existing_conflict_policy.py index 211ed4f5c..ecefa4b05 100644 --- a/tests/nexus/test_use_existing_conflict_policy.py +++ b/tests/nexus/test_use_existing_conflict_policy.py @@ -3,7 +3,6 @@ import asyncio import uuid from dataclasses import dataclass -from typing import Optional import pytest from nexusrpc.handler import service_handler diff --git a/tests/nexus/test_workflow_caller.py b/tests/nexus/test_workflow_caller.py index 29b2f03a3..07c22e688 100644 --- a/tests/nexus/test_workflow_caller.py +++ b/tests/nexus/test_workflow_caller.py @@ -190,7 +190,7 @@ def sync_or_async_operation( @sync_operation async def sync_operation( - self, ctx: StartOperationContext, input: OpInput + self, _ctx: StartOperationContext, input: OpInput ) -> OpOutput: assert isinstance(input.response_type, SyncResponse) if input.response_type.exception_in_operation_start: @@ -245,10 +245,10 @@ class CallerWorkflow: def __init__( self, input: CallerWfInput, - request_cancel: bool, + _request_cancel: bool, task_queue: str, ) -> None: - self.nexus_client: workflow.NexusClient[ServiceInterface | ServiceImpl] = ( + self.nexus_client: workflow.NexusClient[ServiceInterface | ServiceImpl] = ( # type:ignore[reportAttributeAccessIssue] workflow.create_nexus_client( service={ CallerReference.IMPL_WITH_INTERFACE: ServiceImpl, @@ -265,7 +265,7 @@ async def run( self, input: CallerWfInput, request_cancel: bool, - task_queue: str, + _task_queue: str, ) -> CallerWfOutput: op_input = input.op_input try: @@ -386,7 +386,7 @@ def __init__( @workflow.run async def run( - self, input: CallerWfInput, request_cancel: bool, task_queue: str + self, input: CallerWfInput, _request_cancel: bool, _task_queue: str ) -> CallerWfOutput: op_input = input.op_input if op_input.response_type.op_definition_type == OpDefinitionType.LONGHAND: @@ -761,7 +761,7 @@ async def test_untyped_caller( task_queue=task_queue, workflow_failure_exception_types=[Exception], ): - if response_type == SyncResponse: + if type(response_type) == SyncResponse: response_type = SyncResponse( op_definition_type=op_definition_type, use_async_def=True, @@ -834,7 +834,7 @@ class ServiceInterfaceWithNameOverride: class ServiceImplInterfaceWithNeitherInterfaceNorNameOverride: @sync_operation async def op( - self, ctx: StartOperationContext, input: None + self, _ctx: StartOperationContext, _input: None ) -> ServiceClassNameOutput: return ServiceClassNameOutput(self.__class__.__name__) @@ -843,7 +843,7 @@ async def op( class ServiceImplInterfaceWithoutNameOverride: @sync_operation async def op( - self, ctx: StartOperationContext, input: None + self, _ctx: StartOperationContext, _input: None ) -> ServiceClassNameOutput: return ServiceClassNameOutput(self.__class__.__name__) @@ -852,7 +852,7 @@ async def op( class ServiceImplInterfaceWithNameOverride: @sync_operation async def op( - self, ctx: StartOperationContext, input: None + self, _ctx: StartOperationContext, _input: None ) -> ServiceClassNameOutput: return ServiceClassNameOutput(self.__class__.__name__) @@ -861,7 +861,7 @@ async def op( class ServiceImplWithNameOverride: @sync_operation async def op( - self, ctx: StartOperationContext, input: None + self, _ctx: StartOperationContext, _input: None ) -> ServiceClassNameOutput: return ServiceClassNameOutput(self.__class__.__name__) @@ -1005,7 +1005,7 @@ async def run(self, input: str) -> str: class ServiceImplWithOperationsThatExecuteWorkflowBeforeStartingBackingWorkflow: @workflow_run_operation async def my_workflow_run_operation( - self, ctx: WorkflowRunOperationContext, input: None + self, ctx: WorkflowRunOperationContext, _input: None ) -> nexus.WorkflowHandle[str]: result_1 = await nexus.client().execute_workflow( EchoWorkflow.run, @@ -1026,7 +1026,7 @@ async def my_workflow_run_operation( @workflow.defn class WorkflowCallingNexusOperationThatExecutesWorkflowBeforeStartingBackingWorkflow: @workflow.run - async def run(self, input: str, task_queue: str) -> str: + async def run(self, _input: str, task_queue: str) -> str: nexus_client = workflow.create_nexus_client( service=ServiceImplWithOperationsThatExecuteWorkflowBeforeStartingBackingWorkflow, endpoint=make_nexus_endpoint_name(task_queue), @@ -1070,7 +1070,7 @@ async def test_workflow_run_operation_can_execute_workflow_before_starting_backi @service_handler class SimpleSyncService: @sync_operation - async def sync_op(self, ctx: StartOperationContext, input: str) -> str: + async def sync_op(self, _ctx: StartOperationContext, input: str) -> str: return input @@ -1423,7 +1423,7 @@ async def test_workflow_run_operation_overloads( class CustomMetricsService: @nexusrpc.handler.sync_operation async def custom_metric_op( - self, ctx: nexusrpc.handler.StartOperationContext, input: None + self, _ctx: nexusrpc.handler.StartOperationContext, _input: None ) -> None: counter = nexus.metric_meter().create_counter( "my-operation-counter", "my-operation-description", "my-operation-unit" @@ -1433,7 +1433,7 @@ async def custom_metric_op( @nexusrpc.handler.sync_operation def custom_metric_op_executor( - self, ctx: nexusrpc.handler.StartOperationContext, input: None + self, _ctx: nexusrpc.handler.StartOperationContext, _input: None ) -> None: counter = nexus.metric_meter().create_counter( "my-executor-operation-counter", diff --git a/tests/nexus/test_workflow_caller_cancellation_types.py b/tests/nexus/test_workflow_caller_cancellation_types.py index 16cfb8805..fd5aa84a7 100644 --- a/tests/nexus/test_workflow_caller_cancellation_types.py +++ b/tests/nexus/test_workflow_caller_cancellation_types.py @@ -2,7 +2,7 @@ import uuid from dataclasses import dataclass, field from datetime import datetime, timezone -from typing import Any, Optional +from typing import Any import nexusrpc import nexusrpc.handler._decorators @@ -68,7 +68,7 @@ class Service: class WorkflowOpHandler( temporalio.nexus._operation_handlers.WorkflowRunOperationHandler ): - def __init__(self): + def __init__(self): # type:ignore[reportMissingSuperCall] pass async def start( diff --git a/tests/nexus/test_workflow_caller_cancellation_types_when_cancel_handler_fails.py b/tests/nexus/test_workflow_caller_cancellation_types_when_cancel_handler_fails.py index c9cb71807..37aa986ed 100644 --- a/tests/nexus/test_workflow_caller_cancellation_types_when_cancel_handler_fails.py +++ b/tests/nexus/test_workflow_caller_cancellation_types_when_cancel_handler_fails.py @@ -6,7 +6,7 @@ import uuid from dataclasses import dataclass, field from datetime import datetime, timezone -from typing import Any, Optional +from typing import Any import nexusrpc import nexusrpc.handler._decorators @@ -79,7 +79,7 @@ class Service: class WorkflowOpHandler( temporalio.nexus._operation_handlers.WorkflowRunOperationHandler ): - def __init__(self): + def __init__(self): # type:ignore[reportMissingSuperCall] pass async def start( diff --git a/tests/nexus/test_workflow_caller_error_chains.py b/tests/nexus/test_workflow_caller_error_chains.py index 4ba9ca6d5..07a575d60 100644 --- a/tests/nexus/test_workflow_caller_error_chains.py +++ b/tests/nexus/test_workflow_caller_error_chains.py @@ -33,7 +33,7 @@ class ErrorConversionTestCase: action_in_nexus_operation: Callable[..., Any] expected_exception_chain_in_workflow: list[tuple[type[Exception], dict[str, Any]]] - def __init_subclass__(cls, **kwargs): + def __init_subclass__(cls, **kwargs): # type:ignore[reportMissingParameterType] super().__init_subclass__(**kwargs) assert cls.__name__ not in error_conversion_test_cases error_conversion_test_cases[cls.__name__] = cls @@ -353,7 +353,7 @@ class ErrorTestInput: @nexusrpc.handler.service_handler class ErrorTestService: @sync_operation - async def op(self, ctx: StartOperationContext, input: ErrorTestInput) -> None: + async def op(self, _ctx: StartOperationContext, input: ErrorTestInput) -> None: error_conversion_test_cases[input.name].action_in_nexus_operation() diff --git a/tests/nexus/test_workflow_caller_errors.py b/tests/nexus/test_workflow_caller_errors.py index 0fc32ba5b..4872de9ca 100644 --- a/tests/nexus/test_workflow_caller_errors.py +++ b/tests/nexus/test_workflow_caller_errors.py @@ -61,14 +61,14 @@ async def run(self) -> None: class ErrorTestService: @nexusrpc.handler.sync_operation def retried_due_to_exception( - self, ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput + self, _ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput ) -> None: operation_invocation_counts[input.id] += 1 raise Exception @nexusrpc.handler.sync_operation def retried_due_to_retryable_application_error( - self, ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput + self, _ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput ) -> None: operation_invocation_counts[input.id] += 1 raise ApplicationError( @@ -79,7 +79,7 @@ def retried_due_to_retryable_application_error( @nexusrpc.handler.sync_operation def retried_due_to_resource_exhausted_handler_error( - self, ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput + self, _ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput ) -> None: operation_invocation_counts[input.id] += 1 raise nexusrpc.HandlerError( @@ -89,7 +89,7 @@ def retried_due_to_resource_exhausted_handler_error( @nexusrpc.handler.sync_operation def retried_due_to_internal_handler_error( - self, ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput + self, _ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput ) -> None: operation_invocation_counts[input.id] += 1 raise nexusrpc.HandlerError( @@ -99,7 +99,7 @@ def retried_due_to_internal_handler_error( @nexusrpc.handler.sync_operation async def fails_due_to_workflow_already_started( - self, ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput + self, _ctx: nexusrpc.handler.StartOperationContext, input: ErrorTestInput ) -> None: operation_invocation_counts[input.id] += 1 for _ in range(2): @@ -240,7 +240,7 @@ async def test_nexus_operation_fails_without_retry_as_handler_error( class StartTimeoutTestService: @sync_operation async def expect_timeout_cancellation_async( - self, ctx: StartOperationContext, input: None + self, ctx: StartOperationContext, _input: None ) -> None: try: await asyncio.wait_for(ctx.task_cancellation.wait_until_cancelled(), 1) @@ -249,7 +249,7 @@ async def expect_timeout_cancellation_async( @sync_operation def expect_timeout_cancellation_sync( - self, ctx: StartOperationContext, input: None + self, ctx: StartOperationContext, _input: None ) -> None: global _start_operation_sync_complete cancelled = ctx.task_cancellation.wait_until_cancelled_sync(1) diff --git a/tests/nexus/test_workflow_run_operation.py b/tests/nexus/test_workflow_run_operation.py index cfbaa91ef..7d284412c 100644 --- a/tests/nexus/test_workflow_run_operation.py +++ b/tests/nexus/test_workflow_run_operation.py @@ -1,7 +1,7 @@ import re import uuid from dataclasses import dataclass -from typing import Any, Type +from typing import Any import nexusrpc import pytest diff --git a/tests/test_client.py b/tests/test_client.py index 791c59b2d..833c97fb0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,7 +6,7 @@ import uuid from collections.abc import Mapping from datetime import datetime, timedelta, timezone -from typing import Any, List, Optional, Tuple, Union, cast +from typing import Any, cast from unittest import mock import google.protobuf.any_pb2 @@ -46,8 +46,6 @@ Interceptor, OutboundInterceptor, QueryWorkflowInput, - RPCError, - RPCStatusCode, Schedule, ScheduleActionExecutionStartWorkflow, ScheduleActionStartWorkflow, @@ -86,6 +84,10 @@ ) from temporalio.converter import DataConverter from temporalio.exceptions import WorkflowAlreadyStartedError +from temporalio.service import ( + RPCError, + RPCStatusCode, +) from temporalio.testing import WorkflowEnvironment from tests.helpers import ( assert_eq_eventually, @@ -378,7 +380,7 @@ async def test_query(client: Client, worker: ExternalWorker): await handle.result() assert "some query arg" == await handle.query("some query", "some query arg") # Try a query not on the workflow - with pytest.raises(WorkflowQueryFailedError) as err: + with pytest.raises(WorkflowQueryFailedError): await handle.query("does not exist") @@ -899,7 +901,7 @@ def update_schedule_simple(input: ScheduleUpdateInput) -> ScheduleUpdate: # Update but error with pytest.raises(RuntimeError) as err: - def update_fail(input: ScheduleUpdateInput) -> ScheduleUpdate: + def update_fail(_input: ScheduleUpdateInput) -> ScheduleUpdate: raise RuntimeError("Oh no") await handle.update(update_fail) @@ -919,7 +921,7 @@ def update_fail(input: ScheduleUpdateInput) -> ScheduleUpdate: ) assert isinstance(new_schedule.action, ScheduleActionStartWorkflow) - async def update_schedule_basic(input: ScheduleUpdateInput) -> ScheduleUpdate: + async def update_schedule_basic(_input: ScheduleUpdateInput) -> ScheduleUpdate: return ScheduleUpdate(new_schedule) await handle.update(update_schedule_basic) @@ -1163,7 +1165,7 @@ async def test_schedule_backfill( async def test_schedule_create_limited_actions_validation( - client: Client, worker: ExternalWorker, env: WorkflowEnvironment + client: Client, worker: ExternalWorker ): sched = Schedule( action=ScheduleActionStartWorkflow( @@ -1561,7 +1563,7 @@ def test_fork_create_client( self._expected = _ForkTestResult.assertion_error( "Cannot create client across forks" ) - self._env = env + self._env = env # type:ignore[reportUninitializedInstanceVariable] self.run(mp_fork_ctx) @@ -1579,5 +1581,5 @@ def test_fork_use_client( self._expected = _ForkTestResult.assertion_error( "Cannot use client across forks" ) - self._client = client + self._client = client # type:ignore[reportUninitializedInstanceVariable] self.run(mp_fork_ctx) diff --git a/tests/test_client_type_errors.py b/tests/test_client_type_errors.py index d0f3b6de5..adf3fcd3c 100644 --- a/tests/test_client_type_errors.py +++ b/tests/test_client_type_errors.py @@ -79,7 +79,7 @@ async def run(self, _: WorkflowInput) -> WorkflowOutput: return WorkflowOutput() -async def _start_and_execute_workflow_code_for_type_checking_test(): +async def _start_and_execute_workflow_code_for_type_checking_test(): # type:ignore[reportUnusedFunction] client = Client(service_client=Mock(spec=ServiceClient)) # Good @@ -117,7 +117,7 @@ async def _start_and_execute_workflow_code_for_type_checking_test(): ) -async def _signal_workflow_code_for_type_checking_test(): +async def _signal_workflow_code_for_type_checking_test(): # type:ignore[reportUnusedFunction] client = Client(service_client=Mock(spec=ServiceClient)) handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow( TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq" @@ -134,7 +134,7 @@ async def _signal_workflow_code_for_type_checking_test(): await handle.signal(TestWorkflow2.signal, SignalInput()) # type: ignore -async def _query_workflow_code_for_type_checking_test(): +async def _query_workflow_code_for_type_checking_test(): # type:ignore[reportUnusedFunction] client = Client(service_client=Mock(spec=ServiceClient)) handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow( TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq" @@ -152,7 +152,7 @@ async def _query_workflow_code_for_type_checking_test(): await handle.query(TestWorkflow2.query, QueryInput()) # type: ignore -async def _update_workflow_code_for_type_checking_test(): +async def _update_workflow_code_for_type_checking_test(): # type:ignore[reportUnusedFunction] client = Client(service_client=Mock(spec=ServiceClient)) handle: WorkflowHandle[TestWorkflow, WorkflowOutput] = await client.start_workflow( TestWorkflow.run, WorkflowInput(), id="wid", task_queue="tq" @@ -186,7 +186,7 @@ async def _update_workflow_code_for_type_checking_test(): await handle.execute_update(TestWorkflow2.update, UpdateInput()) # type: ignore -async def _update_with_start_workflow_code_for_type_checking_test(): +async def _update_with_start_workflow_code_for_type_checking_test(): # type:ignore[reportUnusedFunction] client = Client(service_client=Mock(spec=ServiceClient)) # Good diff --git a/tests/test_common.py b/tests/test_common.py index 5df4767c4..84dfc09b9 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -38,19 +38,19 @@ def test_retry_policy_validate(): RetryPolicy(maximum_attempts=-1)._validate() -def some_hinted_func(foo: str) -> DefinedLater: +def some_hinted_func(_foo: str) -> DefinedLater: return DefinedLater() -async def some_hinted_func_async(foo: str) -> DefinedLater: +async def some_hinted_func_async(_foo: str) -> DefinedLater: return DefinedLater() class MyCallableClass: - def __call__(self, foo: str) -> DefinedLater: + def __call__(self, _foo: str) -> DefinedLater: raise NotImplementedError - def some_method(self, foo: str) -> DefinedLater: + def some_method(self, _foo: str) -> DefinedLater: raise NotImplementedError diff --git a/tests/test_converter.py b/tests/test_converter.py index 138ea65b5..bb5b3c8bc 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -13,17 +13,9 @@ from enum import Enum, IntEnum from typing import ( Any, - Deque, - Dict, - List, + Dict, # type:ignore[reportDeprecated] Literal, NewType, - Optional, - Set, - Text, - Tuple, - Type, - Union, ) from uuid import UUID, uuid4 @@ -56,7 +48,7 @@ # StrEnum is available in 3.11+ if sys.version_info >= (3, 11): - from enum import StrEnum + from enum import StrEnum # type:ignore[reportUnreachable] class NonSerializableClass: @@ -73,7 +65,7 @@ class SerializableEnum(IntEnum): if sys.version_info >= (3, 11): - class SerializableStrEnum(StrEnum): + class SerializableStrEnum(StrEnum): # type:ignore[reportUnreachable] FOO = "foo" @@ -99,12 +91,12 @@ class NewTypeMessage: async def test_converter_default(): async def assert_payload( - input, - expected_encoding, - expected_data, + input, # type:ignore[reportMissingParameterType] + expected_encoding, # type:ignore[reportMissingParameterType] + expected_data, # type:ignore[reportMissingParameterType] *, - expected_decoded_input=None, - type_hint=None, + expected_decoded_input=None, # type:ignore[reportMissingParameterType] + type_hint=None, # type:ignore[reportMissingParameterType] ): payloads = await DataConverter().encode([input]) # Check encoding and data @@ -258,7 +250,7 @@ def test_encode_search_attribute_values(): with pytest.raises(TypeError, match="of type tuple not one of"): encode_search_attribute_values([("bad type",)]) # type: ignore[arg-type] with pytest.raises(ValueError, match="Timezone must be present"): - encode_search_attribute_values([datetime.utcnow()]) + encode_search_attribute_values([datetime.utcnow()]) # type: ignore[reportDeprecated] with pytest.raises(TypeError, match="must have the same type"): encode_search_attribute_values(["foo", 123]) # type: ignore[arg-type] @@ -266,7 +258,7 @@ def test_encode_search_attribute_values(): def test_decode_search_attributes(): """Tests decode from protobuf for python types""" - def payload(key, dtype, data, encoding=None): + def payload(key, dtype, data, encoding=None): # type:ignore[reportMissingParameterType] if encoding is None: encoding = {"encoding": b"json/plain"} check = temporalio.api.common.v1.Payload( @@ -323,7 +315,7 @@ class MyTypedDictNotTotal(TypedDict, total=False): # TODO(cretz): Fix when https://github.com/pydantic/pydantic/pull/9612 tagged if sys.version_info <= (3, 12, 3): - class MyPydanticClass(pydantic.BaseModel): + class MyPydanticClass(pydantic.BaseModel): # type: ignore[reportUnreachable] foo: str bar: list[MyPydanticClass] baz: UUID | None = None @@ -388,13 +380,13 @@ def fail(hint: Any, value: Any) -> None: ok(NestedDataClass, {"foo": "bar", "unknownfield": "baz"}, NestedDataClass("bar")) # Optional/Union - ok(Optional[int], 5) - ok(Optional[int], None) - ok(Optional[MyDataClass], MyDataClass("foo", 5, SerializableEnum.FOO)) - ok(Union[int, str], 5) - ok(Union[int, str], "foo") - ok(Union[MyDataClass, NestedDataClass], MyDataClass("foo", 5, SerializableEnum.FOO)) - ok(Union[MyDataClass, NestedDataClass], NestedDataClass("foo")) + ok(int | None, 5) + ok(int | None, None) + ok(MyDataClass | None, MyDataClass("foo", 5, SerializableEnum.FOO)) + ok(int | str, 5) + ok(int | str, "foo") + ok(MyDataClass | NestedDataClass, MyDataClass("foo", 5, SerializableEnum.FOO)) + ok(MyDataClass | NestedDataClass, NestedDataClass("foo")) ok(int | None, None) ok(int | None, 5) fail(int | None, "1") @@ -414,7 +406,7 @@ def fail(hint: Any, value: Any) -> None: ok(set[int], {5, 6}) ok(set, {5, 6}) ok(list, ["foo"]) - ok(Deque[int], deque([5, 6])) + ok(deque[int], deque([5, 6])) ok(Sequence[int], [5, 6]) fail(list[int], [1, 2, "3"]) @@ -445,7 +437,7 @@ def fail(hint: Any, value: Any) -> None: ok(dict[None, str], {"null": "1"}) # Dict has a different value for None keys - ok(Dict[None, str], {None: "1"}) + ok(Dict[None, str], {None: "1"}) # type:ignore[reportDeprecated] # Alias ok(MyDataClassAlias, MyDataClass("foo", 5, SerializableEnum.FOO)) @@ -461,7 +453,7 @@ def fail(hint: Any, value: Any) -> None: # StrEnum is available in 3.11+ if sys.version_info >= (3, 11): # StrEnum - ok(SerializableStrEnum, SerializableStrEnum.FOO) + ok(SerializableStrEnum, SerializableStrEnum.FOO) # type:ignore[reportUnreachable] ok( list[SerializableStrEnum], [SerializableStrEnum.FOO, SerializableStrEnum.FOO], @@ -470,7 +462,7 @@ def fail(hint: Any, value: Any) -> None: # Pydantic # TODO(cretz): Fix when https://github.com/pydantic/pydantic/pull/9612 tagged if sys.version_info <= (3, 12, 3): - ok( + ok( # type: ignore[reportUnreachable] MyPydanticClass, MyPydanticClass( foo="foo", bar=[MyPydanticClass(foo="baz", bar=[])], baz=uuid4() diff --git a/tests/test_envconfig.py b/tests/test_envconfig.py index 9bd385fce..c1a7e32ab 100644 --- a/tests/test_envconfig.py +++ b/tests/test_envconfig.py @@ -258,7 +258,7 @@ def test_load_profiles_from_data_all(): assert connect_config.get("target_host") == "custom-address" -def test_load_profiles_no_env_override(tmp_path: Path, monkeypatch): +def test_load_profiles_no_env_override(tmp_path: Path, monkeypatch): # type: ignore[reportMissingParameterType] """Confirm that load_profiles does not apply env overrides.""" config_file = tmp_path / "config.toml" config_file.write_text(TOML_CONFIG_BASE) diff --git a/tests/test_plugins.py b/tests/test_plugins.py index ea2cf3a1a..399d16c7e 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -1,10 +1,9 @@ import dataclasses import uuid import warnings -from collections import Counter from collections.abc import AsyncIterator, Awaitable, Callable from contextlib import AbstractAsyncContextManager, asynccontextmanager -from typing import Optional, cast +from typing import cast import pytest @@ -182,7 +181,7 @@ async def test_worker_duplicated_plugin(client: Client) -> None: client = Client(**new_config) with warnings.catch_warnings(record=True) as warning_list: - worker = Worker( + Worker( client, task_queue="queue" + str(uuid.uuid4()), activities=[never_run_activity], @@ -194,7 +193,7 @@ async def test_worker_duplicated_plugin(client: Client) -> None: async def test_worker_sandbox_restrictions(client: Client) -> None: - with warnings.catch_warnings(record=True) as warning_list: + with warnings.catch_warnings(record=True): worker = Worker( client, task_queue="queue" + str(uuid.uuid4()), diff --git a/tests/test_runtime.py b/tests/test_runtime.py index c2829f03d..bc21d7d6c 100644 --- a/tests/test_runtime.py +++ b/tests/test_runtime.py @@ -4,7 +4,7 @@ import re import uuid from datetime import timedelta -from typing import List, cast +from typing import cast from urllib.request import urlopen import pytest @@ -25,7 +25,6 @@ assert_eq_eventually, assert_eventually, find_free_port, - worker_versioning_enabled, ) diff --git a/tests/test_serialization_context.py b/tests/test_serialization_context.py index 07d48bdd3..4e217861b 100644 --- a/tests/test_serialization_context.py +++ b/tests/test_serialization_context.py @@ -15,7 +15,7 @@ from collections.abc import Sequence from dataclasses import dataclass, field from datetime import timedelta -from typing import Any, List, Literal, Optional, Type +from typing import Any, Literal import nexusrpc import pytest @@ -837,7 +837,7 @@ def __init__(self, pass_validation: bool) -> None: self.input: TraceData | None = None @workflow.run - async def run(self, pass_validation: bool) -> TraceData: + async def run(self, _pass_validation: bool) -> TraceData: await workflow.wait_condition(lambda: self.input is not None) assert self.input return self.input @@ -1583,7 +1583,7 @@ def __init__(self): self.received_update = False @workflow.run - async def run(self, data: str) -> str: + async def run(self, _data: str) -> str: await workflow.wait_condition( lambda: (self.received_signal and self.received_update) ) @@ -1705,7 +1705,7 @@ async def operation( @workflow.defn class NexusOperationTestWorkflow: @workflow.run - async def run(self, data: str) -> None: + async def run(self, _data: str) -> None: nexus_client = workflow.create_nexus_client( service=NexusOperationTestServiceHandler, endpoint=make_nexus_endpoint_name(workflow.info().task_queue), diff --git a/tests/test_service.py b/tests/test_service.py index 61acf7ded..9fdcd9fc7 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -3,7 +3,7 @@ import re from collections.abc import Callable, Mapping from datetime import timedelta -from typing import Any, Dict, Tuple, Type +from typing import Any import google.protobuf.empty_pb2 import google.protobuf.message @@ -47,7 +47,7 @@ def assert_all_calls_present( ) -> None: # Collect service calls service_calls = set() - for name, call in inspect.getmembers(service): + for name, _call in inspect.getmembers(service): # ignore private methods and non-rpc members "client" and "service" if name[0] != "_" and name != "client" and name != "service": service_calls.add(name) diff --git a/tests/test_workflow.py b/tests/test_workflow.py index f46775975..c62a69cce 100644 --- a/tests/test_workflow.py +++ b/tests/test_workflow.py @@ -2,7 +2,7 @@ import itertools import typing from collections.abc import Callable, Sequence -from typing import Any, Set, Type, get_type_hints +from typing import Any, get_type_hints import pytest @@ -12,7 +12,7 @@ class GoodDefnBase: @workflow.run - async def run(self, name: str) -> str: + async def run(self, _name: str) -> str: raise NotImplementedError @workflow.signal @@ -31,7 +31,7 @@ def base_update(self): @workflow.defn(name="workflow-custom") class GoodDefn(GoodDefnBase): @workflow.run - async def run(self, name: str) -> str: + async def run(self, _name: str) -> str: raise NotImplementedError @workflow.signal @@ -43,7 +43,7 @@ def signal2(self): pass @workflow.signal(dynamic=True, description="boo") - def signal3(self, name: str, args: Sequence[RawValue]): + def signal3(self, _name: str, _args: Sequence[RawValue]): pass @workflow.query @@ -55,7 +55,7 @@ def query2(self): pass @workflow.query(dynamic=True, description="dqd") - def query3(self, name: str, args: Sequence[RawValue]): + def query3(self, _name: str, _args: Sequence[RawValue]): pass @workflow.update @@ -67,7 +67,7 @@ def update2(self): pass @workflow.update(dynamic=True, description="dud") - def update3(self, name: str, args: Sequence[RawValue]): + def update3(self, _name: str, _args: Sequence[RawValue]): pass @@ -160,7 +160,7 @@ def test_workflow_defn_good(): @workflow.defn(versioning_behavior=VersioningBehavior.PINNED) class VersioningBehaviorDefn: @workflow.run - async def run(self, name: str) -> str: + async def run(self, _name: str) -> str: raise NotImplementedError @@ -205,11 +205,11 @@ def signal2(self): pass @workflow.signal(dynamic=True) - def signal3(self, name: str, args: Sequence[RawValue]): + def signal3(self, _name: str, _args: Sequence[RawValue]): pass @workflow.signal(dynamic=True) - def signal4(self, name: str, args: Sequence[RawValue]): + def signal4(self, _name: str, _args: Sequence[RawValue]): pass # Intentionally missing decorator @@ -225,11 +225,11 @@ def query2(self): pass @workflow.query(dynamic=True) - def query3(self, name: str, args: Sequence[RawValue]): + def query3(self, _name: str, _args: Sequence[RawValue]): pass @workflow.query(dynamic=True) - def query4(self, name: str, args: Sequence[RawValue]): + def query4(self, _name: str, _args: Sequence[RawValue]): pass # Intentionally missing decorator @@ -237,11 +237,11 @@ def base_query(self): pass @workflow.update - def update1(self, arg1: str): + def update1(self, _arg1: str): pass @workflow.update(name="update1") - def update2(self, arg1: str): + def update2(self, _arg1: str): pass # Intentionally missing decorator @@ -293,7 +293,7 @@ def test_workflow_defn_local_class(): with pytest.raises(ValueError) as err: @workflow.defn - class LocalClass: + class LocalClass: # type:ignore[reportUnusedClass] @workflow.run async def run(self): pass @@ -409,31 +409,31 @@ def a1(self, a): # type: ignore[reportMissingParameterType] def a2(self, b): # type: ignore[reportMissingParameterType] pass - def b1(self, a: int): + def b1(self, _a: int): pass - def b2(self, b: int) -> str: + def b2(self, _b: int) -> str: return "" - def c1(self, a1: int, a2: str) -> str: + def c1(self, _a1: int, _a2: str) -> str: return "" - def c2(self, b1: int, b2: str) -> int: + def c2(self, _b1: int, _b2: str) -> int: return 0 - def d1(self, a1, a2: str) -> None: # type: ignore[reportMissingParameterType] + def d1(self, _a1, _a2: str) -> None: # type: ignore[reportMissingParameterType] pass - def d2(self, b1, b2: str) -> str: # type: ignore[reportMissingParameterType] + def d2(self, _b1, _b2: str) -> str: # type: ignore[reportMissingParameterType] return "" - def e1(self, a1, a2: str = "") -> None: # type: ignore[reportMissingParameterType] + def e1(self, _a1, _a2: str = "") -> None: # type: ignore[reportMissingParameterType] return None - def e2(self, b1, b2: str = "") -> str: # type: ignore[reportMissingParameterType] + def e2(self, _b1, _b2: str = "") -> str: # type: ignore[reportMissingParameterType] return "" - def f1(self, a1, a2: str = "a") -> None: # type: ignore[reportMissingParameterType] + def f1(self, _a1, _a2: str = "a") -> None: # type: ignore[reportMissingParameterType] return None @@ -469,12 +469,12 @@ def test_workflow_init_not__init__(): class BadUpdateValidator: @workflow.update - def my_update(self, a: str): + def my_update(self, _a: str): pass # assert-type-error-pyright: "Argument of type .+ cannot be assigned to parameter" @my_update.validator # type: ignore - def my_validator(self, a: int): + def my_validator(self, _a: int): pass @workflow.run @@ -496,7 +496,6 @@ def _assert_config_function_parity( config_class: type[Any], excluded_params: set[str], ) -> None: - function_name = function_obj.__name__ config_name = config_class.__name__ # Get the signature and type hints diff --git a/tests/testing/test_workflow.py b/tests/testing/test_workflow.py index 1a857a55d..b0082d1cd 100644 --- a/tests/testing/test_workflow.py +++ b/tests/testing/test_workflow.py @@ -1,10 +1,9 @@ import asyncio import platform -import sys import uuid from datetime import datetime, timedelta, timezone from time import monotonic -from typing import Any, Optional, Union +from typing import Any import pytest @@ -13,7 +12,6 @@ Client, Interceptor, OutboundInterceptor, - RPCError, StartWorkflowInput, WorkflowFailureError, WorkflowHandle, @@ -30,6 +28,7 @@ TimeoutError, TimeoutType, ) +from temporalio.service import RPCError from temporalio.testing import WorkflowEnvironment from tests import DEV_SERVER_DOWNLOAD_VERSION from tests.helpers import new_worker diff --git a/tests/worker/test_activity.py b/tests/worker/test_activity.py index 7a9e27f84..e66a42dc0 100644 --- a/tests/worker/test_activity.py +++ b/tests/worker/test_activity.py @@ -15,7 +15,7 @@ from dataclasses import dataclass from datetime import datetime, timedelta, timezone from time import sleep -from typing import Any, List, NoReturn, Optional, Type +from typing import Any, NoReturn import pytest @@ -101,7 +101,7 @@ async def test_activity_custom_name( shared_state_manager: SharedStateManager, ): @activity.defn(name="my custom activity name!") - async def get_name(name: str) -> str: + async def get_name(_name: str) -> str: return f"Name: {activity.info().activity_type}" result = await _execute_workflow_with_activity( @@ -202,7 +202,7 @@ async def capture_info() -> None: ) assert info - assert info.activity_id + assert info.activity_id # type:ignore[reportUnreachable] assert info.activity_type == "capture_info" assert info.attempt == 1 assert abs( @@ -364,7 +364,7 @@ async def test_activity_kwonly_params(): with pytest.raises(TypeError) as err: @activity.defn - async def say_hello(*, name: str) -> str: + async def say_hello(*, name: str) -> str: # type:ignore[reportUnusedFunction] return f"Hello, {name}!" assert str(err.value).endswith("cannot have keyword-only arguments") @@ -1045,7 +1045,6 @@ async def say_hello(name: str) -> str: async def test_activity_worker_shutdown( client: Client, worker: ExternalWorker, - shared_state_manager: SharedStateManager, ): activity_started = asyncio.Event() @@ -1541,11 +1540,11 @@ async def test_activity_dynamic_duplicate( shared_state_manager: SharedStateManager, ): @activity.defn(dynamic=True) - async def dyn_activity_1(args: Sequence[RawValue]) -> None: + async def dyn_activity_1(_args: Sequence[RawValue]) -> None: pass @activity.defn(dynamic=True) - async def dyn_activity_2(args: Sequence[RawValue]) -> None: + async def dyn_activity_2(_args: Sequence[RawValue]) -> None: pass with pytest.raises(TypeError) as err: @@ -1823,7 +1822,7 @@ async def wait_cancel() -> str: activity.heartbeat() with pytest.raises(WorkflowFailureError) as e: - result = await _execute_workflow_with_activity( + await _execute_workflow_with_activity( client, worker, wait_cancel, diff --git a/tests/worker/test_command_aware_visitor.py b/tests/worker/test_command_aware_visitor.py index 9e4b7a39b..b8488689e 100644 --- a/tests/worker/test_command_aware_visitor.py +++ b/tests/worker/test_command_aware_visitor.py @@ -1,7 +1,7 @@ """Test that CommandAwarePayloadVisitor handles all commands with seq fields that have payloads.""" from collections.abc import Iterator -from typing import Any, Type +from typing import Any from temporalio.bridge._visitor import PayloadVisitor from temporalio.bridge.proto.workflow_activation import workflow_activation_pb2 @@ -15,8 +15,6 @@ def test_command_aware_visitor_has_methods_for_all_seq_protos_with_payloads(): We only override methods when the base class has a visitor method (i.e., there are payloads to visit). Commands without payloads don't need overrides since there's nothing to visit. """ - visitor = CommandAwarePayloadVisitor() - # Find all protos with seq command_protos = list(_get_workflow_command_protos_with_seq()) job_protos = list(_get_workflow_activation_job_protos_with_seq()) diff --git a/tests/worker/test_interceptor.py b/tests/worker/test_interceptor.py index a5616bb17..16605876e 100644 --- a/tests/worker/test_interceptor.py +++ b/tests/worker/test_interceptor.py @@ -2,7 +2,7 @@ import uuid from collections.abc import Callable from datetime import timedelta -from typing import Any, List, NoReturn, Optional, Tuple, Type +from typing import Any, NoReturn import nexusrpc import pytest @@ -167,7 +167,7 @@ async def execute_nexus_operation_cancel( @workflow.defn class ExpectCancelNexusWorkflow: @workflow.run - async def run(self, input: str): + async def run(self, _input: str): try: await asyncio.wait_for(asyncio.Future(), 2) except asyncio.TimeoutError: @@ -252,7 +252,7 @@ def query(self, param: str) -> str: return f"query: {param}" @workflow.signal - def signal(self, param: str) -> None: + def signal(self, _param: str) -> None: self.finish.set() @workflow.update diff --git a/tests/worker/test_replayer.py b/tests/worker/test_replayer.py index 67c1b1d52..22d771556 100644 --- a/tests/worker/test_replayer.py +++ b/tests/worker/test_replayer.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from datetime import timedelta from pathlib import Path -from typing import Any, Dict, Optional, Type +from typing import Any import pytest diff --git a/tests/worker/test_update_with_start.py b/tests/worker/test_update_with_start.py index 23f997c08..4ed625960 100644 --- a/tests/worker/test_update_with_start.py +++ b/tests/worker/test_update_with_start.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from datetime import timedelta from enum import Enum, IntEnum -from typing import Any, Optional, Union +from typing import Any from unittest.mock import patch import pytest diff --git a/tests/worker/test_visitor.py b/tests/worker/test_visitor.py index 4fb820f31..41e6ccad9 100644 --- a/tests/worker/test_visitor.py +++ b/tests/worker/test_visitor.py @@ -99,14 +99,6 @@ async def test_workflow_activation(): ] ) - async def visitor(payload: Payload) -> Payload: - # Mark visited by prefixing data - new_payload = Payload() - new_payload.metadata.update(payload.metadata) - new_payload.metadata["visited"] = b"True" - new_payload.data = payload.data - return new_payload - act = original.__deepcopy__() await PayloadVisitor().visit(Visitor(), act) assert act.jobs[0].initialize_workflow.arguments[0].metadata["visited"] diff --git a/tests/worker/test_worker.py b/tests/worker/test_worker.py index 9779bc633..b1b65112d 100644 --- a/tests/worker/test_worker.py +++ b/tests/worker/test_worker.py @@ -7,7 +7,7 @@ import uuid from collections.abc import Awaitable, Callable, Sequence from datetime import timedelta -from typing import Any, Optional +from typing import Any from urllib.request import urlopen import nexusrpc @@ -20,16 +20,13 @@ from temporalio.api.workflowservice.v1 import ( DescribeWorkerDeploymentRequest, DescribeWorkerDeploymentResponse, - ListWorkersRequest, SetWorkerDeploymentCurrentVersionRequest, SetWorkerDeploymentCurrentVersionResponse, SetWorkerDeploymentRampingVersionRequest, SetWorkerDeploymentRampingVersionResponse, ) from temporalio.client import ( - BuildIdOpAddNewDefault, Client, - TaskReachabilityType, ) from temporalio.common import PinnedVersioningOverride, RawValue, VersioningBehavior from temporalio.runtime import ( @@ -64,7 +61,6 @@ assert_eventually, find_free_port, new_worker, - worker_versioning_enabled, ) from tests.helpers.fork import _ForkTestResult, _TestFork from tests.helpers.nexus import create_nexus_endpoint, make_nexus_endpoint_name @@ -239,7 +235,7 @@ async def test_worker_validate_fail(client: Client, env: WorkflowEnvironment): assert str(err.value).startswith("Worker validation failed") -async def test_can_run_resource_based_worker(client: Client, env: WorkflowEnvironment): +async def test_can_run_resource_based_worker(client: Client): tuner = WorkerTuner.create_resource_based( target_memory_usage=0.5, target_cpu_usage=0.5, @@ -262,7 +258,7 @@ async def test_can_run_resource_based_worker(client: Client, env: WorkflowEnviro await wf1.result() -async def test_can_run_composite_tuner_worker(client: Client, env: WorkflowEnvironment): +async def test_can_run_composite_tuner_worker(client: Client): resource_based_options = ResourceBasedTunerConfig(0.5, 0.5) tuner = WorkerTuner.create_composite( workflow_supplier=FixedSizeSlotSupplier(5), @@ -299,9 +295,7 @@ async def test_can_run_composite_tuner_worker(client: Client, env: WorkflowEnvir await wf1.result() -async def test_cant_specify_max_concurrent_and_tuner( - client: Client, env: WorkflowEnvironment -): +async def test_cant_specify_max_concurrent_and_tuner(client: Client): tuner = WorkerTuner.create_resource_based( target_memory_usage=0.5, target_cpu_usage=0.5, @@ -320,7 +314,7 @@ async def test_cant_specify_max_concurrent_and_tuner( assert "when also specifying tuner" in str(err.value) -async def test_warns_when_workers_too_low(client: Client, env: WorkflowEnvironment): +async def test_warns_when_workers_too_low(client: Client): tuner = WorkerTuner.create_resource_based( target_memory_usage=0.5, target_cpu_usage=0.5, @@ -503,7 +497,7 @@ async def run(self) -> str: return "hi" -async def test_throwing_slot_supplier(client: Client, env: WorkflowEnvironment): +async def test_throwing_slot_supplier(client: Client): """Ensures a (mostly) broken slot supplier doesn't hose everything up""" class ThrowingSlotSupplier(CustomSlotSupplier): @@ -546,7 +540,7 @@ def release_slot(self, ctx: SlotReleaseContext) -> None: await wf1.result() -async def test_blocking_slot_supplier(client: Client, env: WorkflowEnvironment): +async def test_blocking_slot_supplier(client: Client): class BlockingSlotSupplier(CustomSlotSupplier): marked_used = False @@ -828,7 +822,7 @@ async def check_results(): @workflow.defn(dynamic=True, versioning_behavior=VersioningBehavior.PINNED) class DynamicWorkflowVersioningOnDefn: @workflow.run - async def run(self, args: Sequence[RawValue]) -> str: + async def run(self, _args: Sequence[RawValue]) -> str: return "dynamic" @@ -841,7 +835,7 @@ def dynamic_config(self) -> DynamicWorkflowConfig: ) @workflow.run - async def run(self, args: Sequence[RawValue]) -> str: + async def run(self, _args: Sequence[RawValue]) -> str: return "dynamic" @@ -922,12 +916,12 @@ async def run(self) -> str: @workflow.defn(dynamic=True) class NoVersioningAnnotationDynamicWorkflow: @workflow.run - async def run(self, args: Sequence[RawValue]) -> str: + async def run(self, _args: Sequence[RawValue]) -> str: return "whee" async def test_workflows_must_have_versioning_behavior_when_feature_turned_on( - client: Client, env: WorkflowEnvironment + client: Client, ): with pytest.raises(ValueError) as exc_info: Worker( @@ -1051,9 +1045,7 @@ async def test_workflows_can_use_versioning_override( ) -async def test_can_run_autoscaling_polling_worker( - client: Client, env: WorkflowEnvironment -): +async def test_can_run_autoscaling_polling_worker(client: Client): # Create new runtime with Prom server prom_addr = f"127.0.0.1:{find_free_port()}" runtime = Runtime( @@ -1228,7 +1220,7 @@ def shutdown(self) -> None: class TestForkCreateWorker(_TestFork): async def coro(self): - self._worker = Worker( + self._worker = Worker( # type:ignore[reportUninitializedInstanceVariable] self._client, task_queue=f"task-queue-{uuid.uuid4()}", activities=[never_run_activity], @@ -1242,7 +1234,7 @@ def test_fork_create_worker( self._expected = _ForkTestResult.assertion_error( "Cannot create worker across forks" ) - self._client = client + self._client = client # type:ignore[reportUninitializedInstanceVariable] self.run(mp_fork_ctx) @@ -1256,7 +1248,7 @@ def test_fork_use_worker( self._expected = _ForkTestResult.assertion_error( "Cannot use worker across forks" ) - self._pre_fork_worker = Worker( + self._pre_fork_worker = Worker( # type:ignore[reportUninitializedInstanceVariable] client, task_queue=f"task-queue-{uuid.uuid4()}", activities=[never_run_activity], diff --git a/tests/worker/test_workflow.py b/tests/worker/test_workflow.py index 5dcab07cf..8c7feae82 100644 --- a/tests/worker/test_workflow.py +++ b/tests/worker/test_workflow.py @@ -1,3 +1,4 @@ +# pyright: reportUnreachable=false from __future__ import annotations import asyncio @@ -22,14 +23,8 @@ from functools import partial from typing import ( Any, - Dict, - List, Literal, NoReturn, - Optional, - Tuple, - Type, - Union, cast, ) from urllib.request import urlopen @@ -62,8 +57,6 @@ AsyncActivityCancelledError, Client, CreateScheduleInput, - RPCError, - RPCStatusCode, ScheduleActionStartWorkflow, ScheduleHandle, SignalWorkflowInput, @@ -115,7 +108,7 @@ Runtime, TelemetryConfig, ) -from temporalio.service import __version__ +from temporalio.service import RPCError, RPCStatusCode, __version__ from temporalio.testing import WorkflowEnvironment from temporalio.worker import ( ExecuteWorkflowInput, @@ -1196,7 +1189,7 @@ async def test_workflow_cancel_child_started(client: Client, use_execute: bool): @pytest.mark.skip(reason="unable to easily prevent child start currently") -async def test_workflow_cancel_child_unstarted(client: Client): +async def test_workflow_cancel_child_unstarted(_client: Client): raise NotImplementedError @@ -1531,7 +1524,7 @@ async def decode(self, payloads: Sequence[Payload]) -> list[Payload]: return list(wrapper.payloads) -async def test_workflow_with_codec(client: Client, env: WorkflowEnvironment): +async def test_workflow_with_codec(client: Client): # Make client with this codec and run a couple of existing tests config = client.config() config["data_converter"] = DataConverter(payload_codec=SimpleCodec()) @@ -1996,7 +1989,7 @@ def last_signal(self) -> str: return self._last_signal -async def test_workflow_logging(client: Client, env: WorkflowEnvironment): +async def test_workflow_logging(client: Client): workflow.logger.full_workflow_info_on_extra = True with LogCapturer().logs_captured( workflow.logger.base_logger, activity.logger.base_logger @@ -5148,7 +5141,7 @@ class Foo(pydantic.BaseModel): @workflow.defn(failure_exception_types=[pydantic.ValidationError]) class FailOnBadPydanticInputWorkflow: @workflow.run - async def run(self, params: Foo) -> None: + async def run(self, _params: Foo) -> None: pass @@ -5168,7 +5161,7 @@ async def test_workflow_fail_on_bad_pydantic_input(client: Client): @workflow.defn(failure_exception_types=[Exception]) class FailOnBadInputWorkflow: @workflow.run - async def run(self, param: str) -> None: + async def run(self, _param: str) -> None: pass @@ -5261,7 +5254,7 @@ async def test_workflow_replace_worker_client_diff_runtimes_fail(client: Client) @activity.defn(dynamic=True) -async def return_name_activity(args: Sequence[RawValue]) -> str: +async def return_name_activity(_args: Sequence[RawValue]) -> str: return activity.info().activity_type @@ -5620,13 +5613,13 @@ async def run( if handler_dynamism == "-dynamic-": async def my_late_registered_dynamic_update( - name: str, args: Sequence[RawValue] + _name: str, _args: Sequence[RawValue] ) -> str: await workflow.wait_condition(lambda: self.handlers_may_finish) return "my-late-registered-dynamic-update-result" async def my_late_registered_dynamic_signal( - name: str, args: Sequence[RawValue] + _name: str, _args: Sequence[RawValue] ) -> None: await workflow.wait_condition(lambda: self.handlers_may_finish) @@ -5681,12 +5674,12 @@ async def my_signal(self) -> None: await workflow.wait_condition(lambda: self.handlers_may_finish) @workflow.update(dynamic=True) - async def my_dynamic_update(self, name: str, args: Sequence[RawValue]) -> str: + async def my_dynamic_update(self, _name: str, _args: Sequence[RawValue]) -> str: await workflow.wait_condition(lambda: self.handlers_may_finish) return "my-dynamic-update-result" @workflow.signal(dynamic=True) - async def my_dynamic_signal(self, name: str, args: Sequence[RawValue]) -> None: + async def my_dynamic_signal(self, _name: str, _args: Sequence[RawValue]) -> None: await workflow.wait_condition(lambda: self.handlers_may_finish) @@ -5984,7 +5977,6 @@ async def my_update(self) -> str: async def test_update_completion_is_honored_when_after_workflow_return_2( client: Client, - env: WorkflowEnvironment, ): async with Worker( client, @@ -7514,7 +7506,7 @@ def dynamic_config(self) -> temporalio.workflow.DynamicWorkflowConfig: raise Exception("Dynamic config failure") @workflow.run - async def run(self, args: Sequence[RawValue]) -> None: + async def run(self, _args: Sequence[RawValue]) -> None: raise RuntimeError("Should never actually run") @@ -8284,7 +8276,7 @@ async def test_previous_run_failure(client: Client): assert result == "Done" -class EncryptionCodec(PayloadCodec): +class FakeEncryptionCodec(PayloadCodec): def __init__( self, key_id: str = "test-key-id", @@ -8325,7 +8317,6 @@ async def decode(self, payloads: Sequence[Payload]) -> list[Payload]: return ret def encrypt(self, data: bytes) -> bytes: - nonce = os.urandom(12) return data def decrypt(self, data: bytes) -> bytes: @@ -8364,7 +8355,7 @@ async def test_search_attribute_codec(client: Client, env_type: str): config = client.config() config["data_converter"] = dataclasses.replace( - temporalio.converter.default(), payload_codec=EncryptionCodec() + temporalio.converter.default(), payload_codec=FakeEncryptionCodec() ) client = Client(**config) @@ -8375,7 +8366,7 @@ async def test_search_attribute_codec(client: Client, env_type: str): SearchAttributeCodecChildWorkflow, ) as worker: # Run workflow - result = await client.execute_workflow( + await client.execute_workflow( SearchAttributeCodecParentWorkflow.run, "Temporal", id="encryption-workflow-id", @@ -8425,7 +8416,7 @@ async def test_activity_failure_with_encoded_payload_is_decoded_in_workflow( ): config = client.config() config["data_converter"] = dataclasses.replace( - temporalio.converter.default(), payload_codec=EncryptionCodec() + temporalio.converter.default(), payload_codec=FakeEncryptionCodec() ) client = Client(**config) diff --git a/tests/worker/workflow_sandbox/test_importer.py b/tests/worker/workflow_sandbox/test_importer.py index 290ef8648..0ed478c03 100644 --- a/tests/worker/workflow_sandbox/test_importer.py +++ b/tests/worker/workflow_sandbox/test_importer.py @@ -20,7 +20,7 @@ def test_workflow_sandbox_importer_invalid_module(): with pytest.raises(RestrictedWorkflowAccessError) as err: with Importer(restrictions, RestrictionContext()).applied(): - import tests.worker.workflow_sandbox.testmodules.invalid_module + import tests.worker.workflow_sandbox.testmodules.invalid_module # type:ignore[reportUnusedImport] assert ( err.value.qualified_name == "tests.worker.workflow_sandbox.testmodules.invalid_module" @@ -116,8 +116,8 @@ def test_workflow_sandbox_importer_invalid_module_members(): def test_workflow_sandbox_importer_sys_module(): # Import outside to make sure this is in sys.modules - import tests.worker.workflow_sandbox.testmodules.passthrough_module - import tests.worker.workflow_sandbox.testmodules.stateful_module + import tests.worker.workflow_sandbox.testmodules.passthrough_module # type:ignore[reportUnusedImport] + import tests.worker.workflow_sandbox.testmodules.stateful_module # type:ignore[reportUnusedImport] with Importer(restrictions, RestrictionContext()).applied(): # Passthrough should be there but not non-passthrough diff --git a/tests/worker/workflow_sandbox/test_restrictions.py b/tests/worker/workflow_sandbox/test_restrictions.py index 27310c1ed..5e0beb1db 100644 --- a/tests/worker/workflow_sandbox/test_restrictions.py +++ b/tests/worker/workflow_sandbox/test_restrictions.py @@ -3,7 +3,7 @@ import pathlib import sys from dataclasses import dataclass -from typing import ClassVar, Dict, Optional +from typing import ClassVar import pytest diff --git a/tests/worker/workflow_sandbox/test_runner.py b/tests/worker/workflow_sandbox/test_runner.py index 5dc1bd02d..44e58fa3c 100644 --- a/tests/worker/workflow_sandbox/test_runner.py +++ b/tests/worker/workflow_sandbox/test_runner.py @@ -12,7 +12,7 @@ from dataclasses import dataclass from datetime import date, datetime, timedelta from enum import IntEnum -from typing import Any, Dict, List, Optional, Set, Type +from typing import Any import pytest @@ -194,7 +194,7 @@ async def test_workflow_sandbox_restrictions(client: Client): # We can only validate this restriction prior to 3.14 because we had to exempt it due to # https://github.com/python/cpython/issues/140228 if sys.version_info < (3, 14): - invalid_code_to_check.append("import os.path\nos.path.abspath('foo')") + invalid_code_to_check.append("import os.path\nos.path.abspath('foo')") # type: ignore[reportUnreachable] for code in invalid_code_to_check: with pytest.raises(WorkflowFailureError) as err: @@ -500,7 +500,7 @@ async def execute_workflow(self, input: ExecuteWorkflowInput) -> Any: with workflow.unsafe.sandbox_import_notification_policy( workflow.SandboxImportNotificationPolicy.WARN_ON_UNINTENTIONAL_PASSTHROUGH ): - import tests.worker.workflow_sandbox.testmodules.lazy_module_interceptor # noqa: F401 + import tests.worker.workflow_sandbox.testmodules.lazy_module_interceptor # type:ignore[reportUnusedImport] # noqa: F401 return await super().execute_workflow(input) @@ -517,7 +517,7 @@ class LazyImportWorkflow: @workflow.run async def run(self) -> None: try: - import tests.worker.workflow_sandbox.testmodules.lazy_module # noqa: F401 + import tests.worker.workflow_sandbox.testmodules.lazy_module # type:ignore[reportUnusedImport] # noqa: F401 except UnintentionalPassthroughError as err: raise ApplicationError( str(err), type="UnintentionalPassthroughError" @@ -626,7 +626,7 @@ async def run(self) -> None: SandboxImportNotificationPolicy.SILENT ): try: - import tests.worker.workflow_sandbox.testmodules.lazy_module # noqa: F401 + import tests.worker.workflow_sandbox.testmodules.lazy_module # type:ignore[reportUnusedImport] # noqa: F401 except UserWarning: raise ApplicationError("No warnings were expected") diff --git a/uv.lock b/uv.lock index 3dd385b88..e29cf27db 100644 --- a/uv.lock +++ b/uv.lock @@ -208,6 +208,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" }, ] +[[package]] +name = "basedpyright" +version = "1.34.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodejs-wheel-binaries" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/77/ded02ba2b400807b291fa2b9d29ac7f473e86a45d1f5212d8276e9029107/basedpyright-1.34.0.tar.gz", hash = "sha256:7ae3b06f644fac15fdd14a00d0d1f12f92a8205ae1609aabd5a0799b1a68be1d", size = 22803348, upload-time = "2025-11-19T14:48:16.38Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/9e/ced31964ed49f06be6197bd530958b6ddca9a079a8d7ee0ee7429cae9e27/basedpyright-1.34.0-py3-none-any.whl", hash = "sha256:e76015c1ebb671d2c6d7fef8a12bc0f1b9d15d74e17847b7b95a3a66e187c70f", size = 11865958, upload-time = "2025-11-19T14:48:13.724Z" }, +] + [[package]] name = "bashlex" version = "0.18" @@ -1812,6 +1824,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] +[[package]] +name = "nodejs-wheel-binaries" +version = "24.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/89/da307731fdbb05a5f640b26de5b8ac0dc463fef059162accfc89e32f73bc/nodejs_wheel_binaries-24.11.1.tar.gz", hash = "sha256:413dfffeadfb91edb4d8256545dea797c237bba9b3faefea973cde92d96bb922", size = 8059, upload-time = "2025-11-18T18:21:58.207Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/5f/be5a4112e678143d4c15264d918f9a2dc086905c6426eb44515cf391a958/nodejs_wheel_binaries-24.11.1-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:0e14874c3579def458245cdbc3239e37610702b0aa0975c1dc55e2cb80e42102", size = 55114309, upload-time = "2025-11-18T18:21:21.697Z" }, + { url = "https://files.pythonhosted.org/packages/fa/1c/2e9d6af2ea32b65928c42b3e5baa7a306870711d93c3536cb25fc090a80d/nodejs_wheel_binaries-24.11.1-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:c2741525c9874b69b3e5a6d6c9179a6fe484ea0c3d5e7b7c01121c8e5d78b7e2", size = 55285957, upload-time = "2025-11-18T18:21:27.177Z" }, + { url = "https://files.pythonhosted.org/packages/d0/79/35696d7ba41b1bd35ef8682f13d46ba38c826c59e58b86b267458eb53d87/nodejs_wheel_binaries-24.11.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:5ef598101b0fb1c2bf643abb76dfbf6f76f1686198ed17ae46009049ee83c546", size = 59645875, upload-time = "2025-11-18T18:21:33.004Z" }, + { url = "https://files.pythonhosted.org/packages/b4/98/2a9694adee0af72bc602a046b0632a0c89e26586090c558b1c9199b187cc/nodejs_wheel_binaries-24.11.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:cde41d5e4705266688a8d8071debf4f8a6fcea264c61292782672ee75a6905f9", size = 60140941, upload-time = "2025-11-18T18:21:37.228Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d6/573e5e2cba9d934f5f89d0beab00c3315e2e6604eb4df0fcd1d80c5a07a8/nodejs_wheel_binaries-24.11.1-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:78bc5bb889313b565df8969bb7423849a9c7fc218bf735ff0ce176b56b3e96f0", size = 61644243, upload-time = "2025-11-18T18:21:43.325Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e6/643234d5e94067df8ce8d7bba10f3804106668f7a1050aeb10fdd226ead4/nodejs_wheel_binaries-24.11.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c79a7e43869ccecab1cae8183778249cceb14ca2de67b5650b223385682c6239", size = 62225657, upload-time = "2025-11-18T18:21:47.708Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/2fb05127102a80225cab7a75c0e9edf88a0a1b79f912e1e36c7c1aaa8f4e/nodejs_wheel_binaries-24.11.1-py2.py3-none-win_amd64.whl", hash = "sha256:10197b1c9c04d79403501766f76508b0dac101ab34371ef8a46fcf51773497d0", size = 41322308, upload-time = "2025-11-18T18:21:51.347Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b7/bc0cdbc2cc3a66fcac82c79912e135a0110b37b790a14c477f18e18d90cd/nodejs_wheel_binaries-24.11.1-py2.py3-none-win_arm64.whl", hash = "sha256:376b9ea1c4bc1207878975dfeb604f7aa5668c260c6154dcd2af9d42f7734116", size = 39026497, upload-time = "2025-11-18T18:21:54.634Z" }, +] + [[package]] name = "openai" version = "2.13.0" @@ -2947,6 +2975,7 @@ pydantic = [ [package.dev-dependencies] dev = [ + { name = "basedpyright" }, { name = "cibuildwheel" }, { name = "googleapis-common-protos" }, { name = "grpcio-tools" }, @@ -2989,6 +3018,7 @@ provides-extras = ["grpc", "opentelemetry", "pydantic", "openai-agents"] [package.metadata.requires-dev] dev = [ + { name = "basedpyright", specifier = "==1.34.0" }, { name = "cibuildwheel", specifier = ">=2.22.0,<3" }, { name = "googleapis-common-protos", specifier = "==1.70.0" }, { name = "grpcio-tools", specifier = ">=1.48.2,<2" },