From 42c7a596409684e38042de2bcb922e54452ed445 Mon Sep 17 00:00:00 2001 From: Eduard van Valkenburg Date: Thu, 31 Jul 2025 17:04:22 +0200 Subject: [PATCH] Python: updated doc generation setup and some slight api enhancements (#267) * updated doc generation setup and some slight api enhancements * small fix in index --- .gitignore | 1 + python/docs/agent-framework/conf.py | 18 ++- python/docs/agent-framework/index.md | 5 +- .../docs/agent-framework/reference/index.md | 2 + .../python/agent_framework.azure.rst | 4 + .../python/agent_framework.exceptions.rst | 5 +- .../python/agent_framework.foundry.rst | 4 + .../python/agent_framework.openai.rst | 4 + .../reference/python/agent_framework.rst | 5 - .../azure/agent_framework_azure/__init__.py | 2 + .../agent_framework_azure/_chat_client.py | 32 ++-- .../azure/agent_framework_azure/_shared.py | 146 +++++++++--------- .../azure/tests/test_azure_chat_client.py | 2 +- .../agent_framework_foundry/_chat_client.py | 20 +-- .../packages/main/agent_framework/__init__.py | 1 - .../packages/main/agent_framework/_clients.py | 13 +- .../main/agent_framework/_pydantic.py | 10 +- .../packages/main/agent_framework/_tools.py | 16 +- .../packages/main/agent_framework/_types.py | 37 +---- .../main/agent_framework/azure/__init__.py | 1 + .../main/agent_framework/azure/__init__.pyi | 2 + .../main/agent_framework/foundry/__init__.py | 2 +- .../main/agent_framework/foundry/__init__.pyi | 4 +- .../agent_framework/openai/_chat_client.py | 17 +- .../openai/_responses_client.py | 17 +- .../main/agent_framework/openai/_shared.py | 53 +++---- python/pyproject.toml | 3 +- python/uv.lock | 41 +---- 28 files changed, 216 insertions(+), 251 deletions(-) create mode 100644 python/docs/agent-framework/reference/python/agent_framework.azure.rst create mode 100644 python/docs/agent-framework/reference/python/agent_framework.foundry.rst create mode 100644 python/docs/agent-framework/reference/python/agent_framework.openai.rst diff --git a/.gitignore b/.gitignore index 372dbbeb94..362346380d 100644 --- a/.gitignore +++ b/.gitignore @@ -173,6 +173,7 @@ cython_debug/ # PyPI configuration file .pypirc +**/.DS_Store .DS_Store # Visual Studio 2015/2017 cache/options directory diff --git a/python/docs/agent-framework/conf.py b/python/docs/agent-framework/conf.py index f4b9564d5c..569499140b 100644 --- a/python/docs/agent-framework/conf.py +++ b/python/docs/agent-framework/conf.py @@ -15,6 +15,8 @@ from sphinx.application import Sphinx # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information import agent_framework +import agent_framework_foundry +import agent_framework_azure project = "agent_framework" copyright = "2025, Microsoft" @@ -35,6 +37,7 @@ sys.path.append(str(Path(".").resolve())) extensions = [ "sphinx.ext.napoleon", "sphinx.ext.autodoc", + "sphinx.ext.coverage", "sphinx.ext.autosummary", "sphinx.ext.todo", "sphinx.ext.viewcode", @@ -50,13 +53,16 @@ extensions = [ ] suppress_warnings = ["myst.header"] -napoleon_custom_sections = [("Returns", "params_style")] +# Napoleon settings +napoleon_google_docstring = True +napoleon_use_admonition_for_examples = False +napoleon_include_init_with_doc = True +napoleon_custom_sections = [("returns_style", "params_style")] templates_path = ["_templates"] -autoclass_content = "class" -# TODO: incldue all notebooks excluding those requiring remote API access. +# TODO: include all notebooks excluding those requiring remote API access. nb_execution_mode = "off" # Guides and tutorials must succeed. @@ -134,11 +140,15 @@ html_context = { "doc_path": "python/docs/agent-framework/", } +autoclass_content = "both" autodoc_default_options = { "members": True, + "member-order": "alphabetical", "undoc-members": True, + "show-inheritance": True, + "imported-members": True, } - +autodoc_pydantic_model_show_json = False autodoc_pydantic_model_show_config_summary = False autodoc_pydantic_model_show_json_error_strategy = "coerce" python_use_unqualified_type_names = True diff --git a/python/docs/agent-framework/index.md b/python/docs/agent-framework/index.md index ad61b6f714..ffa078acb5 100644 --- a/python/docs/agent-framework/index.md +++ b/python/docs/agent-framework/index.md @@ -76,8 +76,9 @@ Get Started Implementations of connectors and other external components for the Agent Framework. These extensions allow you to connect to various AI models, services, and tools, enhancing the capabilities of your agents. -* {py:class}`~agent-framework-openai` for using OpenAI models. -* {py:class}`~agent-framework-azure` for using Azure services. +* {py:mod}`~agent-framework.azure` for using Azure services. +* {py:mod}`~agent-framework.foundry` for using Foundry models. +* {py:mod}`~agent-framework.openai` for using OpenAI models. +++ ::: diff --git a/python/docs/agent-framework/reference/index.md b/python/docs/agent-framework/reference/index.md index bf306dea5d..f9642c8dcf 100644 --- a/python/docs/agent-framework/reference/index.md +++ b/python/docs/agent-framework/reference/index.md @@ -14,4 +14,6 @@ myst: python/agent_framework python/agent_framework.exceptions python/agent_framework.openai +python/agent_framework.azure +python/agent_framework.foundry ``` diff --git a/python/docs/agent-framework/reference/python/agent_framework.azure.rst b/python/docs/agent-framework/reference/python/agent_framework.azure.rst new file mode 100644 index 0000000000..9ca4738986 --- /dev/null +++ b/python/docs/agent-framework/reference/python/agent_framework.azure.rst @@ -0,0 +1,4 @@ +agent_framework.azure +========================== + +.. automodule:: agent_framework.azure diff --git a/python/docs/agent-framework/reference/python/agent_framework.exceptions.rst b/python/docs/agent-framework/reference/python/agent_framework.exceptions.rst index 2defab5b4a..7ee054fa05 100644 --- a/python/docs/agent-framework/reference/python/agent_framework.exceptions.rst +++ b/python/docs/agent-framework/reference/python/agent_framework.exceptions.rst @@ -2,7 +2,4 @@ agent_framework.exceptions ========================== .. automodule:: agent_framework.exceptions - :members: - :undoc-members: - :show-inheritance: - :member-order: bysource \ No newline at end of file + :member-order: bysource diff --git a/python/docs/agent-framework/reference/python/agent_framework.foundry.rst b/python/docs/agent-framework/reference/python/agent_framework.foundry.rst new file mode 100644 index 0000000000..5e92de23f5 --- /dev/null +++ b/python/docs/agent-framework/reference/python/agent_framework.foundry.rst @@ -0,0 +1,4 @@ +agent_framework.foundry +========================== + +.. automodule:: agent_framework.foundry diff --git a/python/docs/agent-framework/reference/python/agent_framework.openai.rst b/python/docs/agent-framework/reference/python/agent_framework.openai.rst new file mode 100644 index 0000000000..7f8a73ad6d --- /dev/null +++ b/python/docs/agent-framework/reference/python/agent_framework.openai.rst @@ -0,0 +1,4 @@ +agent_framework.openai +========================== + +.. automodule:: agent_framework.openai diff --git a/python/docs/agent-framework/reference/python/agent_framework.rst b/python/docs/agent-framework/reference/python/agent_framework.rst index 195634f509..e24c689456 100644 --- a/python/docs/agent-framework/reference/python/agent_framework.rst +++ b/python/docs/agent-framework/reference/python/agent_framework.rst @@ -2,8 +2,3 @@ agent_framework =============== .. automodule:: agent_framework - :members: - :undoc-members: - :imported-members: - :show-inheritance: - :member-order: groupwise diff --git a/python/packages/azure/agent_framework_azure/__init__.py b/python/packages/azure/agent_framework_azure/__init__.py index 2996ec5c5d..1763009dbc 100644 --- a/python/packages/azure/agent_framework_azure/__init__.py +++ b/python/packages/azure/agent_framework_azure/__init__.py @@ -4,6 +4,7 @@ import importlib.metadata from ._chat_client import AzureChatClient from ._entra_id_authentication import get_entra_auth_token +from ._shared import AzureOpenAISettings try: __version__ = importlib.metadata.version(__name__) @@ -12,6 +13,7 @@ except importlib.metadata.PackageNotFoundError: __all__ = [ "AzureChatClient", + "AzureOpenAISettings", "__version__", "get_entra_auth_token", ] diff --git a/python/packages/azure/agent_framework_azure/_chat_client.py b/python/packages/azure/agent_framework_azure/_chat_client.py index 7b50f81cdd..6093e34fbd 100644 --- a/python/packages/azure/agent_framework_azure/_chat_client.py +++ b/python/packages/azure/agent_framework_azure/_chat_client.py @@ -16,8 +16,8 @@ from agent_framework import ( TextContent, ) from agent_framework.exceptions import ServiceInitializationError -from agent_framework.openai import OpenAIModelTypes from agent_framework.openai._chat_client import OpenAIChatClientBase +from agent_framework.openai._shared import OpenAIModelTypes from openai.lib.azure import AsyncAzureADTokenProvider, AsyncAzureOpenAI from openai.types.chat.chat_completion import ChatCompletion, Choice from openai.types.chat.chat_completion_chunk import ChatCompletionChunk @@ -59,25 +59,25 @@ class AzureChatClient(AzureOpenAIConfigBase, OpenAIChatClientBase): """Initialize an AzureChatCompletion service. Args: - api_key (str | None): The optional api key. If provided, will override the value in the + api_key: The optional api key. If provided, will override the value in the env vars or .env file. - deployment_name (str | None): The optional deployment. If provided, will override the value + deployment_name: The optional deployment. If provided, will override the value (chat_deployment_name) in the env vars or .env file. - endpoint (str | None): The optional deployment endpoint. If provided will override the value + endpoint: The optional deployment endpoint. If provided will override the value in the env vars or .env file. - base_url (str | None): The optional deployment base_url. If provided will override the value + base_url: The optional deployment base_url. If provided will override the value in the env vars or .env file. - api_version (str | None): The optional deployment api version. If provided will override the value + api_version: The optional deployment api version. If provided will override the value in the env vars or .env file. - ad_token (str | None): The Azure Active Directory token. (Optional) - ad_token_provider (AsyncAzureADTokenProvider): The Azure Active Directory token provider. (Optional) - token_endpoint (str | None): The token endpoint to request an Azure token. (Optional) - default_headers (Mapping[str, str]): The default headers mapping of string keys to + ad_token: The Azure Active Directory token. (Optional) + ad_token_provider: The Azure Active Directory token provider. (Optional) + token_endpoint: The token endpoint to request an Azure token. (Optional) + default_headers: The default headers mapping of string keys to string values for HTTP requests. (Optional) - async_client (AsyncAzureOpenAI | None): An existing client to use. (Optional) - env_file_path (str | None): Use the environment settings file as a fallback to using env vars. - env_file_encoding (str | None): The encoding of the environment settings file, defaults to 'utf-8'. - instruction_role (str | None): The role to use for 'instruction' messages, for example, summarization + async_client: An existing client to use. (Optional) + env_file_path: Use the environment settings file as a fallback to using env vars. + env_file_encoding: The encoding of the environment settings file, defaults to 'utf-8'. + instruction_role: The role to use for 'instruction' messages, for example, summarization prompts could use `developer` or `system`. (Optional) """ try: @@ -120,7 +120,7 @@ class AzureChatClient(AzureOpenAIConfigBase, OpenAIChatClientBase): Args: settings: A dictionary of settings for the service. should contain keys: service_id, and optionally: - ad_auth, ad_token_provider, default_headers + ad_auth, ad_token_provider, default_headers """ return AzureChatClient( api_key=settings.get("api_key"), @@ -193,7 +193,7 @@ class AzureChatClient(AzureOpenAIConfigBase, OpenAIChatClientBase): return None # pragma: no cover @staticmethod - def split_message(message: "ChatResponse") -> ChatResponse: + def _split_message(message: "ChatResponse") -> ChatResponse: """Split an Azure On Your Data response into separate ChatMessages within the ChatResponse. If the message does not have three contents, and those three are one each of: diff --git a/python/packages/azure/agent_framework_azure/_shared.py b/python/packages/azure/agent_framework_azure/_shared.py index a43c96cc5b..3bf526313f 100644 --- a/python/packages/azure/agent_framework_azure/_shared.py +++ b/python/packages/azure/agent_framework_azure/_shared.py @@ -6,9 +6,9 @@ from collections.abc import Awaitable, Callable, Mapping from copy import copy from typing import Any, ClassVar, Final -from agent_framework import AFBaseSettings, HttpsUrl +from agent_framework._pydantic import AFBaseSettings, HttpsUrl from agent_framework.exceptions import ServiceInitializationError -from agent_framework.openai import OpenAIHandler, OpenAIModelTypes +from agent_framework.openai._shared import OpenAIHandler, OpenAIModelTypes from agent_framework.telemetry import USER_AGENT_KEY from openai.lib.azure import AsyncAzureOpenAI from pydantic import ConfigDict, SecretStr, validate_call @@ -30,75 +30,79 @@ class AzureOpenAISettings(AFBaseSettings): with the encoding 'utf-8'. If the settings are not found in the .env file, the settings are ignored; however, validation will fail alerting that the settings are missing. - Optional settings for prefix 'AZURE_OPENAI_' are: - - chat_deployment_name: str - The name of the Azure Chat deployment. This value - will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_CHAT_DEPLOYMENT_NAME) - - responses_deployment_name: str - The name of the Azure Responses deployment. This value - will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME) - - text_deployment_name: str - The name of the Azure Text deployment. This value - will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_TEXT_DEPLOYMENT_NAME) - - embedding_deployment_name: str - The name of the Azure Embedding deployment. This value - will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME) - - text_to_image_deployment_name: str - The name of the Azure Text to Image deployment. This - value will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_TEXT_TO_IMAGE_DEPLOYMENT_NAME) - - audio_to_text_deployment_name: str - The name of the Azure Audio to Text deployment. This - value will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_AUDIO_TO_TEXT_DEPLOYMENT_NAME) - - text_to_audio_deployment_name: str - The name of the Azure Text to Audio deployment. This - value will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_TEXT_TO_AUDIO_DEPLOYMENT_NAME) - - realtime_deployment_name: str - The name of the Azure Realtime deployment. This value - will correspond to the custom name you chose for your deployment - when you deployed a model. This value can be found under - Resource Management > Deployments in the Azure portal or, alternatively, - under Management > Deployments in Azure AI Foundry. - (Env var AZURE_OPENAI_REALTIME_DEPLOYMENT_NAME) - - api_key: SecretStr - The API key for the Azure deployment. This value can be - found in the Keys & Endpoint section when examining your resource in - the Azure portal. You can use either KEY1 or KEY2. - (Env var AZURE_OPENAI_API_KEY) - - base_url: HttpsUrl | None - base_url: The url of the Azure deployment. This value - can be found in the Keys & Endpoint section when examining - your resource from the Azure portal, the base_url consists of the endpoint, - followed by /openai/deployments/{deployment_name}/, - use endpoint if you only want to supply the endpoint. - (Env var AZURE_OPENAI_BASE_URL) - - endpoint: HttpsUrl - The endpoint of the Azure deployment. This value - can be found in the Keys & Endpoint section when examining - your resource from the Azure portal, the endpoint should end in openai.azure.com. - If both base_url and endpoint are supplied, base_url will be used. - (Env var AZURE_OPENAI_ENDPOINT) - - api_version: str | None - The API version to use. The default value is "2024-02-01". - (Env var AZURE_OPENAI_API_VERSION) - - token_endpoint: str - The token endpoint to use to retrieve the authentication token. - The default value is "https://cognitiveservices.azure.com/.default". - (Env var AZURE_OPENAI_TOKEN_ENDPOINT) + Attributes: + chat_deployment_name: The name of the Azure Chat deployment. This value + will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_CHAT_DEPLOYMENT_NAME) + responses_deployment_name: The name of the Azure Responses deployment. This value + will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME) + text_deployment_name: The name of the Azure Text deployment. This value + will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_TEXT_DEPLOYMENT_NAME) + embedding_deployment_name: The name of the Azure Embedding deployment. This value + will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME) + text_to_image_deployment_name: The name of the Azure Text to Image deployment. This + value will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_TEXT_TO_IMAGE_DEPLOYMENT_NAME) + audio_to_text_deployment_name: The name of the Azure Audio to Text deployment. This + value will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_AUDIO_TO_TEXT_DEPLOYMENT_NAME) + text_to_audio_deployment_name: The name of the Azure Text to Audio deployment. This + value will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_TEXT_TO_AUDIO_DEPLOYMENT_NAME) + realtime_deployment_name: The name of the Azure Realtime deployment. This value + will correspond to the custom name you chose for your deployment + when you deployed a model. This value can be found under + Resource Management > Deployments in the Azure portal or, alternatively, + under Management > Deployments in Azure AI Foundry. + (Env var AZURE_OPENAI_REALTIME_DEPLOYMENT_NAME) + api_key: The API key for the Azure deployment. This value can be + found in the Keys & Endpoint section when examining your resource in + the Azure portal. You can use either KEY1 or KEY2. + (Env var AZURE_OPENAI_API_KEY) + base_url: The url of the Azure deployment. This value + can be found in the Keys & Endpoint section when examining + your resource from the Azure portal, the base_url consists of the endpoint, + followed by /openai/deployments/{deployment_name}/, + use endpoint if you only want to supply the endpoint. + (Env var AZURE_OPENAI_BASE_URL) + endpoint: The endpoint of the Azure deployment. This value + can be found in the Keys & Endpoint section when examining + your resource from the Azure portal, the endpoint should end in openai.azure.com. + If both base_url and endpoint are supplied, base_url will be used. + (Env var AZURE_OPENAI_ENDPOINT) + api_version: The API version to use. The default value is "2024-02-01". + (Env var AZURE_OPENAI_API_VERSION) + token_endpoint: The token endpoint to use to retrieve the authentication token. + The default value is "https://cognitiveservices.azure.com/.default". + (Env var AZURE_OPENAI_TOKEN_ENDPOINT) + + Parameters: + env_file_path: The path to the .env file to load settings from. + env_file_encoding: The encoding of the .env file, defaults to 'utf-8'. """ env_prefix: ClassVar[str] = "AZURE_OPENAI_" diff --git a/python/packages/azure/tests/test_azure_chat_client.py b/python/packages/azure/tests/test_azure_chat_client.py index face9cbb13..a36ecedcd9 100644 --- a/python/packages/azure/tests/test_azure_chat_client.py +++ b/python/packages/azure/tests/test_azure_chat_client.py @@ -476,7 +476,7 @@ async def test_azure_on_your_data_split_messages( content = await azure_chat_client.get_response( messages=messages_in, ) - message = azure_chat_client.split_message(content) + message = azure_chat_client._split_message(content) assert len(content.messages) == 1 assert len(content.messages[0].contents) == 3 assert isinstance(content.messages[0].contents[0], FunctionCallContent) diff --git a/python/packages/foundry/agent_framework_foundry/_chat_client.py b/python/packages/foundry/agent_framework_foundry/_chat_client.py index 4a1994583f..a00a5358eb 100644 --- a/python/packages/foundry/agent_framework_foundry/_chat_client.py +++ b/python/packages/foundry/agent_framework_foundry/_chat_client.py @@ -7,7 +7,6 @@ from collections.abc import AsyncIterable, MutableMapping, MutableSequence from typing import Any, ClassVar from agent_framework import ( - AFBaseSettings, AIContents, AIFunction, ChatClientBase, @@ -28,6 +27,7 @@ from agent_framework import ( use_tool_calling, ) from agent_framework._clients import ai_function_to_json_schema_spec +from agent_framework._pydantic import AFBaseSettings from agent_framework.exceptions import ServiceInitializationError from agent_framework.telemetry import use_telemetry from azure.ai.agents.models import ( @@ -74,14 +74,16 @@ class FoundrySettings(AFBaseSettings): with the encoding 'utf-8'. If the settings are not found in the .env file, the settings are ignored; however, validation will fail alerting that the settings are missing. - Optional settings for prefix 'FOUNDRY_' are: - - project_endpoint: str | None - The Azure AI Foundry project endpoint URL. - (Env var FOUNDRY_PROJECT_ENDPOINT) - - model_deployment_name: str | None - The name of the model deployment to use. - (Env var FOUNDRY_MODEL_DEPLOYMENT_NAME) - - agent_name: str | None - Default name for automatically created agents. - (Env var FOUNDRY_AGENT_NAME) - - env_file_path: str | None - if provided, the .env settings are read from this file path location + Attributes: + project_endpoint: The Azure AI Foundry project endpoint URL. + (Env var FOUNDRY_PROJECT_ENDPOINT) + model_deployment_name: The name of the model deployment to use. + (Env var FOUNDRY_MODEL_DEPLOYMENT_NAME) + agent_name: Default name for automatically created agents. + (Env var FOUNDRY_AGENT_NAME) + Parameters: + env_file_path: If provided, the .env settings are read from this file path location. + env_file_encoding: The encoding of the .env file, defaults to 'utf-8'. """ env_prefix: ClassVar[str] = "FOUNDRY_" diff --git a/python/packages/main/agent_framework/__init__.py b/python/packages/main/agent_framework/__init__.py index 0a3dcbfd7c..2e2734f47c 100644 --- a/python/packages/main/agent_framework/__init__.py +++ b/python/packages/main/agent_framework/__init__.py @@ -11,6 +11,5 @@ except importlib.metadata.PackageNotFoundError: from ._agents import * # noqa: F403 from ._clients import * # noqa: F403 from ._logging import * # noqa: F403 -from ._pydantic import * # noqa: F403 from ._tools import * # noqa: F403 from ._types import * # noqa: F403 diff --git a/python/packages/main/agent_framework/_clients.py b/python/packages/main/agent_framework/_clients.py index 05e40a9158..4f37e0f516 100644 --- a/python/packages/main/agent_framework/_clients.py +++ b/python/packages/main/agent_framework/_clients.py @@ -225,22 +225,21 @@ def use_tool_calling(cls: type[TChatClientBase]) -> type[TChatClientBase]: Remarks: This only works on classes that derive from ChatClientBase - and the _inner_get_response - and _inner_get_streaming_response methods. - It also sets a __maximum_iterations_per_request attribute on the class. + and the `_inner_get_response` + and `_inner_get_streaming_response` methods. + It also sets a `__maximum_iterations_per_request` attribute on the class. if you want to expose this to end_users, do a version of this: - ```python - @use_tool_calling - class MyChatClient(ChatClientBase): @property + def maximum_iterations_per_request(self): return getattr(self, "__maximum_iterations_per_request", 10) @maximum_iterations_per_request.setter + def maximum_iterations_per_request(self, value: int) -> None: setattr(self, "__maximum_iterations_per_request", value) - ``` + """ setattr(cls, "__maximum_iterations_per_request", 10) diff --git a/python/packages/main/agent_framework/_pydantic.py b/python/packages/main/agent_framework/_pydantic.py index 3504abb778..3a70bdf3c6 100644 --- a/python/packages/main/agent_framework/_pydantic.py +++ b/python/packages/main/agent_framework/_pydantic.py @@ -29,11 +29,11 @@ class AFBaseSettings(BaseSettings): In the case where a value is specified for the same Settings field in multiple ways, the selected value is determined as follows (in descending order of priority): - - Arguments passed to the Settings class initializer. - - Environment variables, e.g. my_prefix_special_function as described above. - - Variables loaded from a dotenv (.env) file. - - Variables loaded from the secrets directory. - - The default field values for the Settings model. + - Arguments passed to the Settings class initializer. + - Environment variables, e.g. my_prefix_special_function as described above. + - Variables loaded from a dotenv (.env) file. + - Variables loaded from the secrets directory. + - The default field values for the Settings model. """ env_prefix: ClassVar[str] = "" diff --git a/python/packages/main/agent_framework/_tools.py b/python/packages/main/agent_framework/_tools.py index eb72c21033..a24b48d2f7 100644 --- a/python/packages/main/agent_framework/_tools.py +++ b/python/packages/main/agent_framework/_tools.py @@ -146,15 +146,17 @@ def ai_function( ) -> AIFunction[Any, ReturnT]: """Decorate a function to turn it into a AIFunction that can be passed to models and executed automatically. - Remarks: - In order to add descriptions to parameters, use: + This function will create a Pydantic model from the function's signature, + which will be used to validate the arguments passed to the function. + And will be used to generate the JSON schema for the function's parameters. + In order to add descriptions to parameters, in your function signature, + use the `Annotated` type from `typing` and the `Field` class from `pydantic`: - ```python - from typing import Annotated - from pydantic import Field + from typing import Annotated - arg: Annotated[, Field(description="")] - ``` + from pydantic import Field + + : Annotated[, Field(description="")] Args: func: The function to wrap. If None, returns a decorator. diff --git a/python/packages/main/agent_framework/_types.py b/python/packages/main/agent_framework/_types.py index 8854b191ba..40aa63bc66 100644 --- a/python/packages/main/agent_framework/_types.py +++ b/python/packages/main/agent_framework/_types.py @@ -312,9 +312,7 @@ class AIContent(AFBaseModel): type: Literal["ai"] = "ai" additional_properties: dict[str, Any] | None = None - """Additional properties for the content.""" raw_representation: Any | None = Field(default=None, repr=False) - """The raw representation of the content from an underlying implementation.""" class TextContent(AIContent): @@ -367,7 +365,9 @@ class TextReasoningContent(AIContent): raw_representation: Optional raw representation of the content. - """ # TODO(): Should we merge these two classes, and use a property to distinguish them? + """ + + # TODO(eavanvalkenburg): Should we merge these two classes, and use a property to distinguish them? text: str type: Literal["text_reasoning"] = "text_reasoning" # type: ignore[assignment] @@ -536,9 +536,7 @@ class UriContent(AIContent): type: Literal["uri"] = "uri" # type: ignore[assignment] uri: str - """The URI of the content, e.g., 'https://example.com/image.png'.""" media_type: str - """The media type of the content, e.g., 'image/png', 'application/json', etc.""" def __init__( self, @@ -604,11 +602,8 @@ class ErrorContent(AIContent): type: Literal["error"] = "error" # type: ignore[assignment] error_code: str | None = None - """The error code associated with the error.""" details: str | None = None - """Additional details about the error.""" message: str | None - """The error message.""" def __init__( self, @@ -660,13 +655,9 @@ class FunctionCallContent(AIContent): type: Literal["function_call"] = "function_call" # type: ignore[assignment] call_id: str - """The function call identifier.""" name: str - """The name of the function requested.""" arguments: str | dict[str, Any | None] | None = None - """The arguments requested to be provided to the function.""" exception: Exception | None = None - """Any exception that occurred while mapping the original function call data to this representation.""" def __init__( self, @@ -753,11 +744,8 @@ class FunctionResultContent(AIContent): type: Literal["function_result"] = "function_result" # type: ignore[assignment] call_id: str - """The identifier of the function call for which this is the result.""" result: Any | None = None - """The result of the function call, or a generic error message if the function call failed.""" exception: Exception | None = None - """An exception that occurred if the function call failed.""" def __init__( self, @@ -802,7 +790,6 @@ class UsageContent(AIContent): type: Literal["usage"] = "usage" # type: ignore[assignment] details: UsageDetails - """The usage information.""" def __init__( self, @@ -812,14 +799,7 @@ class UsageContent(AIContent): raw_representation: Any | None = None, **kwargs: Any, ) -> None: - """Initializes a UsageContent instance. - - Args: - details: The usage information. - additional_properties: Optional additional properties associated with the content. - raw_representation: Optional raw representation of the content. - **kwargs: Any additional keyword arguments. - """ + """Initializes a UsageContent instance.""" super().__init__( details=details, # type: ignore[reportCallIssue] raw_representation=raw_representation, @@ -890,15 +870,6 @@ class ChatFinishReason(AFBaseModel): Attributes: value: The string representation of the finish reason. - - Properties: - CONTENT_FILTER: The model filtered content, whether for safety, prohibited content, sensitive content, - or other such issues. - LENGTH: The model reached the maximum length allowed for the request and/or response (typically in - terms of tokens). - STOP: The model encountered a natural stop point or provided stop sequence. - TOOL_CALLS: The model requested the use of a tool that was defined in the request. - """ value: str diff --git a/python/packages/main/agent_framework/azure/__init__.py b/python/packages/main/agent_framework/azure/__init__.py index 47e9bde750..4d603b2daf 100644 --- a/python/packages/main/agent_framework/azure/__init__.py +++ b/python/packages/main/agent_framework/azure/__init__.py @@ -7,6 +7,7 @@ PACKAGE_NAME = "agent_framework_azure" PACKAGE_EXTRA = "azure" _IMPORTS = [ "AzureChatClient", + "AzureOpenAISettings", "get_entra_auth_token", "__version__", ] diff --git a/python/packages/main/agent_framework/azure/__init__.pyi b/python/packages/main/agent_framework/azure/__init__.pyi index a3a22bee99..ddee59e59d 100644 --- a/python/packages/main/agent_framework/azure/__init__.pyi +++ b/python/packages/main/agent_framework/azure/__init__.pyi @@ -2,12 +2,14 @@ from agent_framework_azure import ( AzureChatClient, + AzureOpenAISettings, __version__, get_entra_auth_token, ) __all__ = [ "AzureChatClient", + "AzureOpenAISettings", "__version__", "get_entra_auth_token", ] diff --git a/python/packages/main/agent_framework/foundry/__init__.py b/python/packages/main/agent_framework/foundry/__init__.py index 91f46f0db3..671b4d7857 100644 --- a/python/packages/main/agent_framework/foundry/__init__.py +++ b/python/packages/main/agent_framework/foundry/__init__.py @@ -5,7 +5,7 @@ from typing import Any PACKAGE_NAME = "agent_framework_foundry" PACKAGE_EXTRA = "foundry" -_IMPORTS = ["__version__", "FoundryChatClient"] +_IMPORTS = ["__version__", "FoundryChatClient", "FoundrySettings"] def __getattr__(name: str) -> Any: diff --git a/python/packages/main/agent_framework/foundry/__init__.pyi b/python/packages/main/agent_framework/foundry/__init__.pyi index 9593f889fb..bed6035918 100644 --- a/python/packages/main/agent_framework/foundry/__init__.pyi +++ b/python/packages/main/agent_framework/foundry/__init__.pyi @@ -1,5 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. -from agent_framework_foundry import FoundryChatClient, __version__ +from agent_framework_foundry import FoundryChatClient, FoundrySettings, __version__ -__all__ = ["FoundryChatClient", "__version__"] +__all__ = ["FoundryChatClient", "FoundrySettings", "__version__"] diff --git a/python/packages/main/agent_framework/openai/_chat_client.py b/python/packages/main/agent_framework/openai/_chat_client.py index d59e1a025e..31b870092f 100644 --- a/python/packages/main/agent_framework/openai/_chat_client.py +++ b/python/packages/main/agent_framework/openai/_chat_client.py @@ -286,26 +286,27 @@ class OpenAIChatClient(OpenAIConfigBase, OpenAIChatClientBase): org_id: str | None = None, default_headers: Mapping[str, str] | None = None, async_client: AsyncOpenAI | None = None, + instruction_role: str | None = None, env_file_path: str | None = None, env_file_encoding: str | None = None, - instruction_role: str | None = None, ) -> None: """Initialize an OpenAIChatCompletion service. Args: - ai_model_id (str): OpenAI model name, see + ai_model_id: OpenAI model name, see https://platform.openai.com/docs/models - api_key (str | None): The optional API key to use. If provided will override, + api_key: The optional API key to use. If provided will override, the env vars or .env file value. - org_id (str | None): The optional org ID to use. If provided will override, + org_id: The optional org ID to use. If provided will override, the env vars or .env file value. default_headers: The default headers mapping of string keys to string values for HTTP requests. (Optional) - async_client (Optional[AsyncOpenAI]): An existing client to use. (Optional) - env_file_path (str | None): Use the environment settings file as a fallback + async_client: An existing client to use. (Optional) + instruction_role: The role to use for 'instruction' messages, for example, + "system" or "developer". If not provided, the default is "system". + env_file_path: Use the environment settings file as a fallback to environment variables. (Optional) - env_file_encoding (str | None): The encoding of the environment settings file. (Optional) - instruction_role (str | None): The role to use for 'instruction' messages, for example, + env_file_encoding: The encoding of the environment settings file. (Optional) """ try: openai_settings = OpenAISettings( diff --git a/python/packages/main/agent_framework/openai/_responses_client.py b/python/packages/main/agent_framework/openai/_responses_client.py index 8b678a213a..ccbc342cc1 100644 --- a/python/packages/main/agent_framework/openai/_responses_client.py +++ b/python/packages/main/agent_framework/openai/_responses_client.py @@ -66,26 +66,27 @@ class OpenAIResponsesClient(OpenAIConfigBase, ChatClientBase, OpenAIHandler): org_id: str | None = None, default_headers: Mapping[str, str] | None = None, async_client: AsyncOpenAI | None = None, + instruction_role: str | None = None, env_file_path: str | None = None, env_file_encoding: str | None = None, - instruction_role: str | None = None, ) -> None: """Initialize an OpenAIChatCompletion service. Args: - ai_model_id (str): OpenAI model name, see + ai_model_id: OpenAI model name, see https://platform.openai.com/docs/models - api_key (str | None): The optional API key to use. If provided will override, + api_key: The optional API key to use. If provided will override, the env vars or .env file value. - org_id (str | None): The optional org ID to use. If provided will override, + org_id: The optional org ID to use. If provided will override, the env vars or .env file value. default_headers: The default headers mapping of string keys to string values for HTTP requests. (Optional) - async_client (Optional[AsyncOpenAI]): An existing client to use. (Optional) - env_file_path (str | None): Use the environment settings file as a fallback + async_client: An existing client to use. (Optional) + instruction_role: The role to use for 'instruction' messages, for example, + "system" or "developer". If not provided, the default is "system". + env_file_path: Use the environment settings file as a fallback to environment variables. (Optional) - env_file_encoding (str | None): The encoding of the environment settings file. (Optional) - instruction_role (str | None): The role to use for 'instruction' messages, for example, + env_file_encoding: The encoding of the environment settings file. (Optional) """ try: openai_settings = OpenAISettings( diff --git a/python/packages/main/agent_framework/openai/_shared.py b/python/packages/main/agent_framework/openai/_shared.py index 8567f44ecc..5e922d69d7 100644 --- a/python/packages/main/agent_framework/openai/_shared.py +++ b/python/packages/main/agent_framework/openai/_shared.py @@ -54,43 +54,44 @@ OPTION_TYPE = Union[ __all__ = [ - "OpenAIHandler", - "OpenAIModelTypes", "OpenAISettings", ] class OpenAISettings(AFBaseSettings): - """OpenAI model settings. + """OpenAI environment settings. The settings are first loaded from environment variables with the prefix 'OPENAI_'. If the environment variables are not found, the settings can be loaded from a .env file with the encoding 'utf-8'. If the settings are not found in the .env file, the settings are ignored; however, validation will fail alerting that the settings are missing. - Optional settings for prefix 'OPENAI_' are: - - api_key: SecretStr - OpenAI API key, see https://platform.openai.com/account/api-keys - (Env var OPENAI_API_KEY) - - org_id: str | None - This is usually optional unless your account belongs to multiple organizations. - (Env var OPENAI_ORG_ID) - - chat_model_id: str | None - The OpenAI chat model ID to use, for example, gpt-3.5-turbo or gpt-4. - (Env var OPENAI_CHAT_MODEL_ID) - - responses_model_id: str | None - The OpenAI responses model ID to use, for example, gpt-4o or o1. - (Env var OPENAI_RESPONSES_MODEL_ID) - - text_model_id: str | None - The OpenAI text model ID to use, for example, gpt-3.5-turbo-instruct. - (Env var OPENAI_TEXT_MODEL_ID) - - embedding_model_id: str | None - The OpenAI embedding model ID to use, for example, text-embedding-ada-002. - (Env var OPENAI_EMBEDDING_MODEL_ID) - - text_to_image_model_id: str | None - The OpenAI text to image model ID to use, for example, dall-e-3. - (Env var OPENAI_TEXT_TO_IMAGE_MODEL_ID) - - audio_to_text_model_id: str | None - The OpenAI audio to text model ID to use, for example, whisper-1. - (Env var OPENAI_AUDIO_TO_TEXT_MODEL_ID) - - text_to_audio_model_id: str | None - The OpenAI text to audio model ID to use, for example, jukebox-1. - (Env var OPENAI_TEXT_TO_AUDIO_MODEL_ID) - - realtime_model_id: str | None - The OpenAI realtime model ID to use, - for example, gpt-4o-realtime-preview-2024-12-17. - (Env var OPENAI_REALTIME_MODEL_ID) - - env_file_path: str | None - if provided, the .env settings are read from this file path location + Attributes: + api_key: OpenAI API key, see https://platform.openai.com/account/api-keys + (Env var OPENAI_API_KEY) + org_id: This is usually optional unless your account belongs to multiple organizations. + (Env var OPENAI_ORG_ID) + chat_model_id: The OpenAI chat model ID to use, for example, gpt-3.5-turbo or gpt-4. + (Env var OPENAI_CHAT_MODEL_ID) + responses_model_id: The OpenAI responses model ID to use, for example, gpt-4o or o1. + (Env var OPENAI_RESPONSES_MODEL_ID) + text_model_id: The OpenAI text model ID to use, for example, gpt-3.5-turbo-instruct. + (Env var OPENAI_TEXT_MODEL_ID) + embedding_model_id: The OpenAI embedding model ID to use, for example, text-embedding-ada-002. + (Env var OPENAI_EMBEDDING_MODEL_ID) + text_to_image_model_id: The OpenAI text to image model ID to use, for example, dall-e-3. + (Env var OPENAI_TEXT_TO_IMAGE_MODEL_ID) + audio_to_text_model_id: The OpenAI audio to text model ID to use, for example, whisper-1. + (Env var OPENAI_AUDIO_TO_TEXT_MODEL_ID) + text_to_audio_model_id: The OpenAI text to audio model ID to use, for example, jukebox-1. + (Env var OPENAI_TEXT_TO_AUDIO_MODEL_ID) + realtime_model_id: The OpenAI realtime model ID to use, + for example, gpt-4o-realtime-preview-2024-12-17. + (Env var OPENAI_REALTIME_MODEL_ID) + + Parameters: + env_file_path: The path to the .env file to load settings from. + env_file_encoding: The encoding of the .env file, defaults to 'utf-8'. """ env_prefix: ClassVar[str] = "OPENAI_" diff --git a/python/pyproject.toml b/python/pyproject.toml index 2ee0a1e95d..a9f9149390 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -33,8 +33,7 @@ dev = [ "sphinx-copybutton", "sphinx-design", "sphinx", - "sphinxcontrib-apidoc", - "autodoc_pydantic~=2.2", + "autodoc_pydantic>=2", "pygments", "sphinxext-rediraffe", "opentelemetry-instrumentation-openai", diff --git a/python/uv.lock b/python/uv.lock index e015c2d749..147d098f23 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -140,7 +140,6 @@ dev = [ { name = "sphinx-autobuild", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "sphinx-copybutton", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "sphinx-design", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, - { name = "sphinxcontrib-apidoc", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "sphinxext-rediraffe", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "tomli", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "tomli-w", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -156,7 +155,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "autodoc-pydantic", specifier = "~=2.2" }, + { name = "autodoc-pydantic", specifier = ">=2" }, { name = "diskcache" }, { name = "markdown-it-py", extras = ["linkify"] }, { name = "markdownify" }, @@ -180,7 +179,6 @@ dev = [ { name = "sphinx-autobuild" }, { name = "sphinx-copybutton" }, { name = "sphinx-design" }, - { name = "sphinxcontrib-apidoc" }, { name = "sphinxext-rediraffe" }, { name = "tomli" }, { name = "tomli-w" }, @@ -844,7 +842,7 @@ name = "exceptiongroup" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "(python_full_version < '3.13' and sys_platform == 'darwin') or (python_full_version < '3.13' and sys_platform == 'linux') or (python_full_version < '3.13' and sys_platform == 'win32')" }, + { name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } wheels = [ @@ -1922,18 +1920,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] -[[package]] -name = "pbr" -version = "6.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "setuptools", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/01/d2/510cc0d218e753ba62a1bc1434651db3cd797a9716a0a66cc714cb4f0935/pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b", size = 125702, upload-time = "2025-02-04T14:28:06.514Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997, upload-time = "2025-02-04T14:28:03.168Z" }, -] - [[package]] name = "pexpect" version = "4.9.0" @@ -2814,15 +2800,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/02/8857d0dfb8f44ef299a5dfd898f673edefb71e3b533b3b9d2db4c832dd13/ruff-0.12.4-py3-none-win_arm64.whl", hash = "sha256:0618ec4442a83ab545e5b71202a5c0ed7791e8471435b94e655b570a5031a98e", size = 10469336, upload-time = "2025-07-17T17:27:16.913Z" }, ] -[[package]] -name = "setuptools" -version = "80.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, -] - [[package]] name = "six" version = "1.17.0" @@ -2969,20 +2946,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338, upload-time = "2024-08-02T13:48:42.106Z" }, ] -[[package]] -name = "sphinxcontrib-apidoc" -version = "0.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pbr", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1c/8d/161842a1c199c1baed5f5bc0765a59a791324f962fea3b604f105c9493e7/sphinxcontrib_apidoc-0.6.0.tar.gz", hash = "sha256:329b9810d66988f48e127a6bd18cc8efbbd1cd20b8deb4691a35738af49ad88d", size = 16790, upload-time = "2025-05-08T12:55:44.463Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/ac/6b94ecdca590ad0596b83d78277f89d897539a6cfdc997d62f27651540bc/sphinxcontrib_apidoc-0.6.0-py3-none-any.whl", hash = "sha256:668592f933eee858f3bc0d0810d56d50dfa0a70f650a2faaaad501b9a3504633", size = 8765, upload-time = "2025-05-08T12:55:42.733Z" }, -] - [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0"