diff --git a/docs/graph.md b/docs/graph.md index 9bbe3bb011..1a84e58408 100644 --- a/docs/graph.md +++ b/docs/graph.md @@ -379,7 +379,7 @@ class Email: @dataclass class State: user: User - write_agent_messages: list[ModelMessage] = field(default_factory=list) + write_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) email_writer_agent = Agent( @@ -669,8 +669,8 @@ ask_agent = Agent('openai:gpt-5', output_type=str, instrument=True) @dataclass class QuestionState: question: str | None = None - ask_agent_messages: list[ModelMessage] = field(default_factory=list) - evaluate_agent_messages: list[ModelMessage] = field(default_factory=list) + ask_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) + evaluate_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) @dataclass @@ -912,8 +912,8 @@ ask_agent = Agent('openai:gpt-5', output_type=str, instrument=True) @dataclass class QuestionState: question: str | None = None - ask_agent_messages: list[ModelMessage] = field(default_factory=list) - evaluate_agent_messages: list[ModelMessage] = field(default_factory=list) + ask_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) + evaluate_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) @dataclass diff --git a/examples/pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py b/examples/pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py index 45ac25ded8..4d8a11f73f 100644 --- a/examples/pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py +++ b/examples/pydantic_ai_examples/ag_ui/api/agentic_generative_ui.py @@ -27,7 +27,9 @@ class Step(BaseModel): class Plan(BaseModel): """Represents a plan with multiple steps.""" - steps: list[Step] = Field(default_factory=list, description='The steps in the plan') + steps: list[Step] = Field( + default_factory=list[Step], description='The steps in the plan' + ) class JSONPatchOp(BaseModel): diff --git a/examples/pydantic_ai_examples/ag_ui/api/shared_state.py b/examples/pydantic_ai_examples/ag_ui/api/shared_state.py index 5318fd63ee..2d0ee5ff29 100644 --- a/examples/pydantic_ai_examples/ag_ui/api/shared_state.py +++ b/examples/pydantic_ai_examples/ag_ui/api/shared_state.py @@ -62,18 +62,18 @@ class Recipe(BaseModel): description='The skill level required for the recipe', ) special_preferences: list[SpecialPreferences] = Field( - default_factory=list, + default_factory=list[SpecialPreferences], description='Any special preferences for the recipe', ) cooking_time: CookingTime = Field( default=CookingTime.FIVE_MIN, description='The cooking time of the recipe' ) ingredients: list[Ingredient] = Field( - default_factory=list, + default_factory=list[Ingredient], description='Ingredients for the recipe', ) instructions: list[str] = Field( - default_factory=list, description='Instructions for the recipe' + default_factory=list[str], description='Instructions for the recipe' ) diff --git a/examples/pydantic_ai_examples/data_analyst.py b/examples/pydantic_ai_examples/data_analyst.py index b845e5a65c..39f7e0d411 100644 --- a/examples/pydantic_ai_examples/data_analyst.py +++ b/examples/pydantic_ai_examples/data_analyst.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field +from typing import cast import datasets import duckdb @@ -9,7 +10,7 @@ @dataclass class AnalystAgentDeps: - output: dict[str, pd.DataFrame] = field(default_factory=dict) + output: dict[str, pd.DataFrame] = field(default_factory=dict[str, pd.DataFrame]) def store(self, value: pd.DataFrame) -> str: """Store the output in deps and return the reference such as Out[1] to be used by the LLM.""" @@ -47,7 +48,7 @@ def load_dataset( """ # begin load data from hf builder = datasets.load_dataset_builder(path) # pyright: ignore[reportUnknownMemberType] - splits: dict[str, datasets.SplitInfo] = builder.info.splits or {} # pyright: ignore[reportUnknownMemberType] + splits = cast(dict[str, datasets.SplitInfo], builder.info.splits or {}) # pyright: ignore[reportUnknownMemberType] if split not in splits: raise ModelRetry( f'{split} is not valid for dataset {path}. Valid splits are {",".join(splits.keys())}' diff --git a/examples/pydantic_ai_examples/question_graph.py b/examples/pydantic_ai_examples/question_graph.py index e1170d0ce6..bd63c4721a 100644 --- a/examples/pydantic_ai_examples/question_graph.py +++ b/examples/pydantic_ai_examples/question_graph.py @@ -32,8 +32,10 @@ @dataclass class QuestionState: question: str | None = None - ask_agent_messages: list[ModelMessage] = field(default_factory=list) - evaluate_agent_messages: list[ModelMessage] = field(default_factory=list) + ask_agent_messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) + evaluate_agent_messages: list[ModelMessage] = field( + default_factory=list[ModelMessage] + ) @dataclass diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index 043c27c4f5..5256ffd62d 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -90,7 +90,7 @@ class GraphAgentState: """State kept across the execution of the agent graph.""" - message_history: list[_messages.ModelMessage] = dataclasses.field(default_factory=list) + message_history: list[_messages.ModelMessage] = dataclasses.field(default_factory=list[_messages.ModelMessage]) usage: _usage.RunUsage = dataclasses.field(default_factory=_usage.RunUsage) retries: int = 0 run_step: int = 0 @@ -190,12 +190,16 @@ class UserPromptNode(AgentNode[DepsT, NodeRunEndT]): deferred_tool_results: DeferredToolResults | None = None instructions: str | None = None - instructions_functions: list[_system_prompt.SystemPromptRunner[DepsT]] = dataclasses.field(default_factory=list) + instructions_functions: list[_system_prompt.SystemPromptRunner[DepsT]] = dataclasses.field( + default_factory=list[_system_prompt.SystemPromptRunner[DepsT]] + ) system_prompts: tuple[str, ...] = dataclasses.field(default_factory=tuple) - system_prompt_functions: list[_system_prompt.SystemPromptRunner[DepsT]] = dataclasses.field(default_factory=list) + system_prompt_functions: list[_system_prompt.SystemPromptRunner[DepsT]] = dataclasses.field( + default_factory=list[_system_prompt.SystemPromptRunner[DepsT]] + ) system_prompt_dynamic_functions: dict[str, _system_prompt.SystemPromptRunner[DepsT]] = dataclasses.field( - default_factory=dict + default_factory=dict[str, _system_prompt.SystemPromptRunner[DepsT]] ) async def run( # noqa: C901 @@ -1080,10 +1084,18 @@ async def handle_call_or_result( pending = tasks while pending: + pending = cast( + list[ + Task[ + tuple[_messages.ToolReturnPart | _messages.RetryPromptPart, _messages.UserPromptPart | None] + ] + ], + pending, + ) done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED) for task in done: - index = tasks.index(task) - if event := await handle_call_or_result(coro_or_task=task, index=index): + index = tasks.index(task) # pyright: ignore[reportArgumentType] + if event := await handle_call_or_result(coro_or_task=task, index=index): # pyright: ignore[reportArgumentType] yield event # We append the results at the end, rather than as they are received, to retain a consistent ordering @@ -1296,8 +1308,7 @@ async def _process_message_history( if takes_ctx: messages = await processor(run_context, messages) else: - async_processor = cast(_HistoryProcessorAsync, processor) - messages = await async_processor(messages) + messages = await processor(messages) else: if takes_ctx: sync_processor_with_ctx = cast(_HistoryProcessorSyncWithCtx[DepsT], processor) diff --git a/pydantic_ai_slim/pydantic_ai/_function_schema.py b/pydantic_ai_slim/pydantic_ai/_function_schema.py index 2b8270f322..23c9bbdf4b 100644 --- a/pydantic_ai_slim/pydantic_ai/_function_schema.py +++ b/pydantic_ai_slim/pydantic_ai/_function_schema.py @@ -42,7 +42,7 @@ class FunctionSchema: takes_ctx: bool is_async: bool single_arg_name: str | None = None - positional_fields: list[str] = field(default_factory=list) + positional_fields: list[str] = field(default_factory=list[str]) var_positional_field: str | None = None async def call(self, args_dict: dict[str, Any], ctx: RunContext[Any]) -> Any: diff --git a/pydantic_ai_slim/pydantic_ai/_output.py b/pydantic_ai_slim/pydantic_ai/_output.py index e3adfbd190..e3c87dd60c 100644 --- a/pydantic_ai_slim/pydantic_ai/_output.py +++ b/pydantic_ai_slim/pydantic_ai/_output.py @@ -248,11 +248,11 @@ def build( # noqa: C901 if allows_image: outputs = [output for output in outputs if output is not _messages.BinaryImage] - if output := next((output for output in outputs if isinstance(output, NativeOutput)), None): + if output := next((output for output in outputs if isinstance(output, NativeOutput)), None): # pyright: ignore[reportUnknownVariableType,reportUnknownArgumentType] if len(outputs) > 1: raise UserError('`NativeOutput` must be the only output type.') # pragma: no cover - flattened_outputs = _flatten_output_spec(output.outputs) + flattened_outputs = _flatten_output_spec(output.outputs) # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType] if DeferredToolRequests in flattened_outputs: raise UserError( # pragma: no cover @@ -273,11 +273,11 @@ def build( # noqa: C901 allows_deferred_tools=allows_deferred_tools, allows_image=allows_image, ) - elif output := next((output for output in outputs if isinstance(output, PromptedOutput)), None): + elif output := next((output for output in outputs if isinstance(output, PromptedOutput)), None): # pyright: ignore[reportUnknownVariableType,reportUnknownArgumentType] if len(outputs) > 1: raise UserError('`PromptedOutput` must be the only output type.') # pragma: no cover - flattened_outputs = _flatten_output_spec(output.outputs) + flattened_outputs = _flatten_output_spec(output.outputs) # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType] if DeferredToolRequests in flattened_outputs: raise UserError( # pragma: no cover @@ -306,9 +306,9 @@ def build( # noqa: C901 if output is str: text_outputs.append(cast(type[str], output)) elif isinstance(output, TextOutput): - text_outputs.append(output) + text_outputs.append(cast(TextOutput[OutputDataT], output)) elif isinstance(output, ToolOutput): - tool_outputs.append(output) + tool_outputs.append(cast(ToolOutput[OutputDataT], output)) elif isinstance(output, NativeOutput): # We can never get here because this is checked for above. raise UserError('`NativeOutput` must be the only output type.') # pragma: no cover @@ -900,6 +900,7 @@ def build( description = None strict = None if isinstance(output, ToolOutput): + output = cast(ToolOutput[OutputDataT], output) # do we need to error on conflicts here? (DavidM): If this is internal maybe doesn't matter, if public, use overloads name = output.name description = output.description @@ -999,7 +1000,7 @@ def _flatten_output_spec(output_spec: OutputSpec[T]) -> Sequence[_OutputSpecItem def _flatten_output_spec(output_spec: OutputSpec[T]) -> Sequence[_OutputSpecItem[T]]: outputs: Sequence[OutputSpec[T]] if isinstance(output_spec, Sequence): - outputs = output_spec + outputs = cast(Sequence[OutputSpec[T]], output_spec) else: outputs = (output_spec,) diff --git a/pydantic_ai_slim/pydantic_ai/_parts_manager.py b/pydantic_ai_slim/pydantic_ai/_parts_manager.py index 5dfc53630d..a893b02da3 100644 --- a/pydantic_ai_slim/pydantic_ai/_parts_manager.py +++ b/pydantic_ai_slim/pydantic_ai/_parts_manager.py @@ -57,9 +57,9 @@ class ModelResponsePartsManager: Parts are generally added and/or updated by providing deltas, which are tracked by vendor-specific IDs. """ - _parts: list[ManagedPart] = field(default_factory=list, init=False) + _parts: list[ManagedPart] = field(default_factory=list[ManagedPart], init=False) """A list of parts (text or tool calls) that make up the current state of the model's response.""" - _vendor_id_to_part_index: dict[VendorId, int] = field(default_factory=dict, init=False) + _vendor_id_to_part_index: dict[VendorId, int] = field(default_factory=dict[VendorId, int], init=False) """Maps a vendor's "part" ID (if provided) to the index in `_parts` where that part resides.""" def get_parts(self) -> list[ModelResponsePart]: diff --git a/pydantic_ai_slim/pydantic_ai/_run_context.py b/pydantic_ai_slim/pydantic_ai/_run_context.py index b605bd8b54..d0de675687 100644 --- a/pydantic_ai_slim/pydantic_ai/_run_context.py +++ b/pydantic_ai_slim/pydantic_ai/_run_context.py @@ -36,7 +36,7 @@ class RunContext(Generic[RunContextAgentDepsT]): """LLM usage associated with the run.""" prompt: str | Sequence[_messages.UserContent] | None = None """The original user prompt passed to the run.""" - messages: list[_messages.ModelMessage] = field(default_factory=list) + messages: list[_messages.ModelMessage] = field(default_factory=list[_messages.ModelMessage]) """Messages exchanged in the conversation so far.""" validation_context: Any = None """Pydantic [validation context](https://docs.pydantic.dev/latest/concepts/validators/#validation-context) for tool args and run outputs.""" @@ -46,7 +46,7 @@ class RunContext(Generic[RunContextAgentDepsT]): """Whether to include the content of the messages in the trace.""" instrumentation_version: int = DEFAULT_INSTRUMENTATION_VERSION """Instrumentation settings version, if instrumentation is enabled.""" - retries: dict[str, int] = field(default_factory=dict) + retries: dict[str, int] = field(default_factory=dict[str, int]) """Number of retries for each tool so far.""" tool_call_id: str | None = None """The ID of the tool call.""" diff --git a/pydantic_ai_slim/pydantic_ai/_tool_manager.py b/pydantic_ai_slim/pydantic_ai/_tool_manager.py index 9a9f93e1ff..4ff158b0f1 100644 --- a/pydantic_ai_slim/pydantic_ai/_tool_manager.py +++ b/pydantic_ai_slim/pydantic_ai/_tool_manager.py @@ -33,7 +33,7 @@ class ToolManager(Generic[AgentDepsT]): """The agent run context for a specific run step.""" tools: dict[str, ToolsetTool[AgentDepsT]] | None = None """The cached tools for this run step.""" - failed_tools: set[str] = field(default_factory=set) + failed_tools: set[str] = field(default_factory=set[str]) """Names of tools that failed in this run step.""" @classmethod diff --git a/pydantic_ai_slim/pydantic_ai/_utils.py b/pydantic_ai_slim/pydantic_ai/_utils.py index 97230bb046..41ffe938c2 100644 --- a/pydantic_ai_slim/pydantic_ai/_utils.py +++ b/pydantic_ai_slim/pydantic_ai/_utils.py @@ -12,7 +12,7 @@ from datetime import datetime, timezone from functools import partial from types import GenericAlias -from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeGuard, TypeVar, get_args, get_origin, overload +from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeGuard, TypeVar, cast, get_args, get_origin, overload from anyio.to_thread import run_sync from pydantic import BaseModel, TypeAdapter @@ -184,7 +184,7 @@ async def async_iter_groups() -> AsyncIterator[list[T]]: if task is None: # anext(aiter) returns an Awaitable[T], not a Coroutine which asyncio.create_task expects # so far, this doesn't seem to be a problem - task = asyncio.create_task(anext(aiterator)) # pyright: ignore[reportArgumentType] + task = asyncio.create_task(anext(aiterator)) # pyright: ignore[reportArgumentType,reportUnknownVariableType] # we use asyncio.wait to avoid cancelling the coroutine if it's not done done, _ = await asyncio.wait((task,), timeout=wait_time) @@ -375,7 +375,7 @@ def is_async_callable(obj: Any) -> Any: while isinstance(obj, functools.partial): obj = obj.func - return inspect.iscoroutinefunction(obj) or (callable(obj) and inspect.iscoroutinefunction(obj.__call__)) # type: ignore + return inspect.iscoroutinefunction(obj) or (callable(obj) and inspect.iscoroutinefunction(obj.__call__)) def _update_mapped_json_schema_refs(s: dict[str, Any], name_mapping: dict[str, str]) -> None: @@ -395,7 +395,7 @@ def _update_mapped_json_schema_refs(s: dict[str, Any], name_mapping: dict[str, s # Handle arrays if 'items' in s and isinstance(s['items'], dict): - items: dict[str, Any] = s['items'] + items = cast(dict[str, Any], s['items']) _update_mapped_json_schema_refs(items, name_mapping) if 'prefixItems' in s: prefix_items: list[dict[str, Any]] = s['prefixItems'] diff --git a/pydantic_ai_slim/pydantic_ai/direct.py b/pydantic_ai_slim/pydantic_ai/direct.py index eac647f2e4..0cfe220d3d 100644 --- a/pydantic_ai_slim/pydantic_ai/direct.py +++ b/pydantic_ai_slim/pydantic_ai/direct.py @@ -288,7 +288,7 @@ class StreamedResponseSync: _async_stream_cm: AbstractAsyncContextManager[StreamedResponse] _queue: queue.Queue[messages.ModelResponseStreamEvent | Exception | None] = field( - default_factory=queue.Queue, init=False + default_factory=queue.Queue[messages.ModelResponseStreamEvent | Exception | None], init=False ) _thread: threading.Thread | None = field(default=None, init=False) _stream_response: StreamedResponse | None = field(default=None, init=False) diff --git a/pydantic_ai_slim/pydantic_ai/format_prompt.py b/pydantic_ai_slim/pydantic_ai/format_prompt.py index 5e91b83c7c..c45c922753 100644 --- a/pydantic_ai_slim/pydantic_ai/format_prompt.py +++ b/pydantic_ai_slim/pydantic_ai/format_prompt.py @@ -82,11 +82,13 @@ class _ToXml: include_field_info: Literal['once'] | bool # a map of Pydantic and dataclasses Field paths to their metadata: # a field unique string representation and its class - _fields_info: dict[str, tuple[str, FieldInfo | ComputedFieldInfo]] = field(default_factory=dict) + _fields_info: dict[str, tuple[str, FieldInfo | ComputedFieldInfo]] = field( + default_factory=dict[str, tuple[str, FieldInfo | ComputedFieldInfo]] + ) # keep track of fields we have extracted attributes from - _included_fields: set[str] = field(default_factory=set) + _included_fields: set[str] = field(default_factory=set[str]) # keep track of class names for dataclasses and Pydantic models, that occur in lists - _element_names: dict[str, str] = field(default_factory=dict) + _element_names: dict[str, str] = field(default_factory=dict[str, str]) # flag for parsing dataclasses and Pydantic models once _is_info_extracted: bool = False _FIELD_ATTRIBUTES = ('title', 'description') diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 53b6734d34..d0e959e4a2 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -14,7 +14,7 @@ import pydantic import pydantic_core from genai_prices import calc_price, types as genai_types -from opentelemetry._events import Event # pyright: ignore[reportPrivateImportUsage] +from opentelemetry._events import Event from typing_extensions import deprecated from . import _otel_messages, _utils diff --git a/pydantic_ai_slim/pydantic_ai/models/__init__.py b/pydantic_ai_slim/pydantic_ai/models/__init__.py index aef137cc29..da354f2a01 100644 --- a/pydantic_ai_slim/pydantic_ai/models/__init__.py +++ b/pydantic_ai_slim/pydantic_ai/models/__init__.py @@ -522,12 +522,12 @@ class ModelRequestParameters: """Configuration for an agent's request to a model, specifically related to tools and output handling.""" - function_tools: list[ToolDefinition] = field(default_factory=list) - builtin_tools: list[AbstractBuiltinTool] = field(default_factory=list) + function_tools: list[ToolDefinition] = field(default_factory=list[ToolDefinition]) + builtin_tools: list[AbstractBuiltinTool] = field(default_factory=list[AbstractBuiltinTool]) output_mode: OutputMode = 'text' output_object: OutputObjectDefinition | None = None - output_tools: list[ToolDefinition] = field(default_factory=list) + output_tools: list[ToolDefinition] = field(default_factory=list[ToolDefinition]) prompted_output_template: str | None = None allow_text_output: bool = True allow_image_output: bool = False diff --git a/pydantic_ai_slim/pydantic_ai/models/fallback.py b/pydantic_ai_slim/pydantic_ai/models/fallback.py index 67151a07b9..d61d00e1b5 100644 --- a/pydantic_ai_slim/pydantic_ai/models/fallback.py +++ b/pydantic_ai_slim/pydantic_ai/models/fallback.py @@ -4,7 +4,7 @@ from contextlib import AsyncExitStack, asynccontextmanager, suppress from dataclasses import dataclass, field from functools import cached_property -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast from opentelemetry.trace import get_current_span @@ -49,6 +49,7 @@ def __init__( self.models = [infer_model(default_model), *[infer_model(m) for m in fallback_models]] if isinstance(fallback_on, tuple): + fallback_on = cast(tuple[type[Exception], ...], fallback_on) self._fallback_on = _default_fallback_condition_factory(fallback_on) else: self._fallback_on = fallback_on diff --git a/pydantic_ai_slim/pydantic_ai/models/instrumented.py b/pydantic_ai_slim/pydantic_ai/models/instrumented.py index c3900896b5..77d8d0d1ca 100644 --- a/pydantic_ai_slim/pydantic_ai/models/instrumented.py +++ b/pydantic_ai_slim/pydantic_ai/models/instrumented.py @@ -11,10 +11,10 @@ from genai_prices.types import PriceCalculation from opentelemetry._events import ( - Event, # pyright: ignore[reportPrivateImportUsage] - EventLogger, # pyright: ignore[reportPrivateImportUsage] - EventLoggerProvider, # pyright: ignore[reportPrivateImportUsage] - get_event_logger_provider, # pyright: ignore[reportPrivateImportUsage] + Event, + EventLogger, + EventLoggerProvider, + get_event_logger_provider, ) from opentelemetry.metrics import MeterProvider, get_meter_provider from opentelemetry.trace import Span, Tracer, TracerProvider, get_tracer_provider diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 61c8df132b..1ed69ab487 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -780,9 +780,11 @@ class _MapModelResponseContext: _model: OpenAIChatModel - texts: list[str] = field(default_factory=list) - thinkings: list[str] = field(default_factory=list) - tool_calls: list[ChatCompletionMessageFunctionToolCallParam] = field(default_factory=list) + texts: list[str] = field(default_factory=list[str]) + thinkings: list[str] = field(default_factory=list[str]) + tool_calls: list[ChatCompletionMessageFunctionToolCallParam] = field( + default_factory=list[ChatCompletionMessageFunctionToolCallParam] + ) def map_assistant_message(self, message: ModelResponse) -> chat.ChatCompletionAssistantMessageParam: for item in message.parts: @@ -1746,7 +1748,7 @@ async def _map_messages( # noqa: C901 item.tool_name == CodeExecutionTool.kind and code_interpreter_item is not None and isinstance(item.content, dict) - and (content := cast(dict[str, Any], item.content)) # pyright: ignore[reportUnknownMemberType] + and (content := cast(dict[str, Any], item.content)) and (status := content.get('status')) ): code_interpreter_item['status'] = status @@ -1754,7 +1756,7 @@ async def _map_messages( # noqa: C901 item.tool_name == WebSearchTool.kind and web_search_item is not None and isinstance(item.content, dict) # pyright: ignore[reportUnknownMemberType] - and (content := cast(dict[str, Any], item.content)) # pyright: ignore[reportUnknownMemberType] + and (content := cast(dict[str, Any], item.content)) and (status := content.get('status')) ): web_search_item['status'] = status diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index 7ac019d43c..e28d93495b 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -574,7 +574,7 @@ def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, @dataclass class _MapModelResponseContext(OpenAIChatModel._MapModelResponseContext): # type: ignore[reportPrivateUsage] - reasoning_details: list[dict[str, Any]] = field(default_factory=list) + reasoning_details: list[dict[str, Any]] = field(default_factory=list[dict[str, Any]]) def _into_message_param(self) -> chat.ChatCompletionAssistantMessageParam: message_param = super()._into_message_param() diff --git a/pydantic_ai_slim/pydantic_ai/models/outlines.py b/pydantic_ai_slim/pydantic_ai/models/outlines.py index 4791cbacd5..29abb91516 100644 --- a/pydantic_ai_slim/pydantic_ai/models/outlines.py +++ b/pydantic_ai_slim/pydantic_ai/models/outlines.py @@ -2,6 +2,11 @@ # environment to be able to run the associated tests # pyright: reportUnnecessaryTypeIgnoreComment = false +# pyright: reportMissingImports = false +# pyright: reportUnknownVariableType = false +# pyright: reportUnknownMemberType = false +# pyright: reportUnknownParameterType = false +# pyright: reportUnknownArgumentType = false from __future__ import annotations diff --git a/pydantic_ai_slim/pydantic_ai/run.py b/pydantic_ai_slim/pydantic_ai/run.py index 0ed3e2455d..c8f5241f83 100644 --- a/pydantic_ai_slim/pydantic_ai/run.py +++ b/pydantic_ai_slim/pydantic_ai/run.py @@ -186,7 +186,7 @@ def _task_to_node( if isinstance(task, Sequence) and len(task) == 1: first_task = task[0] if isinstance(first_task.inputs, BaseNode): # pragma: no branch - base_node: BaseNode[ + base_node: BaseNode[ # pyright: ignore[reportUnknownVariableType] _agent_graph.GraphAgentState, _agent_graph.GraphAgentDeps[AgentDepsT, OutputDataT], FinalResult[OutputDataT], diff --git a/pydantic_ai_slim/pydantic_ai/tools.py b/pydantic_ai_slim/pydantic_ai/tools.py index dcd860b019..ae127d60e6 100644 --- a/pydantic_ai_slim/pydantic_ai/tools.py +++ b/pydantic_ai_slim/pydantic_ai/tools.py @@ -154,11 +154,11 @@ class DeferredToolRequests: See [deferred tools docs](../deferred-tools.md#deferred-tools) for more information. """ - calls: list[ToolCallPart] = field(default_factory=list) + calls: list[ToolCallPart] = field(default_factory=list[ToolCallPart]) """Tool calls that require external execution.""" - approvals: list[ToolCallPart] = field(default_factory=list) + approvals: list[ToolCallPart] = field(default_factory=list[ToolCallPart]) """Tool calls that require human-in-the-loop approval.""" - metadata: dict[str, dict[str, Any]] = field(default_factory=dict) + metadata: dict[str, dict[str, Any]] = field(default_factory=dict[str, dict[str, Any]]) """Metadata for deferred tool calls, keyed by `tool_call_id`.""" @@ -220,9 +220,11 @@ class DeferredToolResults: See [deferred tools docs](../deferred-tools.md#deferred-tools) for more information. """ - calls: dict[str, DeferredToolCallResult | Any] = field(default_factory=dict) + calls: dict[str, DeferredToolCallResult | Any] = field(default_factory=dict[str, DeferredToolCallResult | Any]) """Map of tool call IDs to results for tool calls that required external execution.""" - approvals: dict[str, bool | DeferredToolApprovalResult] = field(default_factory=dict) + approvals: dict[str, bool | DeferredToolApprovalResult] = field( + default_factory=dict[str, bool | DeferredToolApprovalResult] + ) """Map of tool call IDs to results for tool calls that required human-in-the-loop approval.""" diff --git a/pydantic_ai_slim/pydantic_ai/toolsets/function.py b/pydantic_ai_slim/pydantic_ai/toolsets/function.py index e185ed0273..f050ae2be6 100644 --- a/pydantic_ai_slim/pydantic_ai/toolsets/function.py +++ b/pydantic_ai_slim/pydantic_ai/toolsets/function.py @@ -2,7 +2,7 @@ from collections.abc import Awaitable, Callable, Sequence from dataclasses import dataclass, replace -from typing import Any, overload +from typing import Any, cast, overload from pydantic.json_schema import GenerateJsonSchema @@ -92,6 +92,7 @@ def __init__( self.tools = {} for tool in tools: if isinstance(tool, Tool): + tool = cast(Tool[AgentDepsT], tool) self.add_tool(tool) else: self.add_function(tool) diff --git a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py index 6a2edf1715..a9a7ace936 100644 --- a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py +++ b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py @@ -9,7 +9,7 @@ class MessagesBuilder: """Helper class to build Pydantic AI messages from request/response parts.""" - messages: list[ModelMessage] = field(default_factory=list) + messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) def add(self, part: ModelRequestPart | ModelResponsePart) -> None: """Add a new part, creating a new request or response message if necessary.""" diff --git a/pydantic_ai_slim/pydantic_ai/ui/ag_ui/_event_stream.py b/pydantic_ai_slim/pydantic_ai/ui/ag_ui/_event_stream.py index 2b37d36351..377353ffa8 100644 --- a/pydantic_ai_slim/pydantic_ai/ui/ag_ui/_event_stream.py +++ b/pydantic_ai_slim/pydantic_ai/ui/ag_ui/_event_stream.py @@ -72,7 +72,7 @@ class AGUIEventStream(UIEventStream[RunAgentInput, BaseEvent, AgentDepsT, Output """UI event stream transformer for the Agent-User Interaction (AG-UI) protocol.""" _thinking_text: bool = False - _builtin_tool_call_ids: dict[str, str] = field(default_factory=dict) + _builtin_tool_call_ids: dict[str, str] = field(default_factory=dict[str, str]) _error: bool = False @property diff --git a/pydantic_ai_slim/pydantic_ai/usage.py b/pydantic_ai_slim/pydantic_ai/usage.py index 586af8dcfc..d0cfe93628 100644 --- a/pydantic_ai_slim/pydantic_ai/usage.py +++ b/pydantic_ai_slim/pydantic_ai/usage.py @@ -47,7 +47,7 @@ class UsageBase: dict[str, int], # `details` can not be `None` any longer, but we still want to support deserializing model responses stored in a DB before this was changed BeforeValidator(lambda d: d or {}), - ] = dataclasses.field(default_factory=dict) + ] = dataclasses.field(default_factory=dict[str, int]) """Any extra details returned by the model.""" @property @@ -197,7 +197,7 @@ class RunUsage(UsageBase): output_tokens: int = 0 """Total number of output/completion tokens.""" - details: dict[str, int] = dataclasses.field(default_factory=dict) + details: dict[str, int] = dataclasses.field(default_factory=dict[str, int]) """Any extra details returned by the model.""" def incr(self, incr_usage: RunUsage | RequestUsage) -> None: diff --git a/pydantic_evals/pydantic_evals/_utils.py b/pydantic_evals/pydantic_evals/_utils.py index 267045d7d1..1b5e7d821c 100644 --- a/pydantic_evals/pydantic_evals/_utils.py +++ b/pydantic_evals/pydantic_evals/_utils.py @@ -112,7 +112,7 @@ async def _run_task(tsk: Callable[[], Awaitable[T]], index: int) -> None: try: from logfire._internal.config import ( - LogfireNotConfiguredWarning, # pyright: ignore[reportAssignmentType,reportPrivateImportUsage] + LogfireNotConfiguredWarning, # pyright: ignore[reportAssignmentType] ) # TODO: Remove this `pragma: no cover` once we test evals without pydantic-ai (which includes logfire) except ImportError: # pragma: no cover diff --git a/pydantic_evals/pydantic_evals/dataset.py b/pydantic_evals/pydantic_evals/dataset.py index 4715a36c65..3669cde4ef 100644 --- a/pydantic_evals/pydantic_evals/dataset.py +++ b/pydantic_evals/pydantic_evals/dataset.py @@ -90,7 +90,7 @@ class _CaseModel(BaseModel, Generic[InputsT, OutputT, MetadataT], extra='forbid' inputs: InputsT metadata: MetadataT | None = None expected_output: OutputT | None = None - evaluators: list[EvaluatorSpec] = Field(default_factory=list) + evaluators: list[EvaluatorSpec] = Field(default_factory=list[EvaluatorSpec]) class _DatasetModel(BaseModel, Generic[InputsT, OutputT, MetadataT], extra='forbid'): @@ -100,7 +100,7 @@ class _DatasetModel(BaseModel, Generic[InputsT, OutputT, MetadataT], extra='forb json_schema_path: str | None = Field(default=None, alias='$schema') name: str | None = None cases: list[_CaseModel[InputsT, OutputT, MetadataT]] - evaluators: list[EvaluatorSpec] = Field(default_factory=list) + evaluators: list[EvaluatorSpec] = Field(default_factory=list[EvaluatorSpec]) @dataclass(init=False) @@ -136,7 +136,9 @@ class Case(Generic[InputsT, OutputT, MetadataT]): """ expected_output: OutputT | None = None """Expected output of the task. This is the expected output of the task that will be evaluated.""" - evaluators: list[Evaluator[InputsT, OutputT, MetadataT]] = field(default_factory=list) + evaluators: list[Evaluator[InputsT, OutputT, MetadataT]] = field( + default_factory=list[Evaluator[InputsT, OutputT, MetadataT]] + ) """Evaluators to be used just on this case.""" def __init__( @@ -738,8 +740,8 @@ def _make_typed_dict(cls_name_prefix: str, fields: dict[str, Any]) -> Any: class Case(BaseModel, extra='forbid'): # pyright: ignore[reportUnusedClass] # this _is_ used below, but pyright doesn't seem to notice.. name: str | None = None inputs: in_type # pyright: ignore[reportInvalidTypeForm] - metadata: meta_type | None = None # pyright: ignore[reportInvalidTypeForm,reportUnknownVariableType] - expected_output: out_type | None = None # pyright: ignore[reportInvalidTypeForm,reportUnknownVariableType] + metadata: meta_type | None = None # pyright: ignore[reportInvalidTypeForm] + expected_output: out_type | None = None # pyright: ignore[reportInvalidTypeForm] if evaluator_schema_types: # pragma: no branch evaluators: list[Union[tuple(evaluator_schema_types)]] = [] # pyright: ignore # noqa: UP007 @@ -854,8 +856,8 @@ def _get_relative_path_reference(target: Path, source: Path, _prefix: str = '') class _TaskRun: """Internal class to track metrics and attributes for a task run.""" - attributes: dict[str, Any] = field(init=False, default_factory=dict) - metrics: dict[str, int | float] = field(init=False, default_factory=dict) + attributes: dict[str, Any] = field(init=False, default_factory=dict[str, Any]) + metrics: dict[str, int | float] = field(init=False, default_factory=dict[str, int | float]) def record_metric(self, name: str, value: int | float) -> None: """Record a metric value. diff --git a/pydantic_evals/pydantic_evals/otel/span_tree.py b/pydantic_evals/pydantic_evals/otel/span_tree.py index efdc8d49b8..348870645f 100644 --- a/pydantic_evals/pydantic_evals/otel/span_tree.py +++ b/pydantic_evals/pydantic_evals/otel/span_tree.py @@ -433,8 +433,8 @@ class SpanTree: You can then search or iterate the tree to make your assertions (using DFS for traversal). """ - roots: list[SpanNode] = field(default_factory=list) - nodes_by_id: dict[str, SpanNode] = field(default_factory=dict) + roots: list[SpanNode] = field(default_factory=list[SpanNode]) + nodes_by_id: dict[str, SpanNode] = field(default_factory=dict[str, SpanNode]) # ------------------------------------------------------------------------- # Construction diff --git a/pydantic_evals/pydantic_evals/reporting/__init__.py b/pydantic_evals/pydantic_evals/reporting/__init__.py index 622e70970f..ddccaa8995 100644 --- a/pydantic_evals/pydantic_evals/reporting/__init__.py +++ b/pydantic_evals/pydantic_evals/reporting/__init__.py @@ -78,7 +78,7 @@ class ReportCase(Generic[InputsT, OutputT, MetadataT]): span_id: str | None = None """The span ID of the case span.""" - evaluator_failures: list[EvaluatorFailure] = field(default_factory=list) + evaluator_failures: list[EvaluatorFailure] = field(default_factory=list[EvaluatorFailure]) @dataclass(kw_only=True) @@ -195,7 +195,9 @@ class EvaluationReport(Generic[InputsT, OutputT, MetadataT]): cases: list[ReportCase[InputsT, OutputT, MetadataT]] """The cases in the report.""" - failures: list[ReportCaseFailure[InputsT, OutputT, MetadataT]] = field(default_factory=list) + failures: list[ReportCaseFailure[InputsT, OutputT, MetadataT]] = field( + default_factory=list[ReportCaseFailure[InputsT, OutputT, MetadataT]] + ) """The failures in the report. These are cases where task execution raised an exception.""" experiment_metadata: dict[str, Any] | None = None diff --git a/pydantic_graph/pydantic_graph/_utils.py b/pydantic_graph/pydantic_graph/_utils.py index 13a0d04ba2..5858c9bd56 100644 --- a/pydantic_graph/pydantic_graph/_utils.py +++ b/pydantic_graph/pydantic_graph/_utils.py @@ -144,7 +144,7 @@ async def run_in_executor(func: Callable[_P, _R], *args: _P.args, **kwargs: _P.k try: from logfire._internal.config import ( - LogfireNotConfiguredWarning, # pyright: ignore[reportAssignmentType,reportPrivateImportUsage] + LogfireNotConfiguredWarning, # pyright: ignore[reportAssignmentType] ) except ImportError: # pragma: lax no cover diff --git a/pydantic_graph/pydantic_graph/persistence/in_mem.py b/pydantic_graph/pydantic_graph/persistence/in_mem.py index e50506dd2a..039988cb50 100644 --- a/pydantic_graph/pydantic_graph/persistence/in_mem.py +++ b/pydantic_graph/pydantic_graph/persistence/in_mem.py @@ -92,7 +92,7 @@ class FullStatePersistence(BaseStatePersistence[StateT, RunEndT]): Defaults to `True` so even if nodes or state are modified after the snapshot is taken, the persistence history will record the value at the time of the snapshot. """ - history: list[Snapshot[StateT, RunEndT]] = field(default_factory=list) + history: list[Snapshot[StateT, RunEndT]] = field(default_factory=list[Snapshot[StateT, RunEndT]]) """List of snapshots taken during the graph run.""" _snapshots_type_adapter: pydantic.TypeAdapter[list[Snapshot[StateT, RunEndT]]] | None = field( default=None, init=False, repr=False diff --git a/pyproject.toml b/pyproject.toml index 4e716ee61f..fb66a2fa7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,7 +112,7 @@ dev = [ "genai-prices>=0.0.28", "mcp-run-python>=0.0.20", ] -lint = ["mypy>=1.11.2", "pyright>=1.1.390", "ruff>=0.6.9"] +lint = ["mypy>=1.11.2", "pyright>=1.1.407", "ruff>=0.14.8"] docs = [ "pydantic-ai[a2a]", "black>=24.10.0", diff --git a/tests/conftest.py b/tests/conftest.py index 32b4a475cc..1ae0910d13 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -538,8 +538,13 @@ def model( provider=HuggingFaceProvider(provider_name='nebius', api_key=huggingface_api_key), ) elif request.param == 'outlines': - from outlines.models.transformers import from_transformers - from transformers import AutoModelForCausalLM, AutoTokenizer + from outlines.models.transformers import ( + from_transformers, + ) + from transformers import ( + AutoModelForCausalLM, + AutoTokenizer, + ) from pydantic_ai.models.outlines import OutlinesModel diff --git a/tests/evals/test_evaluator_base.py b/tests/evals/test_evaluator_base.py index 6778ca648c..c335dc2477 100644 --- a/tests/evals/test_evaluator_base.py +++ b/tests/evals/test_evaluator_base.py @@ -189,7 +189,7 @@ class ExampleEvaluator(Evaluator[Any, Any, Any]): value: int = 42 optional: str | None = None default_value: bool = False - default_factory_value: list[int] = field(default_factory=list) + default_factory_value: list[int] = field(default_factory=list[int]) def evaluate(self, ctx: EvaluatorContext) -> bool: raise NotImplementedError diff --git a/tests/example_modules/fake_database.py b/tests/example_modules/fake_database.py index e15a5787e6..f6b8ef66db 100644 --- a/tests/example_modules/fake_database.py +++ b/tests/example_modules/fake_database.py @@ -13,7 +13,7 @@ def get(self, name: str) -> int | None: @dataclass class DatabaseConn: users: FakeTable = field(default_factory=FakeTable) - _forecasts: dict[int, str] = field(default_factory=dict) + _forecasts: dict[int, str] = field(default_factory=dict[int, str]) async def execute(self, query: str) -> list[dict[str, Any]]: return [{'id': 123, 'name': 'John Doe'}] diff --git a/tests/graph/beta/test_broadcast_and_spread.py b/tests/graph/beta/test_broadcast_and_spread.py index 291929e388..bf5f2dcf54 100644 --- a/tests/graph/beta/test_broadcast_and_spread.py +++ b/tests/graph/beta/test_broadcast_and_spread.py @@ -14,7 +14,7 @@ @dataclass class CounterState: - values: list[int] = field(default_factory=list) + values: list[int] = field(default_factory=list[int]) async def test_broadcast_to_multiple_steps(): diff --git a/tests/graph/beta/test_edge_cases.py b/tests/graph/beta/test_edge_cases.py index 1209c0ae81..8716c43daf 100644 --- a/tests/graph/beta/test_edge_cases.py +++ b/tests/graph/beta/test_edge_cases.py @@ -315,7 +315,7 @@ async def test_state_with_mutable_collections(): @dataclass class MutableState: - items: list[int] = field(default_factory=list) + items: list[int] = field(default_factory=list[int]) g = GraphBuilder(state_type=MutableState, output_type=list[int]) diff --git a/tests/graph/beta/test_graph_execution.py b/tests/graph/beta/test_graph_execution.py index d6911eaa79..2a26ed659a 100644 --- a/tests/graph/beta/test_graph_execution.py +++ b/tests/graph/beta/test_graph_execution.py @@ -14,7 +14,7 @@ @dataclass class ExecutionState: - log: list[str] = field(default_factory=list) + log: list[str] = field(default_factory=list[str]) counter: int = 0 diff --git a/tests/graph/beta/test_joins_and_reducers.py b/tests/graph/beta/test_joins_and_reducers.py index f1bf58b2e3..2848a1dbf5 100644 --- a/tests/graph/beta/test_joins_and_reducers.py +++ b/tests/graph/beta/test_joins_and_reducers.py @@ -178,7 +178,7 @@ async def test_multiple_joins(): @dataclass class MultiState: - results: dict[str, list[int]] = field(default_factory=dict) + results: dict[str, list[int]] = field(default_factory=dict[str, list[int]]) g = GraphBuilder(state_type=MultiState, output_type=dict[str, list[int]]) @@ -333,7 +333,7 @@ async def test_reduce_first_value(): @dataclass class StateWithResults: - results: list[str] = field(default_factory=list) + results: list[str] = field(default_factory=list[str]) g = GraphBuilder(state_type=StateWithResults, output_type=str) diff --git a/tests/graph/beta/test_v1_v2_integration.py b/tests/graph/beta/test_v1_v2_integration.py index 2baf40a588..776bb197f2 100644 --- a/tests/graph/beta/test_v1_v2_integration.py +++ b/tests/graph/beta/test_v1_v2_integration.py @@ -17,7 +17,7 @@ @dataclass class IntegrationState: - log: list[str] = field(default_factory=list) + log: list[str] = field(default_factory=list[str]) async def test_v1_nodes_in_v2_graph(): diff --git a/tests/models/mock_openai.py b/tests/models/mock_openai.py index 7658e2960c..f1b141fa82 100644 --- a/tests/models/mock_openai.py +++ b/tests/models/mock_openai.py @@ -30,7 +30,7 @@ class MockOpenAI: completions: MockChatCompletion | Sequence[MockChatCompletion] | None = None stream: Sequence[MockChatCompletionChunk] | Sequence[Sequence[MockChatCompletionChunk]] | None = None index: int = 0 - chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list) + chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list[dict[str, Any]]) base_url: str = 'https://api.openai.com/v1' @cached_property @@ -100,7 +100,7 @@ class MockOpenAIResponses: response: MockResponse | Sequence[MockResponse] | None = None stream: Sequence[MockResponseStreamEvent] | Sequence[Sequence[MockResponseStreamEvent]] | None = None index: int = 0 - response_kwargs: list[dict[str, Any]] = field(default_factory=list) + response_kwargs: list[dict[str, Any]] = field(default_factory=list[dict[str, Any]]) base_url: str = 'https://api.openai.com/v1' @cached_property diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 95fb44c502..97c4f88bef 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -141,7 +141,7 @@ class MockAnthropic: messages_: MockAnthropicMessage | Sequence[MockAnthropicMessage] | None = None stream: Sequence[MockRawMessageStreamEvent] | Sequence[Sequence[MockRawMessageStreamEvent]] | None = None index = 0 - chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list) + chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list[dict[str, Any]]) base_url: str | None = None @cached_property diff --git a/tests/models/test_huggingface.py b/tests/models/test_huggingface.py index 56d74ed619..0cc76cab37 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -79,7 +79,7 @@ class MockHuggingFace: completions: MockChatCompletion | Sequence[MockChatCompletion] | None = None stream: Sequence[MockStreamEvent] | Sequence[Sequence[MockStreamEvent]] | None = None index: int = 0 - chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list) + chat_completion_kwargs: list[dict[str, Any]] = field(default_factory=list[dict[str, Any]]) @cached_property def chat(self) -> Any: diff --git a/tests/test_dbos.py b/tests/test_dbos.py index 1d3b9991db..faff948a84 100644 --- a/tests/test_dbos.py +++ b/tests/test_dbos.py @@ -223,7 +223,7 @@ class Response: @dataclass class BasicSpan: content: str - children: list[BasicSpan] = field(default_factory=list) + children: list[BasicSpan] = field(default_factory=list['BasicSpan']) parent_id: int | None = field(repr=False, compare=False, default=None) diff --git a/tests/test_examples.py b/tests/test_examples.py index 8ed0828250..7bb33a0bbf 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -61,8 +61,8 @@ @dataclass class ExamplesConfig(BaseExamplesConfig): - known_first_party: list[str] = field(default_factory=list) - known_local_folder: list[str] = field(default_factory=list) + known_first_party: list[str] = field(default_factory=list[str]) + known_local_folder: list[str] = field(default_factory=list[str]) def ruff_config(self) -> tuple[str, ...]: config = super().ruff_config() diff --git a/tests/test_prefect.py b/tests/test_prefect.py index b1c18b9803..74ce9e57a1 100644 --- a/tests/test_prefect.py +++ b/tests/test_prefect.py @@ -182,7 +182,7 @@ class Response: @dataclass class BasicSpan: content: str - children: list[BasicSpan] = field(default_factory=list) + children: list[BasicSpan] = field(default_factory=list['BasicSpan']) parent_id: int | None = field(repr=False, compare=False, default=None) diff --git a/tests/test_temporal.py b/tests/test_temporal.py index 98039d9078..249a13dafa 100644 --- a/tests/test_temporal.py +++ b/tests/test_temporal.py @@ -309,7 +309,7 @@ async def run(self, prompt: str, deps: Deps) -> Response: @dataclass class BasicSpan: content: str - children: list[BasicSpan] = field(default_factory=list) + children: list[BasicSpan] = field(default_factory=list['BasicSpan']) parent_id: int | None = field(repr=False, compare=False, default=None) @@ -2262,7 +2262,7 @@ async def test_fastmcp_toolset(allow_model_requests: None, client: Client): class GraphState: """State for the graph execution test.""" - values: list[int] = field(default_factory=list) + values: list[int] = field(default_factory=list[int]) # Create a graph with parallel execution using the beta API diff --git a/tests/test_ui.py b/tests/test_ui.py index 37d22c6ecb..bb0c5ccff1 100644 --- a/tests/test_ui.py +++ b/tests/test_ui.py @@ -68,9 +68,9 @@ class DummyUIRunInput(BaseModel): - messages: list[ModelMessage] = field(default_factory=list) - tool_defs: list[ToolDefinition] = field(default_factory=list) - state: dict[str, Any] = field(default_factory=dict) + messages: list[ModelMessage] = field(default_factory=list[ModelMessage]) + tool_defs: list[ToolDefinition] = field(default_factory=list[ToolDefinition]) + state: dict[str, Any] = field(default_factory=dict[str, Any]) class DummyUIState(BaseModel): diff --git a/uv.lock b/uv.lock index 9e14175c32..8b1e2e3e41 100644 --- a/uv.lock +++ b/uv.lock @@ -5495,8 +5495,8 @@ docs-upload = [ ] lint = [ { name = "mypy", specifier = ">=1.11.2" }, - { name = "pyright", specifier = ">=1.1.390" }, - { name = "ruff", specifier = ">=0.6.9" }, + { name = "pyright", specifier = ">=1.1.407" }, + { name = "ruff", specifier = ">=0.14.8" }, ] [[package]] @@ -5927,15 +5927,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/30/23/2f0a3efc4d6a32f3b [[package]] name = "pyright" -version = "1.1.398" +version = "1.1.407" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/24/d6/48740f1d029e9fc4194880d1ad03dcf0ba3a8f802e0e166b8f63350b3584/pyright-1.1.398.tar.gz", hash = "sha256:357a13edd9be8082dc73be51190913e475fa41a6efb6ec0d4b7aab3bc11638d8", size = 3892675, upload-time = "2025-03-26T10:06:06.063Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/1b/0aa08ee42948b61745ac5b5b5ccaec4669e8884b53d31c8ec20b2fcd6b6f/pyright-1.1.407.tar.gz", hash = "sha256:099674dba5c10489832d4a4b2d302636152a9a42d317986c38474c76fe562262", size = 4122872, upload-time = "2025-10-24T23:17:15.145Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/e0/5283593f61b3c525d6d7e94cfb6b3ded20b3df66e953acaf7bb4f23b3f6e/pyright-1.1.398-py3-none-any.whl", hash = "sha256:0a70bfd007d9ea7de1cf9740e1ad1a40a122592cfe22a3f6791b06162ad08753", size = 5780235, upload-time = "2025-03-26T10:06:03.994Z" }, + { url = "https://files.pythonhosted.org/packages/dc/93/b69052907d032b00c40cb656d21438ec00b3a471733de137a3f65a49a0a0/pyright-1.1.407-py3-none-any.whl", hash = "sha256:6dd419f54fcc13f03b52285796d65e639786373f433e243f8b94cf93a7444d21", size = 5997008, upload-time = "2025-10-24T23:17:13.159Z" }, ] [[package]] @@ -6763,28 +6763,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/f0/62b5a1a723fe183650109407fa56abb433b00aa1c0b9ba555f9c4efec2c6/ruff-0.14.6.tar.gz", hash = "sha256:6f0c742ca6a7783a736b867a263b9a7a80a45ce9bee391eeda296895f1b4e1cc", size = 5669501, upload-time = "2025-11-21T14:26:17.903Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/d2/7dd544116d107fffb24a0064d41a5d2ed1c9d6372d142f9ba108c8e39207/ruff-0.14.6-py3-none-linux_armv6l.whl", hash = "sha256:d724ac2f1c240dbd01a2ae98db5d1d9a5e1d9e96eba999d1c48e30062df578a3", size = 13326119, upload-time = "2025-11-21T14:25:24.2Z" }, - { url = "https://files.pythonhosted.org/packages/36/6a/ad66d0a3315d6327ed6b01f759d83df3c4d5f86c30462121024361137b6a/ruff-0.14.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9f7539ea257aa4d07b7ce87aed580e485c40143f2473ff2f2b75aee003186004", size = 13526007, upload-time = "2025-11-21T14:25:26.906Z" }, - { url = "https://files.pythonhosted.org/packages/a3/9d/dae6db96df28e0a15dea8e986ee393af70fc97fd57669808728080529c37/ruff-0.14.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7f6007e55b90a2a7e93083ba48a9f23c3158c433591c33ee2e99a49b889c6332", size = 12676572, upload-time = "2025-11-21T14:25:29.826Z" }, - { url = "https://files.pythonhosted.org/packages/76/a4/f319e87759949062cfee1b26245048e92e2acce900ad3a909285f9db1859/ruff-0.14.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a8e7b9d73d8728b68f632aa8e824ef041d068d231d8dbc7808532d3629a6bef", size = 13140745, upload-time = "2025-11-21T14:25:32.788Z" }, - { url = "https://files.pythonhosted.org/packages/95/d3/248c1efc71a0a8ed4e8e10b4b2266845d7dfc7a0ab64354afe049eaa1310/ruff-0.14.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d50d45d4553a3ebcbd33e7c5e0fe6ca4aafd9a9122492de357205c2c48f00775", size = 13076486, upload-time = "2025-11-21T14:25:35.601Z" }, - { url = "https://files.pythonhosted.org/packages/a5/19/b68d4563fe50eba4b8c92aa842149bb56dd24d198389c0ed12e7faff4f7d/ruff-0.14.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:118548dd121f8a21bfa8ab2c5b80e5b4aed67ead4b7567790962554f38e598ce", size = 13727563, upload-time = "2025-11-21T14:25:38.514Z" }, - { url = "https://files.pythonhosted.org/packages/47/ac/943169436832d4b0e867235abbdb57ce3a82367b47e0280fa7b4eabb7593/ruff-0.14.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:57256efafbfefcb8748df9d1d766062f62b20150691021f8ab79e2d919f7c11f", size = 15199755, upload-time = "2025-11-21T14:25:41.516Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b9/288bb2399860a36d4bb0541cb66cce3c0f4156aaff009dc8499be0c24bf2/ruff-0.14.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff18134841e5c68f8e5df1999a64429a02d5549036b394fafbe410f886e1989d", size = 14850608, upload-time = "2025-11-21T14:25:44.428Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b1/a0d549dd4364e240f37e7d2907e97ee80587480d98c7799d2d8dc7a2f605/ruff-0.14.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c4b7ec1e66a105d5c27bd57fa93203637d66a26d10ca9809dc7fc18ec58440", size = 14118754, upload-time = "2025-11-21T14:25:47.214Z" }, - { url = "https://files.pythonhosted.org/packages/13/ac/9b9fe63716af8bdfddfacd0882bc1586f29985d3b988b3c62ddce2e202c3/ruff-0.14.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:167843a6f78680746d7e226f255d920aeed5e4ad9c03258094a2d49d3028b105", size = 13949214, upload-time = "2025-11-21T14:25:50.002Z" }, - { url = "https://files.pythonhosted.org/packages/12/27/4dad6c6a77fede9560b7df6802b1b697e97e49ceabe1f12baf3ea20862e9/ruff-0.14.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:16a33af621c9c523b1ae006b1b99b159bf5ac7e4b1f20b85b2572455018e0821", size = 14106112, upload-time = "2025-11-21T14:25:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/6a/db/23e322d7177873eaedea59a7932ca5084ec5b7e20cb30f341ab594130a71/ruff-0.14.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1432ab6e1ae2dc565a7eea707d3b03a0c234ef401482a6f1621bc1f427c2ff55", size = 13035010, upload-time = "2025-11-21T14:25:55.536Z" }, - { url = "https://files.pythonhosted.org/packages/a8/9c/20e21d4d69dbb35e6a1df7691e02f363423658a20a2afacf2a2c011800dc/ruff-0.14.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4c55cfbbe7abb61eb914bfd20683d14cdfb38a6d56c6c66efa55ec6570ee4e71", size = 13054082, upload-time = "2025-11-21T14:25:58.625Z" }, - { url = "https://files.pythonhosted.org/packages/66/25/906ee6a0464c3125c8d673c589771a974965c2be1a1e28b5c3b96cb6ef88/ruff-0.14.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:efea3c0f21901a685fff4befda6d61a1bf4cb43de16da87e8226a281d614350b", size = 13303354, upload-time = "2025-11-21T14:26:01.816Z" }, - { url = "https://files.pythonhosted.org/packages/4c/58/60577569e198d56922b7ead07b465f559002b7b11d53f40937e95067ca1c/ruff-0.14.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:344d97172576d75dc6afc0e9243376dbe1668559c72de1864439c4fc95f78185", size = 14054487, upload-time = "2025-11-21T14:26:05.058Z" }, - { url = "https://files.pythonhosted.org/packages/67/0b/8e4e0639e4cc12547f41cb771b0b44ec8225b6b6a93393176d75fe6f7d40/ruff-0.14.6-py3-none-win32.whl", hash = "sha256:00169c0c8b85396516fdd9ce3446c7ca20c2a8f90a77aa945ba6b8f2bfe99e85", size = 13013361, upload-time = "2025-11-21T14:26:08.152Z" }, - { url = "https://files.pythonhosted.org/packages/fb/02/82240553b77fd1341f80ebb3eaae43ba011c7a91b4224a9f317d8e6591af/ruff-0.14.6-py3-none-win_amd64.whl", hash = "sha256:390e6480c5e3659f8a4c8d6a0373027820419ac14fa0d2713bd8e6c3e125b8b9", size = 14432087, upload-time = "2025-11-21T14:26:10.891Z" }, - { url = "https://files.pythonhosted.org/packages/a5/1f/93f9b0fad9470e4c829a5bb678da4012f0c710d09331b860ee555216f4ea/ruff-0.14.6-py3-none-win_arm64.whl", hash = "sha256:d43c81fbeae52cfa8728d8766bbf46ee4298c888072105815b392da70ca836b2", size = 13520930, upload-time = "2025-11-21T14:26:13.951Z" }, +version = "0.14.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/d9/f7a0c4b3a2bf2556cd5d99b05372c29980249ef71e8e32669ba77428c82c/ruff-0.14.8.tar.gz", hash = "sha256:774ed0dd87d6ce925e3b8496feb3a00ac564bea52b9feb551ecd17e0a23d1eed", size = 5765385, upload-time = "2025-12-04T15:06:17.669Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/b8/9537b52010134b1d2b72870cc3f92d5fb759394094741b09ceccae183fbe/ruff-0.14.8-py3-none-linux_armv6l.whl", hash = "sha256:ec071e9c82eca417f6111fd39f7043acb53cd3fde9b1f95bbed745962e345afb", size = 13441540, upload-time = "2025-12-04T15:06:14.896Z" }, + { url = "https://files.pythonhosted.org/packages/24/00/99031684efb025829713682012b6dd37279b1f695ed1b01725f85fd94b38/ruff-0.14.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8cdb162a7159f4ca36ce980a18c43d8f036966e7f73f866ac8f493b75e0c27e9", size = 13669384, upload-time = "2025-12-04T15:06:51.809Z" }, + { url = "https://files.pythonhosted.org/packages/72/64/3eb5949169fc19c50c04f28ece2c189d3b6edd57e5b533649dae6ca484fe/ruff-0.14.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e2fcbefe91f9fad0916850edf0854530c15bd1926b6b779de47e9ab619ea38f", size = 12806917, upload-time = "2025-12-04T15:06:08.925Z" }, + { url = "https://files.pythonhosted.org/packages/c4/08/5250babb0b1b11910f470370ec0cbc67470231f7cdc033cee57d4976f941/ruff-0.14.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d70721066a296f45786ec31916dc287b44040f553da21564de0ab4d45a869b", size = 13256112, upload-time = "2025-12-04T15:06:23.498Z" }, + { url = "https://files.pythonhosted.org/packages/78/4c/6c588e97a8e8c2d4b522c31a579e1df2b4d003eddfbe23d1f262b1a431ff/ruff-0.14.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c87e09b3cd9d126fc67a9ecd3b5b1d3ded2b9c7fce3f16e315346b9d05cfb52", size = 13227559, upload-time = "2025-12-04T15:06:33.432Z" }, + { url = "https://files.pythonhosted.org/packages/23/ce/5f78cea13eda8eceac71b5f6fa6e9223df9b87bb2c1891c166d1f0dce9f1/ruff-0.14.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d62cb310c4fbcb9ee4ac023fe17f984ae1e12b8a4a02e3d21489f9a2a5f730c", size = 13896379, upload-time = "2025-12-04T15:06:02.687Z" }, + { url = "https://files.pythonhosted.org/packages/cf/79/13de4517c4dadce9218a20035b21212a4c180e009507731f0d3b3f5df85a/ruff-0.14.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1af35c2d62633d4da0521178e8a2641c636d2a7153da0bac1b30cfd4ccd91344", size = 15372786, upload-time = "2025-12-04T15:06:29.828Z" }, + { url = "https://files.pythonhosted.org/packages/00/06/33df72b3bb42be8a1c3815fd4fae83fa2945fc725a25d87ba3e42d1cc108/ruff-0.14.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25add4575ffecc53d60eed3f24b1e934493631b48ebbc6ebaf9d8517924aca4b", size = 14990029, upload-time = "2025-12-04T15:06:36.812Z" }, + { url = "https://files.pythonhosted.org/packages/64/61/0f34927bd90925880394de0e081ce1afab66d7b3525336f5771dcf0cb46c/ruff-0.14.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c943d847b7f02f7db4201a0600ea7d244d8a404fbb639b439e987edcf2baf9a", size = 14407037, upload-time = "2025-12-04T15:06:39.979Z" }, + { url = "https://files.pythonhosted.org/packages/96/bc/058fe0aefc0fbf0d19614cb6d1a3e2c048f7dc77ca64957f33b12cfdc5ef/ruff-0.14.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb6e8bf7b4f627548daa1b69283dac5a296bfe9ce856703b03130732e20ddfe2", size = 14102390, upload-time = "2025-12-04T15:06:46.372Z" }, + { url = "https://files.pythonhosted.org/packages/af/a4/e4f77b02b804546f4c17e8b37a524c27012dd6ff05855d2243b49a7d3cb9/ruff-0.14.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:7aaf2974f378e6b01d1e257c6948207aec6a9b5ba53fab23d0182efb887a0e4a", size = 14230793, upload-time = "2025-12-04T15:06:20.497Z" }, + { url = "https://files.pythonhosted.org/packages/3f/52/bb8c02373f79552e8d087cedaffad76b8892033d2876c2498a2582f09dcf/ruff-0.14.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e5758ca513c43ad8a4ef13f0f081f80f08008f410790f3611a21a92421ab045b", size = 13160039, upload-time = "2025-12-04T15:06:49.06Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ad/b69d6962e477842e25c0b11622548df746290cc6d76f9e0f4ed7456c2c31/ruff-0.14.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f74f7ba163b6e85a8d81a590363bf71618847e5078d90827749bfda1d88c9cdf", size = 13205158, upload-time = "2025-12-04T15:06:54.574Z" }, + { url = "https://files.pythonhosted.org/packages/06/63/54f23da1315c0b3dfc1bc03fbc34e10378918a20c0b0f086418734e57e74/ruff-0.14.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:eed28f6fafcc9591994c42254f5a5c5ca40e69a30721d2ab18bb0bb3baac3ab6", size = 13469550, upload-time = "2025-12-04T15:05:59.209Z" }, + { url = "https://files.pythonhosted.org/packages/70/7d/a4d7b1961e4903bc37fffb7ddcfaa7beb250f67d97cfd1ee1d5cddb1ec90/ruff-0.14.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:21d48fa744c9d1cb8d71eb0a740c4dd02751a5de9db9a730a8ef75ca34cf138e", size = 14211332, upload-time = "2025-12-04T15:06:06.027Z" }, + { url = "https://files.pythonhosted.org/packages/5d/93/2a5063341fa17054e5c86582136e9895db773e3c2ffb770dde50a09f35f0/ruff-0.14.8-py3-none-win32.whl", hash = "sha256:15f04cb45c051159baebb0f0037f404f1dc2f15a927418f29730f411a79bc4e7", size = 13151890, upload-time = "2025-12-04T15:06:11.668Z" }, + { url = "https://files.pythonhosted.org/packages/02/1c/65c61a0859c0add13a3e1cbb6024b42de587456a43006ca2d4fd3d1618fe/ruff-0.14.8-py3-none-win_amd64.whl", hash = "sha256:9eeb0b24242b5bbff3011409a739929f497f3fb5fe3b5698aba5e77e8c833097", size = 14537826, upload-time = "2025-12-04T15:06:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/6d/63/8b41cea3afd7f58eb64ac9251668ee0073789a3bc9ac6f816c8c6fef986d/ruff-0.14.8-py3-none-win_arm64.whl", hash = "sha256:965a582c93c63fe715fd3e3f8aa37c4b776777203d8e1d8aa3cc0c14424a4b99", size = 13634522, upload-time = "2025-12-04T15:06:43.212Z" }, ] [[package]]