Files
computer-playbook/roles/web-app-docs/files/python/infinito_docs/commands.py
T
kevinveenbirkenbachandClaude Opus 5 386fb8cdff fix(docs): stop re-exported types from being documented twice
autodoc documents whatever __all__ lists, an imported name included, and apidoc also writes a page for the submodule the name comes from. An annotation naming such a type resolves to two targets, which -W turns fatal: the documentation catalogs could not be extracted at all.

Only a type reaches that failure, because only a type appears in the annotations sphinx resolves. mesh re-exported Mesh, MeshMember and MeshSpec; libretranslate re-exported LibreTranslate and Outcome; the development inventory package still listed PlanEntry beside the DevInventorySpec that 7fee974c7f removed for this reason. Each now uses the redundant alias the repository already established, which keeps the name importable without listing it. Label in variant/axes.py had no importer and is gone.

Re-exporting a function stays allowed: the development inventory package re-exports its helpers so unit tests can patch them under the package path, and no function has ever produced a second target.

A lint pins the class, because the docstring 7fee974c7f relied on did not hold a third time. It reads the trees apidoc skips from APIDOC_EXCLUDED, which commands.py now names once instead of repeating the three paths inside the argv.

locale/ is the extract this unblocks: 26144 messages over 183 catalogs. 987761 translations carry over, 8893 lose a msgid that no longer exists, and 1136 keep their msgid but come back empty for the next i18n-translate to refill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-21 02:39:36 +02:00

146 lines
3.7 KiB
Python

"""The commands that build one version of the documentation and the progress they report."""
from __future__ import annotations
import re
import sys
_STEP = re.compile(
r"^(reading sources|writing output|postprocess html)\.\.\. \[\s*(\d+)%\]"
)
_SPAN = {
"reading sources": (10, 40),
"writing output": (40, 60),
"postprocess html": (60, 99),
}
APIDOC_EXCLUDED = ("tests", "roles", "library")
def _module(name, *args):
return [sys.executable, "-P", "-m", name, *(str(arg) for arg in args)]
def _generator(name, *args):
return _module(f"infinito_docs.generators.{name}", *args)
def generate_commands(src):
"""Return the commands that prepare ``src`` for ``sphinx-build``.
Args:
src: checkout of the version to document.
Returns:
argv lists, in the order they must run.
"""
generated = src / "generated"
return [
[
sys.executable,
"-m",
"sphinx.ext.apidoc",
"-f",
"-o",
str(generated / "modules"),
str(src),
*(str(src / name) for name in APIDOC_EXCLUDED),
],
_generator(
"yaml_index",
"--source-dir",
src,
"--output-file",
generated / "yaml_index.rst",
),
_generator(
"ansible_roles",
"--roles-dir",
src / "roles",
"--output-dir",
generated / "roles",
),
_generator(
"index",
"--roles-dir",
generated / "roles",
"--output-file",
src / "roles" / "ansible_role_glosar.rst",
"--caption",
"Ansible Role Glossary",
),
_generator(
"roles_overview",
"--roles-dir",
src / "roles",
"--output-file",
generated / "roles_overview.json",
),
_generator(
"make_targets",
"--makefile",
src / "Makefile",
"--output-file",
generated / "make_targets.rst",
),
_generator(
"aliases",
"--aliases-file",
src / "aliases",
"--output-file",
generated / "aliases.rst",
),
_generator(
"cli_commands",
"--cli-dir",
src / "cli",
"--output-file",
generated / "cli_commands.rst",
),
_generator(
"integrations",
"--roles-dir",
src / "roles",
"--output-dir",
generated / "integrations",
),
_generator(
"licensing",
"--roles-dir",
src / "roles",
"--output",
generated / "licensing.rst",
),
_generator("readmes", "--generated-dir", generated),
_module(
"cli.build.docs.readme",
"--override",
"--roles-dir",
src / "roles",
),
_module(
"cli.build.docs.readme.overview",
"--readme",
src / "README.md",
"--roles-dir",
src / "roles",
),
]
def progress_of(line, current):
"""Return the overall build progress after one line of Sphinx output.
Args:
line: a line of ``sphinx-build`` output.
current: progress before this line, in percent.
Returns:
The new progress in percent; it never moves backwards.
"""
match = _STEP.match(line)
if not match:
return current
start, end = _SPAN[match.group(1)]
return max(current, start + (end - start) * int(match.group(2)) // 100)