From 4b3ec54f060ec4361a0e80c0fe1813e87b948482 Mon Sep 17 00:00:00 2001 From: Jens Scheffler Date: Sat, 23 May 2026 23:12:48 +0200 Subject: [PATCH] Replace Sphinx Redoc with Swagger API Docs --- airflow-core/docs/.gitignore | 1 + airflow-core/docs/conf.py | 38 +++------- .../auth-manager/simple/sam-token-api-ref.rst | 6 +- airflow-core/docs/stable-rest-api-ref.rst | 10 ++- airflow-ctl/docs/conf.py | 7 -- devel-common/pyproject.toml | 5 +- devel-common/sphinx_design/.gitignore | 1 + devel-common/src/docs/provider_conf.py | 76 +++++-------------- devel-common/src/docs/utils/conf_constants.py | 37 +++++++-- providers/edge3/docs/edge-api-ref.rst | 25 ++++++ providers/edge3/docs/index.rst | 1 + providers/fab/docs/api-ref/fab-api-ref.rst | 5 +- .../keycloak/docs/api-ref/token-api-ref.rst | 5 +- uv.lock | 39 +++++----- 14 files changed, 125 insertions(+), 131 deletions(-) create mode 100644 devel-common/sphinx_design/.gitignore create mode 100644 providers/edge3/docs/edge-api-ref.rst diff --git a/airflow-core/docs/.gitignore b/airflow-core/docs/.gitignore index 69e1d56a72377..d4a3c7b923459 100644 --- a/airflow-core/docs/.gitignore +++ b/airflow-core/docs/.gitignore @@ -2,3 +2,4 @@ /logs /plugins /.env +static/mirrored diff --git a/airflow-core/docs/conf.py b/airflow-core/docs/conf.py index 71e2b0cd06aeb..e24044690aafa 100644 --- a/airflow-core/docs/conf.py +++ b/airflow-core/docs/conf.py @@ -37,12 +37,14 @@ AUTOAPI_OPTIONS, BASIC_AUTOAPI_IGNORE_PATTERNS, BASIC_SPHINX_EXTENSIONS, - REDOC_SCRIPT_URL, SMARTQUOTES_EXCLUDES, SPELLING_WORDLIST_PATH, SPHINX_DESIGN_STATIC_PATH, - SPHINX_REDOC_EXTENSIONS, + SPHINX_SWAGGER_EXTENSION, SUPPRESS_WARNINGS, + SWAGGER_BUNDLE_URI, + SWAGGER_CSS_URI, + SWAGGER_PRESENT_URI, filter_autoapi_ignore_entries, get_autodoc_mock_imports, get_configs_and_deprecations, @@ -53,13 +55,12 @@ get_intersphinx_mapping, get_rst_epilogue, get_rst_filepath_from_path, + mirror_artifact_locally, skip_util_classes_extension, ) from packaging.version import Version, parse as parse_version import airflow -from airflow.api_fastapi.auth.managers.simple.openapi import __file__ as sam_openapi_file -from airflow.api_fastapi.core_api.openapi import __file__ as main_openapi_file from airflow.configuration import retrieve_configuration_description PACKAGE_NAME = "apache-airflow" @@ -91,11 +92,11 @@ # ones. extensions = BASIC_SPHINX_EXTENSIONS -# -- Options for sphinxcontrib.redoc ------------------------------------------- -# See: https://sphinxcontrib-redoc.readthedocs.io/en/stable/ +extensions.append(SPHINX_SWAGGER_EXTENSION) -extensions.extend(SPHINX_REDOC_EXTENSIONS) -redoc_script_url = REDOC_SCRIPT_URL +swagger_present_uri = mirror_artifact_locally(SWAGGER_PRESENT_URI, Path(__file__).parent) +swagger_bundle_uri = mirror_artifact_locally(SWAGGER_BUNDLE_URI, Path(__file__).parent) +swagger_css_uri = mirror_artifact_locally(SWAGGER_CSS_URI, Path(__file__).parent) extensions.extend( [ @@ -357,27 +358,6 @@ def add_airflow_core_exclude_patterns_to_sphinx(exclude_patterns: list[str]): graphviz_output_format = "svg" -main_openapi_path = Path(main_openapi_file).parent.joinpath("v2-rest-api-generated.yaml") -sam_openapi_path = Path(sam_openapi_file).parent.joinpath("v2-simple-auth-manager-generated.yaml") -redoc = [ - { - "name": "Simple auth manager token API", - "page": "core-concepts/auth-manager/simple/sam-token-api-ref", - "spec": sam_openapi_path.as_posix(), - "opts": { - "hide-hostname": True, - }, - }, - { - "name": "Airflow REST API", - "page": "stable-rest-api-ref", - "spec": main_openapi_path.as_posix(), - "opts": { - "hide-hostname": True, - }, - }, -] - def setup(sphinx): sphinx.connect("autoapi-skip-member", skip_util_classes_extension) diff --git a/airflow-core/docs/core-concepts/auth-manager/simple/sam-token-api-ref.rst b/airflow-core/docs/core-concepts/auth-manager/simple/sam-token-api-ref.rst index 02fd335086d10..518e6e9744948 100644 --- a/airflow-core/docs/core-concepts/auth-manager/simple/sam-token-api-ref.rst +++ b/airflow-core/docs/core-concepts/auth-manager/simple/sam-token-api-ref.rst @@ -19,5 +19,7 @@ Simple auth manager token API ============================= -It's a stub file. It will be converted automatically during the build process -to the valid documentation by the Sphinx plugin. See: /docs/conf.py +.. swagger-plugin:: ../../../../src/airflow/api_fastapi/auth/managers/simple/openapi/v2-simple-auth-manager-generated.yaml + :id: sam-token-api-ref + :page-title: Simple auth manager token API + :swagger-options: { "tryItOutEnabled": "false", "supportedSubmitMethods": [] } diff --git a/airflow-core/docs/stable-rest-api-ref.rst b/airflow-core/docs/stable-rest-api-ref.rst index a02e89b5a59de..bde135f3ec77f 100644 --- a/airflow-core/docs/stable-rest-api-ref.rst +++ b/airflow-core/docs/stable-rest-api-ref.rst @@ -16,8 +16,10 @@ specific language governing permissions and limitations under the License. -Airflow public API reference -============================ +Airflow public REST API reference +================================= -It's a stub file. It will be converted automatically during the build process -to the valid documentation by the Sphinx plugin. See: airflow-core/docs/conf.py +.. swagger-plugin:: ../src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml + :id: core-rest-api-ref + :page-title: Airflow public REST API + :swagger-options: { "tryItOutEnabled": "false", "supportedSubmitMethods": [] } diff --git a/airflow-ctl/docs/conf.py b/airflow-ctl/docs/conf.py index 5a19b2adea3e6..055de186d3ef2 100644 --- a/airflow-ctl/docs/conf.py +++ b/airflow-ctl/docs/conf.py @@ -33,11 +33,9 @@ AUTOAPI_OPTIONS, BASIC_AUTOAPI_IGNORE_PATTERNS, BASIC_SPHINX_EXTENSIONS, - REDOC_SCRIPT_URL, SMARTQUOTES_EXCLUDES, SPELLING_WORDLIST_PATH, SPHINX_DESIGN_STATIC_PATH, - SPHINX_REDOC_EXTENSIONS, SUPPRESS_WARNINGS, filter_autoapi_ignore_entries, get_autodoc_mock_imports, @@ -88,11 +86,6 @@ # ones. extensions = BASIC_SPHINX_EXTENSIONS -# -- Options for sphinxcontrib.redoc ------------------------------------------- -# See: https://sphinxcontrib-redoc.readthedocs.io/en/stable/ - -extensions.extend(SPHINX_REDOC_EXTENSIONS) -redoc_script_url = REDOC_SCRIPT_URL extensions.extend( [ diff --git a/devel-common/pyproject.toml b/devel-common/pyproject.toml index ab8b265bd1448..b503fff551122 100644 --- a/devel-common/pyproject.toml +++ b/devel-common/pyproject.toml @@ -97,12 +97,9 @@ dependencies = [ "sphinxcontrib-jquery>=4.1", "sphinxcontrib-jsmath>=1.0.1", "sphinxcontrib-qthelp>=1.0.3", - "sphinxcontrib-redoc>=1.6.0", "sphinxcontrib-serializinghtml>=1.1.5", "sphinxcontrib-spelling>=8.0.0", - # setuptools 82.0.0+ causes redoc to fail due to pkg_resources removal - # until https://github.com/sphinx-contrib/redoc/issues/53 is resolved - "setuptools<82.0.0", + "swagger-plugin-for-sphinx>=7.0.0", ] "docs-gen" = [ "diagrams>=0.24.4", diff --git a/devel-common/sphinx_design/.gitignore b/devel-common/sphinx_design/.gitignore new file mode 100644 index 0000000000000..e292e5f713f8a --- /dev/null +++ b/devel-common/sphinx_design/.gitignore @@ -0,0 +1 @@ +static/mirrored diff --git a/devel-common/src/docs/provider_conf.py b/devel-common/src/docs/provider_conf.py index 6bc9da15f5f61..785ce042999ed 100644 --- a/devel-common/src/docs/provider_conf.py +++ b/devel-common/src/docs/provider_conf.py @@ -33,7 +33,6 @@ # serve to show the default. import logging import os -from pathlib import Path from typing import Any import rich @@ -47,11 +46,14 @@ AUTOAPI_OPTIONS, BASIC_AUTOAPI_IGNORE_PATTERNS, BASIC_SPHINX_EXTENSIONS, - REDOC_SCRIPT_URL, SMARTQUOTES_EXCLUDES, SPELLING_WORDLIST_PATH, SPHINX_DESIGN_STATIC_PATH, + SPHINX_SWAGGER_EXTENSION, SUPPRESS_WARNINGS, + SWAGGER_BUNDLE_URI, + SWAGGER_CSS_URI, + SWAGGER_PRESENT_URI, filter_autoapi_ignore_entries, get_autodoc_mock_imports, get_configs_and_deprecations, @@ -61,6 +63,7 @@ get_html_theme_options, get_intersphinx_mapping, get_rst_epilogue, + mirror_artifact_locally, ) from sphinx_exts.provider_yaml_utils import load_package_data @@ -119,25 +122,21 @@ # ones. extensions = BASIC_SPHINX_EXTENSIONS -PROVIDER_PACKAGES_WITH_REDOC = ["apache-airflow-providers-fab", "apache-airflow-providers-keycloak"] - -if PACKAGE_NAME in PROVIDER_PACKAGES_WITH_REDOC: - extensions.extend( - [ - "autoapi.extension", - # First, generate redoc - "sphinxcontrib.redoc", - # Second, update redoc script - "sphinx_script_update", - ] - ) - redoc_script_url = REDOC_SCRIPT_URL -else: - extensions.extend( - [ - "autoapi.extension", - ] - ) +PROVIDER_PACKAGES_WITH_API_REFERENCE = [ + "apache-airflow-providers-edge3", + "apache-airflow-providers-fab", + "apache-airflow-providers-keycloak", +] + +if PACKAGE_NAME in PROVIDER_PACKAGES_WITH_API_REFERENCE: + extensions.append(SPHINX_SWAGGER_EXTENSION) + _DOCS_TARGET_ROOT_PATH = SPHINX_DESIGN_STATIC_PATH.parent + + swagger_present_uri = mirror_artifact_locally(SWAGGER_PRESENT_URI, _DOCS_TARGET_ROOT_PATH) + swagger_bundle_uri = mirror_artifact_locally(SWAGGER_BUNDLE_URI, _DOCS_TARGET_ROOT_PATH) + swagger_css_uri = mirror_artifact_locally(SWAGGER_CSS_URI, _DOCS_TARGET_ROOT_PATH) + +extensions.append("autoapi.extension") extensions.extend( [ @@ -357,38 +356,3 @@ spelling_ignore_importable_modules = True graphviz_output_format = "svg" - -if PACKAGE_NAME in PROVIDER_PACKAGES_WITH_REDOC: - from airflow.providers.fab.auth_manager.api_fastapi.openapi import ( - __file__ as fab_auth_manager_fastapi_api_file, - ) - from airflow.providers.keycloak.auth_manager.openapi import ( - __file__ as keycloak_auth_manager_fastapi_api_file, - ) - - fab_auth_manager_fastapi_api_path = Path(fab_auth_manager_fastapi_api_file).parent.joinpath( - "v2-fab-auth-manager-generated.yaml" - ) - keycloak_auth_manager_fastapi_api_path = Path(keycloak_auth_manager_fastapi_api_file).parent.joinpath( - "v2-keycloak-auth-manager-generated.yaml" - ) - redoc = [ - { - "name": "Fab auth manager API", - "page": "api-ref/fab-api-ref", - "spec": fab_auth_manager_fastapi_api_path.as_posix(), - "opts": { - "hide-hostname": True, - "no-auto-auth": True, - }, - }, - { - "name": "Keycloak auth manager token API", - "page": "api-ref/token-api-ref", - "spec": keycloak_auth_manager_fastapi_api_path.as_posix(), - "opts": { - "hide-hostname": True, - "no-auto-auth": True, - }, - }, - ] diff --git a/devel-common/src/docs/utils/conf_constants.py b/devel-common/src/docs/utils/conf_constants.py index 97c4b548fe9ab..df1d36b373f9a 100644 --- a/devel-common/src/docs/utils/conf_constants.py +++ b/devel-common/src/docs/utils/conf_constants.py @@ -22,6 +22,7 @@ import sys from collections import defaultdict from typing import Any +from urllib import request from packaging.version import Version, parse as parse_version @@ -96,15 +97,35 @@ def get_rst_epilogue(package_version: str, airflow_core: bool) -> str: "metrics_tables_from_registry", ] -SPHINX_REDOC_EXTENSIONS = [ - "autoapi.extension", - # First, generate redoc - "sphinxcontrib.redoc", - # Second, update redoc script - "sphinx_script_update", -] +# Properties for Swagger OpenAPI generation: +# See https://github.com/SAP/swagger-plugin-for-sphinx +SPHINX_SWAGGER_EXTENSION = "swagger_plugin_for_sphinx" + + +def mirror_artifact_locally(source_uri: str, doc_root: pathlib.Path) -> str: + """ + Mirror (Swagger UI or other) artifacts locally to avoid relying on external CDNs. + + Note: This is not needed if https://github.com/SAP/swagger-plugin-for-sphinx/issues/508 + is implemented and the mirroring can be just a feature flag in the plugin itself. + + :param source_uri: The original URI of the Swagger UI artifact. + :param doc_root: The root path of the documentation. + :return: The local URI of the mirrored Swagger UI artifact. + """ + filename = pathlib.Path(source_uri).name + local_path = doc_root / "static" / "mirrored" / filename + if not local_path.exists(): + local_path.parent.mkdir(parents=True, exist_ok=True) + request.urlretrieve(source_uri, local_path) + + return f"mirrored/{filename}" + -REDOC_SCRIPT_URL = "https://cdn.jsdelivr.net/npm/redoc@2.0.0-rc.48/bundles/redoc.standalone.js" +_SWAGGER_VERSION = "5.11.0" +SWAGGER_PRESENT_URI = f"https://unpkg.com/swagger-ui-dist@{_SWAGGER_VERSION}/swagger-ui-standalone-preset.js" +SWAGGER_BUNDLE_URI = f"https://unpkg.com/swagger-ui-dist@{_SWAGGER_VERSION}/swagger-ui-bundle.js" +SWAGGER_CSS_URI = f"https://unpkg.com/swagger-ui-dist@{_SWAGGER_VERSION}/swagger-ui.css" def get_rst_filepath_from_path(filepath: pathlib.Path, root: pathlib.Path): diff --git a/providers/edge3/docs/edge-api-ref.rst b/providers/edge3/docs/edge-api-ref.rst new file mode 100644 index 0000000000000..7854c8c2402d7 --- /dev/null +++ b/providers/edge3/docs/edge-api-ref.rst @@ -0,0 +1,25 @@ + + .. Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + .. http://www.apache.org/licenses/LICENSE-2.0 + + .. Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +Edge Worker REST API +==================== + +.. swagger-plugin:: ../src/airflow/providers/edge3/worker_api/v2-edge-generated.yaml + :id: edge-worker-api-ref + :page-title: Edge Worker REST API + :swagger-options: { "tryItOutEnabled": "false", "supportedSubmitMethods": [] } diff --git a/providers/edge3/docs/index.rst b/providers/edge3/docs/index.rst index 3da9957684c41..794cb51aef93f 100644 --- a/providers/edge3/docs/index.rst +++ b/providers/edge3/docs/index.rst @@ -58,6 +58,7 @@ Configuration CLI Python API <_api/airflow/providers/edge3/index> + Edge Worker REST API .. toctree:: :hidden: diff --git a/providers/fab/docs/api-ref/fab-api-ref.rst b/providers/fab/docs/api-ref/fab-api-ref.rst index 87d68179eebda..7182451347492 100644 --- a/providers/fab/docs/api-ref/fab-api-ref.rst +++ b/providers/fab/docs/api-ref/fab-api-ref.rst @@ -19,4 +19,7 @@ FAB auth manager token API ========================== -It's a stub file. It will be automatically converted during the build process into valid documentation by the Sphinx plugin. See: /docs/conf.py +.. swagger-plugin:: ../../src/airflow/providers/fab/auth_manager/api_fastapi/openapi/v2-fab-auth-manager-generated.yaml + :id: fab-auth-manager-api-ref + :page-title: FAB auth manager token API + :swagger-options: { "tryItOutEnabled": "false", "supportedSubmitMethods": [] } diff --git a/providers/keycloak/docs/api-ref/token-api-ref.rst b/providers/keycloak/docs/api-ref/token-api-ref.rst index e9003e082d043..e48c66a4ab9b7 100644 --- a/providers/keycloak/docs/api-ref/token-api-ref.rst +++ b/providers/keycloak/docs/api-ref/token-api-ref.rst @@ -19,4 +19,7 @@ Keycloak auth manager token API =============================== -It's a stub file. It will be automatically converted during the build process into valid documentation by the Sphinx plugin. See: /docs/conf.py +.. swagger-plugin:: ../../src/airflow/providers/keycloak/auth_manager/openapi/v2-keycloak-auth-manager-generated.yaml + :id: keycloak-auth-manager-api-ref + :page-title: Keycloak auth manager token API + :swagger-options: { "tryItOutEnabled": "false", "supportedSubmitMethods": [] } diff --git a/uv.lock b/uv.lock index 7766a2d3cf466..aa4c350e05632 100644 --- a/uv.lock +++ b/uv.lock @@ -2450,7 +2450,6 @@ docs = [ { name = "pagefind" }, { name = "pagefind-bin" }, { name = "rich-click" }, - { name = "setuptools" }, { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, @@ -2471,9 +2470,9 @@ docs = [ { name = "sphinxcontrib-jquery" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-redoc" }, { name = "sphinxcontrib-serializinghtml" }, { name = "sphinxcontrib-spelling" }, + { name = "swagger-plugin-for-sphinx" }, ] docs-gen = [ { name = "diagrams" }, @@ -2642,7 +2641,6 @@ requires-dist = [ { name = "ruff", specifier = "==0.15.13" }, { name = "semver", specifier = ">=3.0.2" }, { name = "semver", marker = "extra == 'devscripts'", specifier = ">=3.0.2" }, - { name = "setuptools", marker = "extra == 'docs'", specifier = "<82.0.0" }, { name = "sphinx", marker = "extra == 'docs'", specifier = ">=7" }, { name = "sphinx-airflow-theme", marker = "extra == 'docs'", url = "https://airflow.apache.org/sphinx-airflow-theme/sphinx_airflow_theme-0.3.10-py3-none-any.whl" }, { name = "sphinx-argparse", marker = "extra == 'docs'", specifier = ">=0.4.0" }, @@ -2659,11 +2657,11 @@ requires-dist = [ { name = "sphinxcontrib-jquery", marker = "extra == 'docs'", specifier = ">=4.1" }, { name = "sphinxcontrib-jsmath", marker = "extra == 'docs'", specifier = ">=1.0.1" }, { name = "sphinxcontrib-qthelp", marker = "extra == 'docs'", specifier = ">=1.0.3" }, - { name = "sphinxcontrib-redoc", marker = "extra == 'docs'", specifier = ">=1.6.0" }, { name = "sphinxcontrib-serializinghtml", marker = "extra == 'docs'", specifier = ">=1.1.5" }, { name = "sphinxcontrib-spelling", marker = "extra == 'docs'", specifier = ">=8.0.0" }, { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'sqlalchemy'", specifier = ">=1.4.49" }, { name = "sqlalchemy-utils", marker = "extra == 'sqlalchemy'", specifier = ">=0.41.2" }, + { name = "swagger-plugin-for-sphinx", marker = "extra == 'docs'", specifier = ">=7.0.0" }, { name = "time-machine", extras = ["dateutil"], specifier = ">=3.0.0" }, { name = "towncrier", marker = "extra == 'devscripts'", specifier = ">=23.11.0" }, { name = "twine", marker = "extra == 'devscripts'", specifier = ">=4.0.2" }, @@ -21738,21 +21736,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, ] -[[package]] -name = "sphinxcontrib-redoc" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "pyyaml" }, - { name = "six" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/73/872189269380d0271d575771986db8a77f06bc4565c1a971bebd54f38d2c/sphinxcontrib-redoc-1.6.0.tar.gz", hash = "sha256:e358edbe23927d36432dde748e978cf897283a331a03e93d3ef02e348dee4561", size = 350482, upload-time = "2020-04-17T19:46:48.041Z" } - [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" @@ -22050,6 +22033,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/1c/a6b5d90a9ca479805798276728ccbbdff0c7228e2ea93b1f731779d635e3/svcs-25.1.0-py3-none-any.whl", hash = "sha256:df49cb7d1a05dfd2dd60af1a2cb84b9c3bb0a74728833cb8c54a7ceeecce6c97", size = 19456, upload-time = "2025-01-25T13:15:19.677Z" }, ] +[[package]] +name = "swagger-plugin-for-sphinx" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "jinja2" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/14/36a4b2172fd6496c646d58dcb11c2877e09cc38e6d206eaa822dad0d0eab/swagger_plugin_for_sphinx-7.0.0.tar.gz", hash = "sha256:86a18b9ec1da2b78a80772fbd5d10549bf393b072f07da9edb5d1eaac02b8d44", size = 106931, upload-time = "2026-02-20T09:10:17.859Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/2d/534436c46a992b8f31bb56e591422519e218b970db1d596ff96142776613/swagger_plugin_for_sphinx-7.0.0-py3-none-any.whl", hash = "sha256:e5207f385f5061bf05eb37355a3a83794bab6e41c5404f5cf4905b90efc9684f", size = 11170, upload-time = "2026-02-20T09:10:15.479Z" }, +] + [[package]] name = "sympy" version = "1.14.0"