Files
computer-playbook/roles/web-app-docs/files/python/infinito_docs/conf.py
T
kevinveenbirkenbachandClaude Opus 5 46445552b8 fix(docs): emit the Architecture section only where its page is written
`sphinx -b gettext -q -W` turns a warning into a failure, and
`make i18n-extract` had been dying on 512 of them. 505 were one defect
repeated: the README template emitted an Architecture section for every
role, while `generate_architecture_page` writes ARCHITECTURE.md only for
invokable ones. 101 roles therefore linked five times each to a page
that does not exist. The section now carries the same
`application_invokable` gate as the page, measured from 101 mismatched
roles to 0.

The remaining seven were separate markup defects, each fatal on its own
under -W. architecture.py's four-entry block was an indented paragraph
that docutils read as a definition list ending abruptly, so it becomes a
literal block. branding.py held a double-backtick literal spanning four
lines, which RST does not allow; it becomes a literal block too.
container_extra_hosts.py wrote `Kwargs:`, which napoleon does not know -
a blank line is measurably not enough, the section has to reach
napoleon, so it is `Keyword Args:`. postgres_libraries.py needed one
blank line before its bullet list, and the cleanup skill an H1 above its
first `##`.

conf.py gains two settings. autodoc_mock_imports covers
`ansible.module_utils.kcadm_json`: that import is correct for an Ansible
module, which resolves module_utils only inside a play, so autodoc on
the control host is what has to yield, not the module.
napoleon_use_ivar stops an `Attributes:` section from emitting
`.. attribute::` directives that collide with the dataclass fields
autodoc already documents - eight duplicate-object warnings, reproduced
and cleared on demand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-18 01:24:35 +02:00

107 lines
3.2 KiB
Python

from __future__ import annotations
import logging
import os
import sys
from pathlib import Path
from docutils import nodes
from pygments.lexers.templates import DjangoLexer
from sphinx.domains.python import PythonDomain
from sphinx.highlighting import lexers
logging.basicConfig(
level=logging.DEBUG if {"-v", "--verbose"} & set(sys.argv) else logging.INFO
)
logger = logging.getLogger(__name__)
CONF_DIR = Path(__file__).resolve().parent
templates_path = [str(CONF_DIR / "templates")]
html_static_path = [str(CONF_DIR / "assets")]
project = os.environ["DOCS_SPHINX_PROJECT"]
copyright = os.environ["DOCS_SPHINX_COPYRIGHT"] # noqa: A001
author = os.environ["DOCS_SPHINX_AUTHOR"]
_design_title = os.environ.get("DOCS_DESIGN_TITLE", "").strip()
if _design_title:
html_title = _design_title
lexers["jinja"] = DjangoLexer()
lexers["j2"] = DjangoLexer()
exclude_patterns = ["docs/build", "venv", "venv/**"]
autodoc_mock_imports = ["ansible.module_utils.kcadm_json"]
html_theme = "sphinxawesome_theme"
html_sidebars = {
"**": ["logo.html", "versions.html", "languages.html", "structure.html"]
}
html_context = {"docs_version": os.environ.get("DOCS_VERSION", "")}
html_favicon = "assets/img/favicon.ico"
html_theme_options = {
"show_prev_next": False,
"logo_light": "assets/img/logo.png",
"logo_dark": "assets/img/logo.png",
}
source_suffix = {
".md": "markdown",
".rst": "restructuredtext",
".yml": "yaml",
".yaml": "yaml",
}
extensions = [
"myst_parser",
"infinito_docs.extensions.local.file_headings",
"infinito_docs.extensions.local.subfolders",
"infinito_docs.extensions.roles_overview",
"infinito_docs.extensions.markdown_include",
"infinito_docs.extensions.parallel_postprocess",
"infinito_docs.extensions.untranslated.yaml",
"infinito_docs.extensions.untranslated.markup",
"infinito_docs.extensions.yaml_source",
"infinito_docs.extensions.directory_index",
"infinito_docs.extensions.mermaid",
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
]
autosummary_generate = True
napoleon_use_ivar = True
locale_dirs = ["locale"]
gettext_compact = "docs"
gettext_location = False
myst_enable_extensions = ["colon_fence"]
myst_heading_anchors = 6
myst_url_schemes = ("http", "https", "mailto", "ftp", "tel")
def replace_assets_in_doctree(app, doctree, docname):
for node in doctree.findall(nodes.image):
if "assets/" in node["uri"]:
node["uri"] = node["uri"].replace("assets/", "_static/")
logger.info("Replaced image URI in %s: %s", docname, node["uri"])
for node in doctree.findall(nodes.raw):
if node.get("format") == "html" and "assets/" in node.astext():
rewritten = node.astext().replace("assets/", "_static/")
node.children = [nodes.raw("", rewritten, format="html")]
logger.info("Replaced raw HTML assets in %s.", docname)
def setup(app):
app.connect("doctree-resolved", replace_assets_in_doctree)
python_domain = app.registry.domains.get(PythonDomain.name)
if python_domain is not None:
directive = python_domain.directives.get("currentmodule")
if directive is not None:
directive.optional_arguments = 10
return {"version": "1.0", "parallel_read_safe": True}