mafw.devtools.documentation.builder

Sphinx documentation building helpers for MAFw versioned documentation.

This module provides functions for building Sphinx documentation across multiple git tags, managing git worktrees, and handling documentation zip archives.

Module Attributes

DEFAULT_MIN_TAG_REGEX

Regular expression to match stable version tags.

DOCS_SUBPATH

The files/directories under each worktree where docs live.

SPHINX_BUILD_CMD

Sphinx build command name.

OLD_VERSION_TO_BE_PATCHED

Tags that require patching with the latest conf.py.

Functions

build_for_tag(tag, outdir, tmproot[, ...])

Create worktree for tag, run sphinx-build, save log.

build_pdf_for_tag(tag, html_tag_dir, tmproot)

Create worktree for tag, run sphinx-build with latex builder, then make PDF.

check_multiversion_structure(outdir)

Check if multiversion structure exists (other version directories).

copy_patch_files(docs_src)

Copy patch files needed for older versions.

create_docs_zip_for_tag(outdir, tag, ...)

Create a zip archive for a built documentation version directory.

ensure_sphinx_build_available()

Ensure that the Sphinx Python package is available.

extract_docs_zip_to_repo_root(zip_path[, ...])

Extract a documentation zip archive into the repository root and remove the zip.

filter_latest_micro(versions)

Keep only the latest micro version per minor (major.minor).

filter_stable_tags(tags, regex)

Filter tags based on a regular expression pattern.

filter_versions_in_range(versions, from_v, to_v)

Filter versions within an inclusive semantic-version range.

find_repo_root([start])

Find the repository root directory.

generate_pdf_index_page(html_outdir, pdf_info)

Generate an HTML page listing all available PDFs.

iter_local_mafw_docs_zips(zip_dir)

List local mafw-docs zip files in a directory.

normalize_registry_item(item)

Normalize a registry item into (version, file_name).

parse_mafw_docs_zip_filename(file_name)

Parse and validate a mafw-docs zip filename.

parse_sphinx_log(log_content)

Parse Sphinx build log to extract warning and error counts, and warning messages.

parse_version_tuple(tag)

Parse vX.Y.Z(.W) into tuple of ints for sorting.

report_build_status(tag, success, log[, ...])

Report build status with warning/error summary.

run(cmd[, cwd])

Helper to run commands with consistent behavior.

mafw.devtools.documentation.builder.build_for_tag(tag: str, outdir: Path, tmproot: Path, use_latest_conf: bool = False, keep_tmp: bool = False) tuple[bool, str][source]

Create worktree for tag, run sphinx-build, save log.

Parameters:
  • tag (str) – Git tag to build documentation for

  • outdir (Path) – Output directory for built documentation

  • tmproot (Path) – Root temporary directory

  • use_latest_conf (bool) – Whether to use latest conf.py, defaults to False

  • keep_tmp (bool) – Whether to keep temporary files, defaults to False

Returns:

Tuple of (success, log_contents)

Return type:

tuple[bool, str]

mafw.devtools.documentation.builder.build_pdf_for_tag(tag: str, html_tag_dir: Path, tmproot: Path, use_latest_conf: bool = False, keep_tmp: bool = False) tuple[bool, str, Path | None][source]

Create worktree for tag, run sphinx-build with latex builder, then make PDF.

Parameters:
  • tag (str) – Git tag to build PDF for

  • html_tag_dir (Path) – Directory containing HTML output for the tag

  • tmproot (Path) – Root temporary directory

  • use_latest_conf (bool) – Whether to use latest conf.py, defaults to False

  • keep_tmp (bool) – Whether to keep temporary files, defaults to False

Returns:

Tuple of (success, log_contents, pdf_path)

Return type:

tuple[bool, str, Path | None]

mafw.devtools.documentation.builder.check_multiversion_structure(outdir: Path) bool[source]

Check if multiversion structure exists (other version directories).

Parameters:

outdir (Path) – Output directory to check

Returns:

True if other versions exist

Return type:

bool

mafw.devtools.documentation.builder.copy_patch_files(docs_src: Path) None[source]

Copy patch files needed for older versions.

Parameters:

docs_src (Path) – Path to documentation source directory

mafw.devtools.documentation.builder.create_docs_zip_for_tag(outdir: Path, tag: str, zip_filepath: Path) Path[source]

Create a zip archive for a built documentation version directory.

The built docs are expected under outdir / tag (e.g. docs/build/doc/vX.Y.Z). The produced zip is laid out so that extracting it from the repository root recreates the original directory structure (e.g. docs/build/doc/vX.Y.Z/...).

The zip file is created at zip_filepath / f"mafw-docs-{tag}.zip".

Notes

  • Symlinks are skipped to avoid ambiguous extraction behavior across platforms.

param outdir:

Output directory that contains the built docs

type outdir:

Path

param tag:

Version tag (e.g. v2.1.0)

type tag:

str

param zip_filepath:

Directory where the zip file is written

type zip_filepath:

Path

return:

Path to the created zip archive

rtype:

Path

raises FileNotFoundError:

If the built docs directory does not exist

raises NotADirectoryError:

If the built docs path is not a directory

mafw.devtools.documentation.builder.ensure_sphinx_build_available() None[source]

Ensure that the Sphinx Python package is available.

doc_versioning is a development helper shipped with MAFw. The script is typically executed from the optional [dev] environment (either by activating the development environment and using the console entry point, or via hatch run dev.py<version>:multidoc on CI/CD).

Checking for the sphinx-build executable alone is not sufficient because the effective availability depends on which Python environment is executing the command. Checking the import spec for sphinx validates that the correct optional dependencies are installed for the running interpreter.

Raises:

DevtoolsError – If Sphinx is not available.

mafw.devtools.documentation.builder.extract_docs_zip_to_repo_root(zip_path: Path, repo_root: Path | None = None) None[source]

Extract a documentation zip archive into the repository root and remove the zip.

The zip archive is expected to contain paths rooted at the repository (e.g. docs/build/doc/vX.Y.Z/...) so that extraction recreates the same structure as a normal documentation build.

Parameters:
  • zip_path (Path) – Zip archive to extract

  • repo_root (Path | None) – Repository root directory, defaults to auto-detection

Raises:
  • FileNotFoundError – If zip_path does not exist

  • zipfile.BadZipFile – If the archive is invalid

mafw.devtools.documentation.builder.filter_latest_micro(versions: list[tuple[Version, Any]]) list[tuple[Version, Any]][source]

Keep only the latest micro version per minor (major.minor).

Parameters:

versions (list[tuple[Version, Any]]) – List of (Version, tag) tuples

Returns:

Filtered list of (Version, tag) tuples

Return type:

list[tuple[Version, Any]]

mafw.devtools.documentation.builder.filter_stable_tags(tags: list[str], regex: str) list[str][source]

Filter tags based on a regular expression pattern.

Parameters:
  • tags (list[str]) – List of tag strings to filter

  • regex (str) – Regular expression pattern to match against

Returns:

Filtered list of matching tags

Return type:

list[str]

mafw.devtools.documentation.builder.filter_versions_in_range(versions: list[str], from_v: str | None, to_v: str | None) list[str][source]

Filter versions within an inclusive semantic-version range.

Parameters:
  • versions (list[str]) – Input versions list

  • from_v (str | None) – Range start (inclusive)

  • to_v (str | None) – Range end (inclusive)

Returns:

Filtered versions list

Return type:

list[str]

Raises:

ValueError – If range bounds are invalid

mafw.devtools.documentation.builder.find_repo_root(start: Path | None = None) Path[source]

Find the repository root directory.

The root is detected by walking upwards until a pyproject.toml file is found. If no such file is found, the starting directory is returned.

Parameters:

start (Path | None) – Directory from which to start searching, defaults to current working directory

Returns:

Resolved repository root directory

Return type:

Path

mafw.devtools.documentation.builder.generate_pdf_index_page(html_outdir: Path, pdf_info: list[dict[str, str]], project_name: str = 'Documentation') None[source]

Generate an HTML page listing all available PDFs. This page will be placed in the root html_versions directory. Order: stable first, then latest, then other releases sorted by version (newest first).

Parameters:
  • html_outdir (Path) – Output directory for HTML files

  • pdf_info (list[dict[str, str]]) – List of dictionaries containing PDF information

  • project_name (str) – Name of the project for the page title, defaults to ‘Documentation’

mafw.devtools.documentation.builder.iter_local_mafw_docs_zips(zip_dir: Path) list[tuple[str, Path]][source]

List local mafw-docs zip files in a directory.

Only files matching mafw-docs-vX.Y.Z.zip are returned.

Parameters:

zip_dir (Path) – Directory to scan

Returns:

List of (version, file_path) tuples

Return type:

list[tuple[str, Path]]

mafw.devtools.documentation.builder.normalize_registry_item(item: str) tuple[str, str][source]

Normalize a registry item into (version, file_name).

The item can be either: - a version string: vX.Y.Z - a file name: mafw-docs-vX.Y.Z.zip

Parameters:

item (str) – Input item

Returns:

Tuple of (version, file_name)

Return type:

tuple[str, str]

Raises:

ValueError – If the item cannot be normalized

mafw.devtools.documentation.builder.parse_mafw_docs_zip_filename(file_name: str) tuple[str, str] | None[source]

Parse and validate a mafw-docs zip filename.

The accepted filename pattern is: mafw-docs-vX.Y.Z.zip.

Parameters:

file_name (str) – File name to parse

Returns:

Tuple of (version, normalized_file_name) if valid, otherwise None

Return type:

tuple[str, str] | None

mafw.devtools.documentation.builder.parse_sphinx_log(log_content: str) tuple[int, int, list[str]][source]

Parse Sphinx build log to extract warning and error counts, and warning messages.

Only three warnings are reported

Parameters:

log_content (str) – Sphinx build log

Returns:

Tuple of warning, error count, warning messages

Return type:

tuple[int, int, list[str]]

mafw.devtools.documentation.builder.parse_version_tuple(tag: str) tuple[int, ...][source]

Parse vX.Y.Z(.W) into tuple of ints for sorting.

Parameters:

tag (str) – Version tag string

Returns:

Tuple of integers representing the version

Return type:

tuple[int, …]

mafw.devtools.documentation.builder.report_build_status(tag: str, success: bool, log: str, build_type: str = 'HTML') None[source]

Report build status with warning/error summary.

Parameters:
  • tag (str) – Version tag being built

  • success (bool) – Whether build succeeded

  • log (str) – Build log content

  • build_type (str) – Type of build (HTML or PDF)

mafw.devtools.documentation.builder.run(cmd: list[str], cwd: Path | None = None) CompletedProcess[str][source]

Helper to run commands with consistent behavior.

Parameters:
  • cmd (list[str]) – Command to execute as a list of strings

  • cwd (Path | None) – Working directory for command execution, defaults to None

Returns:

Completed process result

Return type:

subprocess.CompletedProcess[str]

mafw.devtools.documentation.builder.DEFAULT_MIN_TAG_REGEX = '^v([1-9][0-9]*)\\.[0-9]+\\.[0-9]+(\\.[0-9]+)?$'

Regular expression to match stable version tags.

mafw.devtools.documentation.builder.DOCS_SUBPATH = PosixPath('docs/source')

The files/directories under each worktree where docs live.

mafw.devtools.documentation.builder.OLD_VERSION_TO_BE_PATCHED = ['v1.0.0', 'v1.1.0', 'v1.2.0', 'v1.3.0', 'v1.4.0']

Tags that require patching with the latest conf.py.

mafw.devtools.documentation.builder.SPHINX_BUILD_CMD = 'sphinx-build'

Sphinx build command name.