From 0c3e4c8b37a51eba1c6cbdf72a277134dc4303e5 Mon Sep 17 00:00:00 2001 From: jean-malo Date: Wed, 31 Dec 2025 13:14:43 +0100 Subject: [PATCH] chore: drop support for EOL python 3.9 --- .github/workflows/run_example_scripts.yaml | 15 +- README.md | 5 +- packages/mistralai_azure/pylintrc | 4 +- packages/mistralai_azure/pyproject.toml | 3 +- packages/mistralai_azure/uv.lock | 3 +- packages/mistralai_gcp/pylintrc | 2 +- packages/mistralai_gcp/pyproject.toml | 3 +- packages/mistralai_gcp/uv.lock | 8 +- pylintrc | 2 +- pyproject.toml | 6 +- src/mistralai/extra/mcp/auth.py | 21 +- src/mistralai/extra/mcp/base.py | 20 +- src/mistralai/extra/mcp/sse.py | 28 ++- src/mistralai/extra/mcp/stdio.py | 11 +- src/mistralai/extra/observability/otel.py | 34 ++- src/mistralai/extra/run/context.py | 76 +++---- src/mistralai/extra/run/result.py | 59 +++--- src/mistralai/extra/run/tools.py | 17 +- src/mistralai/extra/struct_chat.py | 23 +- src/mistralai/extra/utils/response_format.py | 8 +- uv.lock | 211 ++++--------------- 21 files changed, 214 insertions(+), 345 deletions(-) diff --git a/.github/workflows/run_example_scripts.yaml b/.github/workflows/run_example_scripts.yaml index 8ea90354..84896d26 100644 --- a/.github/workflows/run_example_scripts.yaml +++ b/.github/workflows/run_example_scripts.yaml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout code @@ -42,18 +42,7 @@ jobs: touch README-PYPI.md # Create this file since the client is not built by Speakeasy uv build - - name: For python 3.9, install the client and run examples without extra dependencies. - if: matrix.python-version == '3.9' - run: | - PACKAGE="dist/$(ls dist | grep whl | head -n 1)" - uv pip install --system "$PACKAGE" - ./scripts/run_examples.sh --no-extra-dep - env: - MISTRAL_AGENT_ID: ${{ secrets.CI_AGENT_ID }} - MISTRAL_API_KEY: ${{ env.MISTRAL_API_KEY }} - - - name: For python 3.10+, install client with extras and run all examples. - if: matrix.python-version != '3.9' + - name: Install client with extras and run all examples. run: | PACKAGE="dist/$(ls dist | grep whl | head -n 1)[agents]" uv pip install --system "$PACKAGE" diff --git a/README.md b/README.md index d198cf10..ba054118 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ It's also possible to write a standalone Python script without needing to set up ```python #!/usr/bin/env -S uv run --script # /// script -# requires-python = ">=3.9" +# requires-python = ">=3.10" # dependencies = [ # "mistralai", # ] @@ -117,8 +117,7 @@ installing the package: pip install "mistralai[agents]" ``` -> Note: Because of some of our dependencies, these features are only available for python version higher or equal to -> 3.10. +> Note: These features require Python 3.10+ (the SDK minimum). ## SDK Example Usage diff --git a/packages/mistralai_azure/pylintrc b/packages/mistralai_azure/pylintrc index a8fcb932..95f656e2 100644 --- a/packages/mistralai_azure/pylintrc +++ b/packages/mistralai_azure/pylintrc @@ -89,7 +89,7 @@ persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.9 +py-version=3.10 # Discover python modules and packages in the file system subtree. recursive=no @@ -660,4 +660,4 @@ init-import=no # List of qualified module names which can have objects that can redefine # builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io \ No newline at end of file +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/packages/mistralai_azure/pyproject.toml b/packages/mistralai_azure/pyproject.toml index 59cd5be3..2842c215 100644 --- a/packages/mistralai_azure/pyproject.toml +++ b/packages/mistralai_azure/pyproject.toml @@ -3,7 +3,7 @@ name = "mistralai_azure" version = "1.6.0" description = "Python Client SDK for the Mistral AI API in Azure." authors = [{ name = "Mistral" }] -requires-python = ">=3.9.2" +requires-python = ">=3.10" readme = "README.md" dependencies = [ "httpcore >=1.0.9", @@ -63,4 +63,3 @@ ignore_missing_imports = true venvPath = "." venv = ".venv" - diff --git a/packages/mistralai_azure/uv.lock b/packages/mistralai_azure/uv.lock index 37c95c55..d77ea936 100644 --- a/packages/mistralai_azure/uv.lock +++ b/packages/mistralai_azure/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.9.2" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.12'", "python_full_version == '3.11.*'", @@ -402,7 +402,6 @@ dependencies = [ { name = "platformdirs" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/e9/60280b14cc1012794120345ce378504cf17409e38cd88f455dc24e0ad6b5/pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", size = 1506739, upload-time = "2024-06-06T14:19:17.955Z" } wheels = [ diff --git a/packages/mistralai_gcp/pylintrc b/packages/mistralai_gcp/pylintrc index 266bc815..c80721af 100644 --- a/packages/mistralai_gcp/pylintrc +++ b/packages/mistralai_gcp/pylintrc @@ -89,7 +89,7 @@ persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.9 +py-version=3.10 # Discover python modules and packages in the file system subtree. recursive=no diff --git a/packages/mistralai_gcp/pyproject.toml b/packages/mistralai_gcp/pyproject.toml index f7f182b6..650ef73b 100644 --- a/packages/mistralai_gcp/pyproject.toml +++ b/packages/mistralai_gcp/pyproject.toml @@ -3,7 +3,7 @@ name = "mistralai-gcp" version = "1.6.0" description = "Python Client SDK for the Mistral AI API in GCP." authors = [{ name = "Mistral" }] -requires-python = ">=3.9" +requires-python = ">=3.10" readme = "README-PYPI.md" dependencies = [ "eval-type-backport >=0.2.0", @@ -66,4 +66,3 @@ ignore_missing_imports = true venvPath = "." venv = ".venv" - diff --git a/packages/mistralai_gcp/uv.lock b/packages/mistralai_gcp/uv.lock index ef292b22..afd17643 100644 --- a/packages/mistralai_gcp/uv.lock +++ b/packages/mistralai_gcp/uv.lock @@ -1,11 +1,10 @@ version = 1 revision = 3 -requires-python = ">=3.9" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.12'", "python_full_version == '3.11.*'", "python_full_version == '3.10.*'", - "python_full_version < '3.10'", ] [[package]] @@ -270,7 +269,6 @@ name = "iniconfig" version = "2.1.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version < '3.10'", ] sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ @@ -419,7 +417,6 @@ name = "platformdirs" version = "4.4.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version < '3.10'", ] sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } wheels = [ @@ -635,11 +632,9 @@ dependencies = [ { name = "dill" }, { name = "isort" }, { name = "mccabe" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/e9/60280b14cc1012794120345ce378504cf17409e38cd88f455dc24e0ad6b5/pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", size = 1506739, upload-time = "2024-06-06T14:19:17.955Z" } wheels = [ @@ -653,7 +648,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "packaging" }, { name = "pluggy" }, diff --git a/pylintrc b/pylintrc index 29202a96..d4e4ba5e 100644 --- a/pylintrc +++ b/pylintrc @@ -90,7 +90,7 @@ persistent=yes # Minimum Python version to use for version dependent checks. Will default to # the version used to run pylint. -py-version=3.9 +py-version=3.10 # Discover python modules and packages in the file system subtree. recursive=no diff --git a/pyproject.toml b/pyproject.toml index 3208eb77..933a3162 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "mistralai" version = "1.10.0" description = "Python Client SDK for the Mistral AI API." authors = [{ name = "Mistral" }] -requires-python = ">=3.9" +requires-python = ">=3.10" readme = "README-PYPI.md" dependencies = [ "eval-type-backport >=0.2.0", @@ -25,7 +25,7 @@ gcp = [ "requests >=2.32.3", ] agents = [ - "mcp >=1.0,<2.0; python_version >= '3.10'", + "mcp >=1.0,<2.0", "griffe >=1.7.3,<2.0", "authlib >=1.5.2,<2.0", ] @@ -42,7 +42,7 @@ dev = [ "types-python-dateutil>=2.9.0.20240316,<3", "types-authlib>=1.5.0.20250516,<2", "types-pyyaml>=6.0.12.20250516,<7", - "mcp>=1.0,<2 ; python_version >= '3.10'", + "mcp>=1.0,<2", "griffe>=1.7.3,<2", "authlib>=1.5.2,<2", ] diff --git a/src/mistralai/extra/mcp/auth.py b/src/mistralai/extra/mcp/auth.py index 909f5d4a..f2b2db8a 100644 --- a/src/mistralai/extra/mcp/auth.py +++ b/src/mistralai/extra/mcp/auth.py @@ -1,9 +1,8 @@ -from typing import Optional +import logging -from authlib.oauth2.rfc8414 import AuthorizationServerMetadata -from authlib.integrations.httpx_client import AsyncOAuth2Client as AsyncOAuth2ClientBase import httpx -import logging +from authlib.integrations.httpx_client import AsyncOAuth2Client as AsyncOAuth2ClientBase +from authlib.oauth2.rfc8414 import AuthorizationServerMetadata from mistralai.types import BaseModel @@ -16,8 +15,8 @@ class Oauth2AuthorizationScheme(BaseModel): authorization_url: str token_url: str scope: list[str] - description: Optional[str] = None - refresh_url: Optional[str] = None + description: str | None = None + refresh_url: str | None = None class OAuthParams(BaseModel): @@ -42,7 +41,7 @@ def from_oauth_params(cls, oauth_params: OAuthParams) -> "AsyncOAuth2Client": async def get_well_known_authorization_server_metadata( server_url: str, -) -> Optional[AuthorizationServerMetadata]: +) -> AuthorizationServerMetadata | None: """Fetch the metadata from the well-known location. This should be available on MCP servers as described by the specification: @@ -123,10 +122,10 @@ async def dynamic_client_registration( async def build_oauth_params( server_url: str, redirect_url: str, - client_id: Optional[str] = None, - client_secret: Optional[str] = None, - scope: Optional[list[str]] = None, - async_client: Optional[httpx.AsyncClient] = None, + client_id: str | None = None, + client_secret: str | None = None, + scope: list[str] | None = None, + async_client: httpx.AsyncClient | None = None, ) -> OAuthParams: """Get issuer metadata and build the oauth required params.""" metadata = await get_oauth_server_metadata(server_url=server_url) diff --git a/src/mistralai/extra/mcp/base.py b/src/mistralai/extra/mcp/base.py index 929b6b11..bbda67d5 100644 --- a/src/mistralai/extra/mcp/base.py +++ b/src/mistralai/extra/mcp/base.py @@ -1,8 +1,8 @@ -from typing import Optional, Sequence, Union import logging import typing +from collections.abc import Sequence from contextlib import AsyncExitStack -from typing import Protocol, Any +from typing import Any, Protocol from mcp import ClientSession # pyright: ignore[reportMissingImports] from mcp.types import ( # pyright: ignore[reportMissingImports] @@ -23,8 +23,8 @@ class MCPSystemPrompt(typing.TypedDict): - description: Optional[str] - messages: list[Union[SystemMessageTypedDict, AssistantMessageTypedDict]] + description: str | None + messages: list[SystemMessageTypedDict | AssistantMessageTypedDict] class MCPClientProtocol(Protocol): @@ -32,7 +32,7 @@ class MCPClientProtocol(Protocol): _name: str - async def initialize(self, exit_stack: Optional[AsyncExitStack]) -> None: + async def initialize(self, exit_stack: AsyncExitStack | None) -> None: ... async def aclose(self) -> None: @@ -42,7 +42,7 @@ async def get_tools(self) -> list[FunctionTool]: ... async def execute_tool( - self, name: str, arguments: dict + self, name: str, arguments: dict[str, Any] ) -> list[TextChunkTypedDict]: ... @@ -60,9 +60,9 @@ class MCPClientBase(MCPClientProtocol): _session: ClientSession - def __init__(self, name: Optional[str] = None): + def __init__(self, name: str | None = None): self._name = name or self.__class__.__name__ - self._exit_stack: Optional[AsyncExitStack] = None + self._exit_stack: AsyncExitStack | None = None self._is_initialized = False def _convert_content(self, mcp_content: ContentBlock) -> TextChunkTypedDict: @@ -109,7 +109,7 @@ async def get_system_prompt( "description": prompt_result.description, "messages": [ typing.cast( - Union[SystemMessageTypedDict, AssistantMessageTypedDict], + SystemMessageTypedDict | AssistantMessageTypedDict, { "role": message.role, "content": self._convert_content(mcp_content=message.content), @@ -122,7 +122,7 @@ async def get_system_prompt( async def list_system_prompts(self) -> ListPromptsResult: return await self._session.list_prompts() - async def initialize(self, exit_stack: Optional[AsyncExitStack] = None) -> None: + async def initialize(self, exit_stack: AsyncExitStack | None = None) -> None: """Initialize the MCP session.""" # client is already initialized so return if self._is_initialized: diff --git a/src/mistralai/extra/mcp/sse.py b/src/mistralai/extra/mcp/sse.py index 3898ba75..ba49fd1a 100644 --- a/src/mistralai/extra/mcp/sse.py +++ b/src/mistralai/extra/mcp/sse.py @@ -1,22 +1,20 @@ import http import logging -import typing -from typing import Any, Optional from contextlib import AsyncExitStack from functools import cached_property +from typing import Any import httpx +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from authlib.oauth2.rfc6749 import OAuth2Token +from mcp.client.sse import sse_client # pyright: ignore[reportMissingImports] +from mcp.shared.message import SessionMessage # pyright: ignore[reportMissingImports] from mistralai.extra.exceptions import MCPAuthException from mistralai.extra.mcp.base import ( MCPClientBase, ) from mistralai.extra.mcp.auth import OAuthParams, AsyncOAuth2Client -from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream - -from mcp.client.sse import sse_client # pyright: ignore[reportMissingImports] -from mcp.shared.message import SessionMessage # pyright: ignore[reportMissingImports] -from authlib.oauth2.rfc6749 import OAuth2Token from mistralai.types import BaseModel @@ -27,7 +25,7 @@ class SSEServerParams(BaseModel): """Parameters required for a MCPClient with SSE transport""" url: str - headers: Optional[dict[str, Any]] = None + headers: dict[str, Any] | None = None timeout: float = 5 sse_read_timeout: float = 60 * 5 @@ -41,20 +39,20 @@ class MCPClientSSE(MCPClientBase): This is possibly going to change in the future since the protocol has ongoing discussions. """ - _oauth_params: Optional[OAuthParams] + _oauth_params: OAuthParams | None _sse_params: SSEServerParams def __init__( self, sse_params: SSEServerParams, - name: Optional[str] = None, - oauth_params: Optional[OAuthParams] = None, - auth_token: Optional[OAuth2Token] = None, + name: str | None = None, + oauth_params: OAuthParams | None = None, + auth_token: OAuth2Token | None = None, ): super().__init__(name=name) self._sse_params = sse_params - self._oauth_params: Optional[OAuthParams] = oauth_params - self._auth_token: Optional[OAuth2Token] = auth_token + self._oauth_params: OAuthParams | None = oauth_params + self._auth_token: OAuth2Token | None = auth_token @cached_property def base_url(self) -> str: @@ -142,7 +140,7 @@ async def requires_auth(self) -> bool: async def _get_transport( self, exit_stack: AsyncExitStack ) -> tuple[ - MemoryObjectReceiveStream[typing.Union[SessionMessage, Exception]], + MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage], ]: try: diff --git a/src/mistralai/extra/mcp/stdio.py b/src/mistralai/extra/mcp/stdio.py index b7af4029..a548066c 100644 --- a/src/mistralai/extra/mcp/stdio.py +++ b/src/mistralai/extra/mcp/stdio.py @@ -1,12 +1,9 @@ -from typing import Optional import logging from contextlib import AsyncExitStack -from mistralai.extra.mcp.base import ( - MCPClientBase, -) +from mcp import StdioServerParameters, stdio_client # pyright: ignore[reportMissingImports] -from mcp import stdio_client, StdioServerParameters # pyright: ignore[reportMissingImports] +from mistralai.extra.mcp.base import MCPClientBase logger = logging.getLogger(__name__) @@ -14,7 +11,9 @@ class MCPClientSTDIO(MCPClientBase): """MCP client that uses stdio for communication.""" - def __init__(self, stdio_params: StdioServerParameters, name: Optional[str] = None): + def __init__( + self, stdio_params: StdioServerParameters, name: str | None = None + ): super().__init__(name=name) self._stdio_params = stdio_params diff --git a/src/mistralai/extra/observability/otel.py b/src/mistralai/extra/observability/otel.py index 6037e681..8be0841d 100644 --- a/src/mistralai/extra/observability/otel.py +++ b/src/mistralai/extra/observability/otel.py @@ -5,7 +5,6 @@ import traceback from datetime import datetime, timezone from enum import Enum -from typing import Optional, Tuple, Union import httpx import opentelemetry.semconv._incubating.attributes.gen_ai_attributes as gen_ai_attributes @@ -135,7 +134,7 @@ def enrich_span_from_response(tracer: trace.Tracer, span: Span, operation_id: st response_data = json.loads(response.content) # Base attributes - attributes: dict[str, Union[str, int]] = { + attributes: dict[str, str | int] = { http_attributes.HTTP_RESPONSE_STATUS_CODE: response.status_code, MistralAIAttributes.MISTRAL_AI_OPERATION_ID: operation_id, gen_ai_attributes.GEN_AI_PROVIDER_NAME: gen_ai_attributes.GenAiProviderNameValues.MISTRAL_AI.value @@ -226,7 +225,7 @@ def export(self, spans): return SpanExportResult.FAILURE -def get_or_create_otel_tracer() -> Tuple[bool, Tracer]: +def get_or_create_otel_tracer() -> tuple[bool, Tracer]: """ 3 possible cases: @@ -273,7 +272,13 @@ def get_or_create_otel_tracer() -> Tuple[bool, Tracer]: return tracing_enabled, tracer -def get_traced_request_and_span(tracing_enabled: bool, tracer: Tracer, span: Optional[Span], operation_id: str, request: httpx.Request) -> Tuple[httpx.Request, Optional[Span]]: +def get_traced_request_and_span( + tracing_enabled: bool, + tracer: Tracer, + span: Span | None, + operation_id: str, + request: httpx.Request, +) -> tuple[httpx.Request, Span | None]: if not tracing_enabled: return request, span @@ -295,7 +300,13 @@ def get_traced_request_and_span(tracing_enabled: bool, tracer: Tracer, span: Opt return request, span -def get_traced_response(tracing_enabled: bool, tracer: Tracer, span: Optional[Span], operation_id: str, response: httpx.Response) -> httpx.Response: +def get_traced_response( + tracing_enabled: bool, + tracer: Tracer, + span: Span | None, + operation_id: str, + response: httpx.Response, +) -> httpx.Response: if not tracing_enabled or not span: return response try: @@ -315,7 +326,14 @@ def get_traced_response(tracing_enabled: bool, tracer: Tracer, span: Optional[Sp end_span(span=span) return response -def get_response_and_error(tracing_enabled: bool, tracer: Tracer, span: Optional[Span], operation_id: str, response: httpx.Response, error: Optional[Exception]) -> Tuple[httpx.Response, Optional[Exception]]: +def get_response_and_error( + tracing_enabled: bool, + tracer: Tracer, + span: Span | None, + operation_id: str, + response: httpx.Response, + error: Exception | None, +) -> tuple[httpx.Response, Exception | None]: if not tracing_enabled or not span: return response, error try: @@ -366,7 +384,7 @@ class TracedResponse(httpx.Response): This hack allows ending the span only once the stream is fully consumed. """ - def __init__(self, *args, span: Optional[Span], **kwargs) -> None: + def __init__(self, *args, span: Span | None, **kwargs) -> None: super().__init__(*args, **kwargs) self.span = span @@ -381,7 +399,7 @@ async def aclose(self) -> None: await super().aclose() @classmethod - def from_response(cls, resp: httpx.Response, span: Optional[Span]) -> "TracedResponse": + def from_response(cls, resp: httpx.Response, span: Span | None) -> "TracedResponse": traced_resp = cls.__new__(cls) traced_resp.__dict__ = copy.copy(resp.__dict__) traced_resp.span = span diff --git a/src/mistralai/extra/run/context.py b/src/mistralai/extra/run/context.py index 08350a84..0d78352a 100644 --- a/src/mistralai/extra/run/context.py +++ b/src/mistralai/extra/run/context.py @@ -1,47 +1,41 @@ import asyncio import inspect import typing -from contextlib import AsyncExitStack -from functools import wraps from collections.abc import Callable - +from contextlib import AsyncExitStack from dataclasses import dataclass, field -from typing import Union, Optional +from functools import wraps +from logging import getLogger import pydantic -from mistralai.extra import ( - response_format_from_pydantic_model, -) +from mistralai.extra import response_format_from_pydantic_model from mistralai.extra.exceptions import RunException from mistralai.extra.mcp.base import MCPClientProtocol from mistralai.extra.run.result import RunResult -from mistralai.types.basemodel import OptionalNullable, BaseModel, UNSET +from mistralai.extra.run.tools import ( + RunCoroutine, + RunFunction, + RunMCPTool, + RunTool, + create_function_result, + create_tool_call, +) from mistralai.models import ( - ResponseFormat, - FunctionCallEntry, - Tools, - ToolsTypedDict, CompletionArgs, CompletionArgsTypedDict, - FunctionResultEntry, ConversationInputs, ConversationInputsTypedDict, + FunctionCallEntry, + FunctionResultEntry, FunctionTool, - MessageInputEntry, InputEntries, + MessageInputEntry, + ResponseFormat, + Tools, + ToolsTypedDict, ) - -from logging import getLogger - -from mistralai.extra.run.tools import ( - create_function_result, - RunFunction, - create_tool_call, - RunTool, - RunMCPTool, - RunCoroutine, -) +from mistralai.types.basemodel import BaseModel, OptionalNullable, UNSET if typing.TYPE_CHECKING: from mistralai import Beta, OptionalNullable @@ -56,8 +50,8 @@ class AgentRequestKwargs(typing.TypedDict): class ModelRequestKwargs(typing.TypedDict): model: str instructions: OptionalNullable[str] - tools: OptionalNullable[Union[list[Tools], list[ToolsTypedDict]]] - completion_args: OptionalNullable[Union[CompletionArgs, CompletionArgsTypedDict]] + tools: OptionalNullable[list[Tools] | list[ToolsTypedDict]] + completion_args: OptionalNullable[CompletionArgs | CompletionArgsTypedDict] @dataclass @@ -72,7 +66,7 @@ class RunContext: passed if the user wants to continue an existing conversation. model (Options[str]): The model name to be used for the conversation. Can't be used along with 'agent_id'. agent_id (Options[str]): The agent id to be used for the conversation. Can't be used along with 'model'. - output_format (Optional[type[BaseModel]]): The output format expected from the conversation. It represents + output_format (type[BaseModel] | None): The output format expected from the conversation. It represents the `response_format` which is part of the `CompletionArgs`. request_count (int): The number of requests made in the current `RunContext`. continue_on_fn_error (bool): Flag to determine if the conversation should continue when function execution @@ -83,10 +77,10 @@ class RunContext: _callable_tools: dict[str, RunTool] = field(init=False, default_factory=dict) _mcp_clients: list[MCPClientProtocol] = field(init=False, default_factory=list) - conversation_id: Optional[str] = field(default=None) - model: Optional[str] = field(default=None) - agent_id: Optional[str] = field(default=None) - output_format: Optional[type[BaseModel]] = field(default=None) + conversation_id: str | None = field(default=None) + model: str | None = field(default=None) + agent_id: str | None = field(default=None) + output_format: type[BaseModel] | None = field(default=None) request_count: int = field(default=0) continue_on_fn_error: bool = field(default=False) @@ -215,10 +209,8 @@ async def prepare_agent_request(self, beta_client: "Beta") -> AgentRequestKwargs async def prepare_model_request( self, - tools: OptionalNullable[Union[list[Tools], list[ToolsTypedDict]]] = UNSET, - completion_args: OptionalNullable[ - Union[CompletionArgs, CompletionArgsTypedDict] - ] = UNSET, + tools: OptionalNullable[list[Tools] | list[ToolsTypedDict]] = UNSET, + completion_args: OptionalNullable[CompletionArgs | CompletionArgsTypedDict] = UNSET, instructions: OptionalNullable[str] = None, ) -> ModelRequestKwargs: if self.model is None: @@ -254,14 +246,12 @@ async def _validate_run( *, beta_client: "Beta", run_ctx: RunContext, - inputs: Union[ConversationInputs, ConversationInputsTypedDict], + inputs: ConversationInputs | ConversationInputsTypedDict, instructions: OptionalNullable[str] = UNSET, - tools: OptionalNullable[Union[list[Tools], list[ToolsTypedDict]]] = UNSET, - completion_args: OptionalNullable[ - Union[CompletionArgs, CompletionArgsTypedDict] - ] = UNSET, + tools: OptionalNullable[list[Tools] | list[ToolsTypedDict]] = UNSET, + completion_args: OptionalNullable[CompletionArgs | CompletionArgsTypedDict] = UNSET, ) -> tuple[ - Union[AgentRequestKwargs, ModelRequestKwargs], RunResult, list[InputEntries] + AgentRequestKwargs | ModelRequestKwargs, RunResult, list[InputEntries] ]: input_entries: list[InputEntries] = [] if isinstance(inputs, str): @@ -277,7 +267,7 @@ async def _validate_run( output_model=run_ctx.output_format, conversation_id=run_ctx.conversation_id, ) - req: Union[AgentRequestKwargs, ModelRequestKwargs] + req: AgentRequestKwargs | ModelRequestKwargs if run_ctx.agent_id: if tools or completion_args: raise RunException("Can't set tools or completion_args when using an agent") diff --git a/src/mistralai/extra/run/result.py b/src/mistralai/extra/run/result.py index 9592dccf..0af48ee7 100644 --- a/src/mistralai/extra/run/result.py +++ b/src/mistralai/extra/run/result.py @@ -1,9 +1,10 @@ import datetime import json import typing -from typing import Union, Annotated, Optional, Literal from dataclasses import dataclass, field -from pydantic import Discriminator, Tag, BaseModel +from typing import Annotated, Literal + +from pydantic import BaseModel, Discriminator, Tag from mistralai.extra.utils.response_format import pydantic_model_from_json from mistralai.models import ( @@ -35,15 +36,15 @@ ) from mistralai.utils import get_discriminator -RunOutputEntries = typing.Union[ - MessageOutputEntry, - FunctionCallEntry, - FunctionResultEntry, - AgentHandoffEntry, - ToolExecutionEntry, -] +RunOutputEntries = ( + MessageOutputEntry + | FunctionCallEntry + | FunctionResultEntry + | AgentHandoffEntry + | ToolExecutionEntry +) -RunEntries = typing.Union[RunOutputEntries, MessageInputEntry] +RunEntries = RunOutputEntries | MessageInputEntry def as_text(entry: RunOutputEntries) -> str: @@ -140,12 +141,12 @@ class RunFiles: @dataclass class RunResult: input_entries: list[InputEntries] - conversation_id: Optional[str] = field(default=None) + conversation_id: str | None = field(default=None) output_entries: list[RunOutputEntries] = field(default_factory=list) files: dict[str, RunFiles] = field(default_factory=dict) - output_model: Optional[type[BaseModel]] = field(default=None) + output_model: type[BaseModel] | None = field(default=None) - def get_file(self, file_id: str) -> Optional[RunFiles]: + def get_file(self, file_id: str) -> RunFiles | None: return self.files.get(file_id) @property @@ -172,36 +173,34 @@ def output_as_model(self) -> BaseModel: class FunctionResultEvent(BaseModel): - id: Optional[str] = None + id: str | None = None - type: Optional[Literal["function.result"]] = "function.result" + type: Literal["function.result"] | None = "function.result" result: str tool_call_id: str - created_at: Optional[datetime.datetime] = datetime.datetime.now( + created_at: datetime.datetime | None = datetime.datetime.now( tz=datetime.timezone.utc ) - output_index: Optional[int] = 0 + output_index: int | None = 0 -RunResultEventsType = typing.Union[SSETypes, Literal["function.result"]] +RunResultEventsType = SSETypes | Literal["function.result"] RunResultEventsData = typing.Annotated[ - Union[ - Annotated[AgentHandoffDoneEvent, Tag("agent.handoff.done")], - Annotated[AgentHandoffStartedEvent, Tag("agent.handoff.started")], - Annotated[ResponseDoneEvent, Tag("conversation.response.done")], - Annotated[ResponseErrorEvent, Tag("conversation.response.error")], - Annotated[ResponseStartedEvent, Tag("conversation.response.started")], - Annotated[FunctionCallEvent, Tag("function.call.delta")], - Annotated[MessageOutputEvent, Tag("message.output.delta")], - Annotated[ToolExecutionDoneEvent, Tag("tool.execution.done")], - Annotated[ToolExecutionStartedEvent, Tag("tool.execution.started")], - Annotated[FunctionResultEvent, Tag("function.result")], - ], + Annotated[AgentHandoffDoneEvent, Tag("agent.handoff.done")] + | Annotated[AgentHandoffStartedEvent, Tag("agent.handoff.started")] + | Annotated[ResponseDoneEvent, Tag("conversation.response.done")] + | Annotated[ResponseErrorEvent, Tag("conversation.response.error")] + | Annotated[ResponseStartedEvent, Tag("conversation.response.started")] + | Annotated[FunctionCallEvent, Tag("function.call.delta")] + | Annotated[MessageOutputEvent, Tag("message.output.delta")] + | Annotated[ToolExecutionDoneEvent, Tag("tool.execution.done")] + | Annotated[ToolExecutionStartedEvent, Tag("tool.execution.started")] + | Annotated[FunctionResultEvent, Tag("function.result")], Discriminator(lambda m: get_discriminator(m, "type", "type")), ] diff --git a/src/mistralai/extra/run/tools.py b/src/mistralai/extra/run/tools.py index e3f80935..b117fdea 100644 --- a/src/mistralai/extra/run/tools.py +++ b/src/mistralai/extra/run/tools.py @@ -1,14 +1,11 @@ +import inspect import itertools +import json import logging from dataclasses import dataclass -import inspect - -from pydantic import Field, create_model -from pydantic.fields import FieldInfo -import json -from typing import cast, Callable, Sequence, Any, ForwardRef, get_type_hints, Union +from typing import Any, Callable, ForwardRef, Sequence, cast, get_type_hints -from opentelemetry import trace +import opentelemetry.semconv._incubating.attributes.gen_ai_attributes as gen_ai_attributes from griffe import ( Docstring, DocstringSectionKind, @@ -16,7 +13,9 @@ DocstringParameter, DocstringSection, ) -import opentelemetry.semconv._incubating.attributes.gen_ai_attributes as gen_ai_attributes +from opentelemetry import trace +from pydantic import Field, create_model +from pydantic.fields import FieldInfo from mistralai.extra.exceptions import RunException from mistralai.extra.mcp.base import MCPClientProtocol @@ -54,7 +53,7 @@ class RunMCPTool: mcp_client: MCPClientProtocol -RunTool = Union[RunFunction, RunCoroutine, RunMCPTool] +RunTool = RunFunction | RunCoroutine | RunMCPTool def _get_function_description(docstring_sections: list[DocstringSection]) -> str: diff --git a/src/mistralai/extra/struct_chat.py b/src/mistralai/extra/struct_chat.py index 364b450f..773cbb6c 100644 --- a/src/mistralai/extra/struct_chat.py +++ b/src/mistralai/extra/struct_chat.py @@ -1,19 +1,26 @@ -from ..models import ChatCompletionResponse, ChatCompletionChoice, AssistantMessage -from .utils.response_format import CustomPydanticModel, pydantic_model_from_json -from typing import List, Optional, Type, Generic -from pydantic import BaseModel import json +from typing import Generic + +from ..models import AssistantMessage, ChatCompletionChoice, ChatCompletionResponse +from .utils.response_format import CustomPydanticModel, pydantic_model_from_json + class ParsedAssistantMessage(AssistantMessage, Generic[CustomPydanticModel]): - parsed: Optional[CustomPydanticModel] + parsed: CustomPydanticModel | None + class ParsedChatCompletionChoice(ChatCompletionChoice, Generic[CustomPydanticModel]): - message: Optional[ParsedAssistantMessage[CustomPydanticModel]] # type: ignore + message: ParsedAssistantMessage[CustomPydanticModel] | None # type: ignore + class ParsedChatCompletionResponse(ChatCompletionResponse, Generic[CustomPydanticModel]): - choices: Optional[List[ParsedChatCompletionChoice[CustomPydanticModel]]] # type: ignore + choices: list[ParsedChatCompletionChoice[CustomPydanticModel]] | None # type: ignore + -def convert_to_parsed_chat_completion_response(response: ChatCompletionResponse, response_format: Type[BaseModel]) -> ParsedChatCompletionResponse: +def convert_to_parsed_chat_completion_response( + response: ChatCompletionResponse, + response_format: type[CustomPydanticModel], +) -> ParsedChatCompletionResponse[CustomPydanticModel]: parsed_choices = [] if response.choices: diff --git a/src/mistralai/extra/utils/response_format.py b/src/mistralai/extra/utils/response_format.py index 67e15912..10bff89f 100644 --- a/src/mistralai/extra/utils/response_format.py +++ b/src/mistralai/extra/utils/response_format.py @@ -1,5 +1,6 @@ +from typing import Any, TypeVar + from pydantic import BaseModel -from typing import TypeVar, Any, Type, Dict from ...models import JSONSchema, ResponseFormat from ._pydantic_helper import rec_strict_json_schema @@ -7,7 +8,7 @@ def response_format_from_pydantic_model( - model: Type[CustomPydanticModel], + model: type[CustomPydanticModel], ) -> ResponseFormat: """Generate a strict JSON schema from a pydantic model.""" model_schema = rec_strict_json_schema(model.model_json_schema()) @@ -18,7 +19,8 @@ def response_format_from_pydantic_model( def pydantic_model_from_json( - json_data: Dict[str, Any], pydantic_model: Type[CustomPydanticModel] + json_data: dict[str, Any], + pydantic_model: type[CustomPydanticModel], ) -> CustomPydanticModel: """Parse a JSON schema into a pydantic model.""" return pydantic_model.model_validate(json_data) diff --git a/uv.lock b/uv.lock index 97fbeeec..59639629 100644 --- a/uv.lock +++ b/uv.lock @@ -1,11 +1,10 @@ version = 1 revision = 3 -requires-python = ">=3.9" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.12'", "python_full_version == '3.11.*'", - "python_full_version == '3.10.*'", - "python_full_version < '3.10'", + "python_full_version < '3.11'", ] [[package]] @@ -162,18 +161,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, - { url = "https://files.pythonhosted.org/packages/c0/cc/08ed5a43f2996a16b462f64a7055c6e962803534924b9b2f1371d8c00b7b/cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf", size = 184288, upload-time = "2025-09-08T23:23:48.404Z" }, - { url = "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", size = 180509, upload-time = "2025-09-08T23:23:49.73Z" }, - { url = "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", size = 208813, upload-time = "2025-09-08T23:23:51.263Z" }, - { url = "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", size = 216498, upload-time = "2025-09-08T23:23:52.494Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/5c51c1c7600bdd7ed9a24a203ec255dccdd0ebf4527f7b922a0bde2fb6ed/cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", size = 203243, upload-time = "2025-09-08T23:23:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/32/f2/81b63e288295928739d715d00952c8c6034cb6c6a516b17d37e0c8be5600/cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", size = 203158, upload-time = "2025-09-08T23:23:55.169Z" }, - { url = "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", size = 216548, upload-time = "2025-09-08T23:23:56.506Z" }, - { url = "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", size = 218897, upload-time = "2025-09-08T23:23:57.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", size = 211249, upload-time = "2025-09-08T23:23:59.139Z" }, - { url = "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", size = 218041, upload-time = "2025-09-08T23:24:00.496Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d9/6218d78f920dcd7507fc16a766b5ef8f3b913cc7aa938e7fc80b9978d089/cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", size = 172138, upload-time = "2025-09-08T23:24:01.7Z" }, - { url = "https://files.pythonhosted.org/packages/54/8f/a1e836f82d8e32a97e6b29cc8f641779181ac7363734f12df27db803ebda/cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", size = 182794, upload-time = "2025-09-08T23:24:02.943Z" }, ] [[package]] @@ -262,22 +249,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, - { url = "https://files.pythonhosted.org/packages/46/7c/0c4760bccf082737ca7ab84a4c2034fcc06b1f21cf3032ea98bd6feb1725/charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9", size = 209609, upload-time = "2025-10-14T04:42:10.922Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a4/69719daef2f3d7f1819de60c9a6be981b8eeead7542d5ec4440f3c80e111/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d", size = 149029, upload-time = "2025-10-14T04:42:12.38Z" }, - { url = "https://files.pythonhosted.org/packages/e6/21/8d4e1d6c1e6070d3672908b8e4533a71b5b53e71d16828cc24d0efec564c/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608", size = 144580, upload-time = "2025-10-14T04:42:13.549Z" }, - { url = "https://files.pythonhosted.org/packages/a7/0a/a616d001b3f25647a9068e0b9199f697ce507ec898cacb06a0d5a1617c99/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc", size = 162340, upload-time = "2025-10-14T04:42:14.892Z" }, - { url = "https://files.pythonhosted.org/packages/85/93/060b52deb249a5450460e0585c88a904a83aec474ab8e7aba787f45e79f2/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e", size = 159619, upload-time = "2025-10-14T04:42:16.676Z" }, - { url = "https://files.pythonhosted.org/packages/dd/21/0274deb1cc0632cd587a9a0ec6b4674d9108e461cb4cd40d457adaeb0564/charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1", size = 153980, upload-time = "2025-10-14T04:42:17.917Z" }, - { url = "https://files.pythonhosted.org/packages/28/2b/e3d7d982858dccc11b31906976323d790dded2017a0572f093ff982d692f/charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3", size = 152174, upload-time = "2025-10-14T04:42:19.018Z" }, - { url = "https://files.pythonhosted.org/packages/6e/ff/4a269f8e35f1e58b2df52c131a1fa019acb7ef3f8697b7d464b07e9b492d/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6", size = 151666, upload-time = "2025-10-14T04:42:20.171Z" }, - { url = "https://files.pythonhosted.org/packages/da/c9/ec39870f0b330d58486001dd8e532c6b9a905f5765f58a6f8204926b4a93/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88", size = 145550, upload-time = "2025-10-14T04:42:21.324Z" }, - { url = "https://files.pythonhosted.org/packages/75/8f/d186ab99e40e0ed9f82f033d6e49001701c81244d01905dd4a6924191a30/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1", size = 163721, upload-time = "2025-10-14T04:42:22.46Z" }, - { url = "https://files.pythonhosted.org/packages/96/b1/6047663b9744df26a7e479ac1e77af7134b1fcf9026243bb48ee2d18810f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf", size = 152127, upload-time = "2025-10-14T04:42:23.712Z" }, - { url = "https://files.pythonhosted.org/packages/59/78/e5a6eac9179f24f704d1be67d08704c3c6ab9f00963963524be27c18ed87/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318", size = 161175, upload-time = "2025-10-14T04:42:24.87Z" }, - { url = "https://files.pythonhosted.org/packages/e5/43/0e626e42d54dd2f8dd6fc5e1c5ff00f05fbca17cb699bedead2cae69c62f/charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c", size = 155375, upload-time = "2025-10-14T04:42:27.246Z" }, - { url = "https://files.pythonhosted.org/packages/e9/91/d9615bf2e06f35e4997616ff31248c3657ed649c5ab9d35ea12fce54e380/charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505", size = 99692, upload-time = "2025-10-14T04:42:28.425Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a9/6c040053909d9d1ef4fcab45fddec083aedc9052c10078339b47c8573ea8/charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966", size = 107192, upload-time = "2025-10-14T04:42:29.482Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c6/4fa536b2c0cd3edfb7ccf8469fa0f363ea67b7213a842b90909ca33dd851/charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50", size = 100220, upload-time = "2025-10-14T04:42:30.632Z" }, { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] @@ -286,7 +257,7 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ @@ -423,32 +394,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, ] -[[package]] -name = "griffe" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "colorama", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/b1/9ff6578d789a89812ff21e4e0f80ffae20a65d5dd84e7a17873fe3b365be/griffe-1.14.0-py3-none-any.whl", hash = "sha256:0e9d52832cccf0f7188cfe585ba962d2674b241c01916d780925df34873bceb0", size = 144439, upload-time = "2025-09-05T15:02:27.511Z" }, -] - [[package]] name = "griffe" version = "1.15.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10'" }, + { name = "colorama" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } wheels = [ @@ -522,27 +473,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, @@ -571,10 +505,10 @@ name = "jsonschema" version = "4.25.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "jsonschema-specifications", marker = "python_full_version >= '3.10'" }, - { name = "referencing", marker = "python_full_version >= '3.10'" }, - { name = "rpds-py", marker = "python_full_version >= '3.10'" }, + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } wheels = [ @@ -586,7 +520,7 @@ name = "jsonschema-specifications" version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "referencing", marker = "python_full_version >= '3.10'" }, + { name = "referencing" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ @@ -607,20 +541,20 @@ name = "mcp" version = "1.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "httpx", marker = "python_full_version >= '3.10'" }, - { name = "httpx-sse", marker = "python_full_version >= '3.10'" }, - { name = "jsonschema", marker = "python_full_version >= '3.10'" }, - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "pydantic-settings", marker = "python_full_version >= '3.10'" }, - { name = "pyjwt", extra = ["crypto"], marker = "python_full_version >= '3.10'" }, - { name = "python-multipart", marker = "python_full_version >= '3.10'" }, - { name = "pywin32", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "sse-starlette", marker = "python_full_version >= '3.10'" }, - { name = "starlette", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, - { name = "uvicorn", marker = "python_full_version >= '3.10' and sys_platform != 'emscripten'" }, + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d5/2d/649d80a0ecf6a1f82632ca44bec21c0461a9d9fc8934d38cb5b319f2db5e/mcp-1.25.0.tar.gz", hash = "sha256:56310361ebf0364e2d438e5b45f7668cbb124e158bb358333cd06e49e83a6802", size = 605387, upload-time = "2025-12-19T10:19:56.985Z" } wheels = [ @@ -648,9 +582,8 @@ dependencies = [ [package.optional-dependencies] agents = [ { name = "authlib" }, - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "mcp", marker = "python_full_version >= '3.10'" }, + { name = "griffe" }, + { name = "mcp" }, ] gcp = [ { name = "google-auth" }, @@ -660,9 +593,8 @@ gcp = [ [package.dev-dependencies] dev = [ { name = "authlib" }, - { name = "griffe", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "griffe", version = "1.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "mcp", marker = "python_full_version >= '3.10'" }, + { name = "griffe" }, + { name = "mcp" }, { name = "mypy" }, { name = "pylint" }, { name = "pytest" }, @@ -685,7 +617,7 @@ requires-dist = [ { name = "griffe", marker = "extra == 'agents'", specifier = ">=1.7.3,<2.0" }, { name = "httpx", specifier = ">=0.28.1" }, { name = "invoke", specifier = ">=2.2.0,<3.0.0" }, - { name = "mcp", marker = "python_full_version >= '3.10' and extra == 'agents'", specifier = ">=1.0,<2.0" }, + { name = "mcp", marker = "extra == 'agents'", specifier = ">=1.0,<2.0" }, { name = "opentelemetry-api", specifier = ">=1.33.1,<2.0.0" }, { name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.37.0,<2.0.0" }, { name = "opentelemetry-sdk", specifier = ">=1.33.1,<2.0.0" }, @@ -702,7 +634,7 @@ provides-extras = ["gcp", "agents"] dev = [ { name = "authlib", specifier = ">=1.5.2,<2" }, { name = "griffe", specifier = ">=1.7.3,<2" }, - { name = "mcp", marker = "python_full_version >= '3.10'", specifier = ">=1.0,<2" }, + { name = "mcp", specifier = ">=1.0,<2" }, { name = "mypy", specifier = "==1.15.0" }, { name = "pylint", specifier = "==3.2.3" }, { name = "pytest", specifier = ">=8.2.2,<9" }, @@ -752,12 +684,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" }, { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" }, { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" }, - { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129, upload-time = "2025-02-05T03:50:24.509Z" }, - { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335, upload-time = "2025-02-05T03:49:36.398Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935, upload-time = "2025-02-05T03:49:14.154Z" }, - { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827, upload-time = "2025-02-05T03:48:59.458Z" }, - { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924, upload-time = "2025-02-05T03:50:03.12Z" }, - { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176, upload-time = "2025-02-05T03:50:10.86Z" }, { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" }, ] @@ -870,27 +796,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "platformdirs" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, -] - [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, @@ -917,8 +826,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460, upload-time = "2025-12-06T00:17:45.678Z" }, { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168, upload-time = "2025-12-06T00:17:46.813Z" }, { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270, upload-time = "2025-12-06T00:17:48.253Z" }, - { url = "https://files.pythonhosted.org/packages/87/85/5c1115e68fd34e8ada6fa75974b4c778a298a3c7170575b49efc1eb99dd2/protobuf-6.33.2-cp39-cp39-win32.whl", hash = "sha256:7109dcc38a680d033ffb8bf896727423528db9163be1b6a02d6a49606dcadbfe", size = 425692, upload-time = "2025-12-06T00:17:49.62Z" }, - { url = "https://files.pythonhosted.org/packages/c5/74/18d9de7fd3c41a8b4808d6268515b320abae003423da1b1319f71bdf0779/protobuf-6.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:2981c58f582f44b6b13173e12bb8656711189c2a70250845f264b877f00b1913", size = 436932, upload-time = "2025-12-06T00:17:51.098Z" }, { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501, upload-time = "2025-12-06T00:17:52.211Z" }, ] @@ -1059,19 +966,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, - { url = "https://files.pythonhosted.org/packages/54/db/160dffb57ed9a3705c4cbcbff0ac03bdae45f1ca7d58ab74645550df3fbd/pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", size = 2107999, upload-time = "2025-11-04T13:42:03.885Z" }, - { url = "https://files.pythonhosted.org/packages/a3/7d/88e7de946f60d9263cc84819f32513520b85c0f8322f9b8f6e4afc938383/pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", size = 1929745, upload-time = "2025-11-04T13:42:06.075Z" }, - { url = "https://files.pythonhosted.org/packages/d5/c2/aef51e5b283780e85e99ff19db0f05842d2d4a8a8cd15e63b0280029b08f/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", size = 1920220, upload-time = "2025-11-04T13:42:08.457Z" }, - { url = "https://files.pythonhosted.org/packages/c7/97/492ab10f9ac8695cd76b2fdb24e9e61f394051df71594e9bcc891c9f586e/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", size = 2067296, upload-time = "2025-11-04T13:42:10.817Z" }, - { url = "https://files.pythonhosted.org/packages/ec/23/984149650e5269c59a2a4c41d234a9570adc68ab29981825cfaf4cfad8f4/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", size = 2231548, upload-time = "2025-11-04T13:42:13.843Z" }, - { url = "https://files.pythonhosted.org/packages/71/0c/85bcbb885b9732c28bec67a222dbed5ed2d77baee1f8bba2002e8cd00c5c/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", size = 2362571, upload-time = "2025-11-04T13:42:16.208Z" }, - { url = "https://files.pythonhosted.org/packages/c0/4a/412d2048be12c334003e9b823a3fa3d038e46cc2d64dd8aab50b31b65499/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", size = 2068175, upload-time = "2025-11-04T13:42:18.911Z" }, - { url = "https://files.pythonhosted.org/packages/73/f4/c58b6a776b502d0a5540ad02e232514285513572060f0d78f7832ca3c98b/pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", size = 2177203, upload-time = "2025-11-04T13:42:22.578Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ae/f06ea4c7e7a9eead3d165e7623cd2ea0cb788e277e4f935af63fc98fa4e6/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", size = 2148191, upload-time = "2025-11-04T13:42:24.89Z" }, - { url = "https://files.pythonhosted.org/packages/c1/57/25a11dcdc656bf5f8b05902c3c2934ac3ea296257cc4a3f79a6319e61856/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", size = 2343907, upload-time = "2025-11-04T13:42:27.683Z" }, - { url = "https://files.pythonhosted.org/packages/96/82/e33d5f4933d7a03327c0c43c65d575e5919d4974ffc026bc917a5f7b9f61/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", size = 2322174, upload-time = "2025-11-04T13:42:30.776Z" }, - { url = "https://files.pythonhosted.org/packages/81/45/4091be67ce9f469e81656f880f3506f6a5624121ec5eb3eab37d7581897d/pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", size = 1990353, upload-time = "2025-11-04T13:42:33.111Z" }, - { url = "https://files.pythonhosted.org/packages/44/8a/a98aede18db6e9cd5d66bcacd8a409fcf8134204cdede2e7de35c5a2c5ef/pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", size = 2015698, upload-time = "2025-11-04T13:42:35.484Z" }, { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, @@ -1103,9 +997,9 @@ name = "pydantic-settings" version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic", marker = "python_full_version >= '3.10'" }, - { name = "python-dotenv", marker = "python_full_version >= '3.10'" }, - { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ @@ -1132,7 +1026,7 @@ wheels = [ [package.optional-dependencies] crypto = [ - { name = "cryptography", marker = "python_full_version >= '3.10'" }, + { name = "cryptography" }, ] [[package]] @@ -1145,11 +1039,9 @@ dependencies = [ { name = "dill" }, { name = "isort" }, { name = "mccabe" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "platformdirs" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "tomlkit" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/e9/60280b14cc1012794120345ce378504cf17409e38cd88f455dc24e0ad6b5/pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", size = 1506739, upload-time = "2024-06-06T14:19:17.955Z" } wheels = [ @@ -1176,8 +1068,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, @@ -1250,9 +1141,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, - { url = "https://files.pythonhosted.org/packages/59/42/b86689aac0cdaee7ae1c58d464b0ff04ca909c19bb6502d4973cdd9f9544/pywin32-311-cp39-cp39-win32.whl", hash = "sha256:aba8f82d551a942cb20d4a83413ccbac30790b50efb89a75e4f586ac0bb8056b", size = 8760837, upload-time = "2025-07-14T20:12:59.59Z" }, - { url = "https://files.pythonhosted.org/packages/9f/8a/1403d0353f8c5a2f0829d2b1c4becbf9da2f0a4d040886404fc4a5431e4d/pywin32-311-cp39-cp39-win_amd64.whl", hash = "sha256:e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91", size = 9590187, upload-time = "2025-07-14T20:13:01.419Z" }, - { url = "https://files.pythonhosted.org/packages/60/22/e0e8d802f124772cec9c75430b01a212f86f9de7546bda715e54140d5aeb/pywin32-311-cp39-cp39-win_arm64.whl", hash = "sha256:62ea666235135fee79bb154e695f3ff67370afefd71bd7fea7512fc70ef31e3d", size = 8778162, upload-time = "2025-07-14T20:13:03.544Z" }, ] [[package]] @@ -1317,15 +1205,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, - { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" }, - { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" }, - { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" }, - { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" }, - { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" }, - { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" }, - { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" }, - { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" }, ] [[package]] @@ -1333,9 +1212,9 @@ name = "referencing" version = "0.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs", marker = "python_full_version >= '3.10'" }, - { name = "rpds-py", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ @@ -1530,8 +1409,8 @@ name = "sse-starlette" version = "3.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "starlette", marker = "python_full_version >= '3.10'" }, + { name = "anyio" }, + { name = "starlette" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/34/f5df66cb383efdbf4f2db23cabb27f51b1dcb737efaf8a558f6f1d195134/sse_starlette-3.1.2.tar.gz", hash = "sha256:55eff034207a83a0eb86de9a68099bd0157838f0b8b999a1b742005c71e33618", size = 26303, upload-time = "2025-12-31T08:02:20.023Z" } wheels = [ @@ -1543,8 +1422,8 @@ name = "starlette" version = "0.50.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } wheels = [ @@ -1674,9 +1553,9 @@ name = "uvicorn" version = "0.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", marker = "python_full_version >= '3.10'" }, - { name = "h11", marker = "python_full_version >= '3.10'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } wheels = [