This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 3d73cceafae Docs: Make common.compat.sdk re-exports clickable (#67083)
3d73cceafae is described below

commit 3d73cceafaeea0de24ed7afc7350023cfb7d2c46
Author: Yuseok Jo <[email protected]>
AuthorDate: Tue May 19 06:27:13 2026 +0900

    Docs: Make common.compat.sdk re-exports clickable (#67083)
    
    * Docs: Make common.compat.sdk re-exports clickable
    
    * Fix mypy error in common.compat.sdk xref handler
---
 devel-common/src/docs/utils/conf_constants.py      |   1 +
 .../src/sphinx_exts/common_compat_alias.py         | 124 +++++++++++++++++++++
 2 files changed, 125 insertions(+)

diff --git a/devel-common/src/docs/utils/conf_constants.py 
b/devel-common/src/docs/utils/conf_constants.py
index dd2e0c31b67..97c4b548fe9 100644
--- a/devel-common/src/docs/utils/conf_constants.py
+++ b/devel-common/src/docs/utils/conf_constants.py
@@ -86,6 +86,7 @@ BASIC_SPHINX_EXTENSIONS = [
     "removemarktransform",
     "sphinx_copybutton",
     "airflow_intersphinx",
+    "common_compat_alias",
     "sphinxcontrib.spelling",
     "sphinx_airflow_theme",
     "redirects",
diff --git a/devel-common/src/sphinx_exts/common_compat_alias.py 
b/devel-common/src/sphinx_exts/common_compat_alias.py
new file mode 100644
index 00000000000..8bbc6d68afe
--- /dev/null
+++ b/devel-common/src/sphinx_exts/common_compat_alias.py
@@ -0,0 +1,124 @@
+# 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.
+"""
+Resolve unresolved ``airflow.providers.common.compat.sdk.<Name>`` 
cross-references
+to the symbol's canonical location (typically ``airflow.sdk.<Name>``).
+
+``airflow.providers.common.compat.sdk`` dispatches symbols at runtime through
+``__getattr__``, so static documentation tooling (autoapi) cannot see the
+re-exports. Without this extension, any documentation that names a compat.sdk
+symbol — most visibly the "Bases:" line on provider operator/sensor/hook
+pages — renders as plain text rather than a link.
+
+The handler consults the same ``_IMPORT_MAP`` / ``_RENAME_MAP`` / 
``_MODULE_MAP``
+that the runtime dispatcher uses, tries the canonical (Airflow 3) target first
+followed by the legacy fallbacks, and re-runs Sphinx's intersphinx lookup 
against
+each rewritten target until one resolves.
+"""
+
+from __future__ import annotations
+
+import copy
+from typing import TYPE_CHECKING
+
+from sphinx.ext.intersphinx import resolve_reference_any_inventory
+
+if TYPE_CHECKING:
+    from docutils.nodes import Element, TextElement
+    from sphinx.addnodes import pending_xref
+    from sphinx.application import Sphinx
+    from sphinx.environment import BuildEnvironment
+
+PREFIX = "airflow.providers.common.compat.sdk."
+
+
+def _canonical_targets(name: str) -> list[str]:
+    """Return the ordered list of intersphinx reftarget candidates for a short 
name."""
+    from airflow.providers.common.compat.sdk import (
+        _IMPORT_MAP,
+        _MODULE_MAP,
+        _RENAME_MAP,
+    )
+
+    targets: list[str] = []
+
+    # Mirrors runtime __getattr__ in providers.common.compat._compat_utils:
+    # rename → module → import, with every path in each tuple tried in order so
+    # legacy (Airflow 2.x) locations stay valid fallbacks when the canonical
+    # target isn't present in any intersphinx inventory.
+    if name in _RENAME_MAP:
+        new_path, old_path, old_name = _RENAME_MAP[name]
+        targets.append(f"{new_path}.{name}")
+        targets.append(f"{old_path}.{old_name}")
+
+    if name in _MODULE_MAP:
+        paths = _MODULE_MAP[name]
+        targets.extend(paths if isinstance(paths, tuple) else (paths,))
+
+    if name in _IMPORT_MAP:
+        paths = _IMPORT_MAP[name]
+        path_tuple = paths if isinstance(paths, tuple) else (paths,)
+        targets.extend(f"{path}.{name}" for path in path_tuple)
+
+    return targets
+
+
+def resolve_compat_sdk_xref(
+    app: Sphinx,
+    env: BuildEnvironment,
+    node: pending_xref,
+    contnode: TextElement,
+) -> Element | None:
+    """Sphinx ``missing-reference`` handler that aliases compat.sdk symbols."""
+    if node.get("refdomain") != "py":
+        return None
+
+    target = node.get("reftarget", "")
+    if not target.startswith(PREFIX):
+        return None
+
+    name = target[len(PREFIX) :]
+    # __getattr__ only dispatches top-level attributes; nested (e.g. 
timezone.utcnow) is out of scope.
+    if "." in name:
+        return None
+
+    try:
+        candidates = _canonical_targets(name)
+    except (ImportError, ModuleNotFoundError, AttributeError):
+        # Narrow on purpose — other exceptions are real bugs and must surface.
+        return None
+
+    if not candidates:
+        return None
+
+    for candidate in candidates:
+        probe = copy.copy(node)
+        probe["reftarget"] = candidate
+        resolved = resolve_reference_any_inventory(env, False, probe, contnode)
+        if resolved is not None:
+            return resolved
+
+    return None
+
+
+def setup(app: Sphinx) -> dict[str, object]:
+    app.connect("missing-reference", resolve_compat_sdk_xref)
+    return {
+        "version": "1.0",
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }

Reply via email to