Skip to content

Commit

Permalink
drgndoc: work around Sphinx not linking to type aliases in annotations
Browse files Browse the repository at this point in the history
Sphinx normally makes type names in annotations links to the
documentation for that type, but this doesn't work for type aliases
(like drgn.Path). See sphinx-doc/sphinx#10785. Add a workaround inspired
by adafruit/circuitpython#8236.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
  • Loading branch information
osandov committed Nov 1, 2023
1 parent a2bd731 commit 1636bbd
Showing 1 changed file with 38 additions and 1 deletion.
39 changes: 38 additions & 1 deletion docs/exts/drgndoc/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@
file for the C extension itself (drgndoc.docstrings).
"""

import ast
import os.path
import re
from typing import Any, Dict, cast
from typing import Any, Dict, Optional, cast

import docutils.nodes
import docutils.parsers.rst.directives
Expand All @@ -63,6 +64,7 @@
ImportFrom,
Module,
Node,
Variable,
parse_paths,
)
from drgndoc.util import dot_join
Expand Down Expand Up @@ -90,6 +92,40 @@ def drgndoc_init(app: sphinx.application.Sphinx) -> None:
)


# Sphinx looks up type annotations as py:class references. This doesn't work
# for type aliases, which are py:data. See
# https://github.com/sphinx-doc/sphinx/issues/10785. This hack intercepts
# missing py:class references, and if they resolve to a variable annotated as
# TypeAlias, retries them as py:data.
def missing_reference(
app: sphinx.application.Sphinx,
env: DrgnDocBuildEnvironment,
node: sphinx.addnodes.pending_xref,
contnode: docutils.nodes.Element,
) -> Optional[docutils.nodes.Element]:
if node.get("refdomain") == "py":
reftarget = node.get("reftarget")
if reftarget and node.get("reftype") == "class":
resolved = env.drgndoc_namespace.resolve_global_name(reftarget)
if (
isinstance(resolved, ResolvedNode)
and isinstance(resolved.node, Variable)
and isinstance(resolved.node.annotation, ast.Name)
and resolved.node.annotation.id == "TypeAlias"
):
node.attributes["reftype"] = "data"
return env.domains["py"].resolve_xref(
env,
node.get("refdoc"),
app.builder,
"data",
reftarget,
node,
contnode,
)
return None


class DrgnDocDirective(sphinx.util.docutils.SphinxDirective):
env: DrgnDocBuildEnvironment

Expand Down Expand Up @@ -248,6 +284,7 @@ def _run_module(

def setup(app: sphinx.application.Sphinx) -> Dict[str, Any]:
app.connect("builder-inited", drgndoc_init)
app.connect("missing-reference", missing_reference)
# List of modules or packages.
app.add_config_value("drgndoc_paths", [], "env")
# List of (regex pattern, substitution) to apply to resolved names.
Expand Down

0 comments on commit 1636bbd

Please sign in to comment.