diff --git a/pyproject.toml b/pyproject.toml index 507eb9d58..c7449d2d0 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" @@ -198,10 +200,12 @@ reportUnknownVariableType = "none" reportUnnecessaryIsInstance = "none" reportUnnecessaryTypeIgnoreComment = "none" reportUnusedCallResult = "none" +reportUnknownLambdaType = "none" include = ["temporalio", "tests"] exclude = [ "temporalio/api", "temporalio/bridge/proto", + "temporalio/bridge/_visitor.py", "tests/worker/workflow_sandbox/testmodules/proto", "temporalio/bridge/worker.py", "temporalio/worker/_replayer.py", 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 5d7857161..12d64bb77 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/client.py b/temporalio/client.py index db912e122..f0a495047 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 @@ -1335,8 +1330,8 @@ async def create_schedule( | ( temporalio.common.TypedSearchAttributes | temporalio.common.SearchAttributes ) = None, - static_summary: str | None = None, - static_details: str | None = None, + static_summary: str | None = None, # type:ignore[reportUnusedParameter] # https://github.com/temporalio/sdk-python/issues/1238 + static_details: str | None = None, # type:ignore[reportUnusedParameter] rpc_metadata: Mapping[str, str | bytes] = {}, rpc_timeout: timedelta | None = None, ) -> ScheduleHandle: @@ -3405,7 +3400,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: @@ -4156,7 +4151,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 @@ -6040,9 +6035,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()) @@ -6138,7 +6133,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( @@ -6186,7 +6181,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 @@ -6307,7 +6302,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 810f5851e..641a5e7b7 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 a8065d207..eeec62799 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 e4738e274..2819a2d7b 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 ( @@ -201,7 +201,7 @@ def nexus_operation_as_tool( >>> # Use tool with an OpenAI agent """ - def operation_callable(input): + def operation_callable(_input: Any): raise NotImplementedError("This function definition is used as a type only") operation_callable.__annotations__ = { @@ -212,7 +212,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/opentelemetry.py b/temporalio/contrib/opentelemetry.py index b1a0d6a06..25d263495 100644 --- a/temporalio/contrib/opentelemetry.py +++ b/temporalio/contrib/opentelemetry.py @@ -7,10 +7,7 @@ from dataclasses import dataclass from typing import ( Any, - Dict, NoReturn, - Optional, - Type, TypeAlias, cast, ) 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..e084f38bd 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,7 +1517,7 @@ 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 @@ -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/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 79e35c95c..432edd32b 100644 --- a/temporalio/nexus/_operation_context.py +++ b/temporalio/nexus/_operation_context.py @@ -18,8 +18,6 @@ TYPE_CHECKING, Any, Concatenate, - Optional, - Union, overload, ) @@ -120,7 +118,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 843aa50d3..c241677eb 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 acd9f17df..2cdcf16a6 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 @@ -30,6 +28,7 @@ def __init__( ) -> None: self._default_runtime: Runtime | None = None self._prevent_default = False + self._default_created = False def default(self) -> Runtime: if not self._default_runtime: diff --git a/temporalio/service.py b/temporalio/service.py index bde62e429..71c309ea7 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.20.0" @@ -379,7 +380,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 1d7b2558e..e8e600dc3 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, @@ -52,7 +53,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 c8d84e861..d6afdc759 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 75afa090e..b5764531e 100644 --- a/temporalio/worker/_nexus.py +++ b/temporalio/worker/_nexus.py @@ -11,9 +11,6 @@ from typing import ( Any, NoReturn, - Optional, - Type, - Union, ) import google.protobuf.json_format @@ -31,6 +28,7 @@ import temporalio.common import temporalio.converter import temporalio.nexus +from temporalio.bridge.worker import PollShutdownError from temporalio.exceptions import ( ApplicationError, WorkflowAlreadyStartedError, @@ -53,7 +51,7 @@ def cancel(self, reason: str): self.task.cancel() -class _NexusWorker: +class _NexusWorker: # type:ignore[reportUnusedClass] def __init__( self, *, @@ -149,7 +147,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 @@ -167,7 +165,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 @@ -442,14 +440,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/_tuning.py b/temporalio/worker/_tuning.py index 4843fee98..644f07aab 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/_workflow.py b/temporalio/worker/_workflow.py index b5aa57fc2..468605ed1 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, *, @@ -186,7 +176,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 +214,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/_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/_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/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/contrib/openai_agents/test_openai.py b/tests/contrib/openai_agents/test_openai.py index 381a213cd..327d71120 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: """ Get the weather for a given city in a country. """ @@ -224,7 +213,7 @@ 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, input: WeatherInput ) -> Weather: return Weather( city=input.city, temperature_range="14-20C", conditions="Sunny with wind." @@ -429,7 +418,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: """ Get the weather for a given city. """ @@ -468,7 +457,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 +927,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 +1155,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 +1273,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 +1405,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 +1440,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 +1506,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 +1522,7 @@ def stream_response( output_schema: AgentOutputSchemaBase | None, handoffs: list[Handoff], tracing: ModelTracing, - **kwargs, + **kwargs, # type:ignore[reportMissingParameterType] ) -> AsyncIterator[TResponseStreamEvent]: raise NotImplementedError() @@ -1606,40 +1595,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,11 +1640,11 @@ 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 @@ -1766,7 +1721,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 +1795,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 +1819,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 +2054,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 +2079,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 +2115,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"' @@ -2477,7 +2432,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 +2440,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 +2579,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/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 b065dc903..c09c6999d 100644 --- a/tests/nexus/test_workflow_caller.py +++ b/tests/nexus/test_workflow_caller.py @@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable from dataclasses import dataclass from enum import IntEnum -from typing import Any, Union +from typing import Any import nexusrpc import nexusrpc.handler @@ -80,7 +80,7 @@ class AsyncResponse: # The order of the two types in this union is critical since the data converter matches # eagerly, ignoring unknown fields, and so would identify an AsyncResponse as a # SyncResponse if SyncResponse came first. -ResponseType = Union[AsyncResponse, SyncResponse] +ResponseType = AsyncResponse | SyncResponse # ----------------------------------------------------------------------------- # Service interface @@ -179,7 +179,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: @@ -234,10 +234,10 @@ class CallerWorkflow: def __init__( self, input: CallerWfInput, - request_cancel: bool, + _request_cancel: bool, task_queue: str, ) -> None: - self.nexus_client: workflow.NexusClient[ServiceInterface] = ( + self.nexus_client: workflow.NexusClient[ServiceInterface] = ( # type:ignore[reportAttributeAccessIssue] workflow.create_nexus_client( service={ CallerReference.IMPL_WITH_INTERFACE: ServiceImpl, @@ -254,7 +254,7 @@ async def run( self, input: CallerWfInput, request_cancel: bool, - task_queue: str, + _task_queue: str, ) -> CallerWfOutput: op_input = input.op_input try: @@ -375,7 +375,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: @@ -750,7 +750,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, @@ -823,7 +823,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__) @@ -832,7 +832,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__) @@ -841,7 +841,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__) @@ -850,7 +850,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__) @@ -994,7 +994,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, @@ -1015,7 +1015,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), @@ -1059,7 +1059,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 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_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_workflow.py b/tests/test_workflow.py index becb0d111..c2ea21005 100644 --- a/tests/test_workflow.py +++ b/tests/test_workflow.py @@ -1,7 +1,7 @@ import inspect import itertools from collections.abc import Callable, Sequence -from typing import Any, Set, Type, get_type_hints +from typing import Any, get_type_hints import pytest @@ -11,7 +11,7 @@ class GoodDefnBase: @workflow.run - async def run(self, name: str) -> str: + async def run(self, _name: str) -> str: raise NotImplementedError @workflow.signal @@ -30,7 +30,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 @@ -42,7 +42,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 @@ -54,7 +54,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 @@ -66,7 +66,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 @@ -138,7 +138,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 @@ -183,11 +183,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 @@ -203,11 +203,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 @@ -215,11 +215,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 @@ -271,7 +271,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 @@ -387,31 +387,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 @@ -447,12 +447,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 @@ -474,7 +474,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_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 7746dce2d..602503c6c 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 pytest @@ -201,7 +201,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 668eabb12..d1d663562 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, @@ -1195,7 +1188,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 @@ -1530,7 +1523,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()) @@ -1995,7 +1988,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 @@ -5163,7 +5156,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 @@ -5183,7 +5176,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 @@ -5276,7 +5269,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 @@ -5635,13 +5628,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) @@ -5696,12 +5689,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) @@ -5999,7 +5992,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, @@ -7529,7 +7521,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") @@ -8299,7 +8291,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", @@ -8340,7 +8332,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: @@ -8379,7 +8370,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) @@ -8390,7 +8381,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", @@ -8440,7 +8431,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_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..b5c7e9476 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 @@ -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 6ac333e4b..7668cd0a7 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 = "1.109.1" @@ -2993,6 +3021,7 @@ pydantic = [ [package.dev-dependencies] dev = [ + { name = "basedpyright" }, { name = "cibuildwheel" }, { name = "googleapis-common-protos" }, { name = "grpcio-tools" }, @@ -3035,6 +3064,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" },