[builder] type Builder core methods with @final and improve docs (#12436)

This commit:

- annotates the `Builder`'s "core" methods, with [`final`](https://docs.python.org/3/library/typing.html#typing.final)
- adds a UML graph to the Builder API docs
- Adds more methods to the Builder API docs

to make it clearer for extension developers, what is expected from a new builder subclass.
This commit is contained in:
Chris Sewell authored and GitHub committed 2024-06-19 14:51:20 +02:00
1 parent e30430d2ba
commit 37ff33dff7
4 files changed
+87 -12

No files matched your search

+1
View File
@@ -18,6 +18,7 @@ extensions = [
'sphinx.ext.viewcode',
'sphinx.ext.inheritance_diagram',
'sphinx.ext.coverage',
'sphinx.ext.graphviz',
]
coverage_statistics_to_report = coverage_statistics_to_stdout = True
templates_path = ['_templates']
+75 -9
View File
@@ -3,15 +3,66 @@
Builder API
===========
.. todo:: Expand this.
.. currentmodule:: sphinx.builders
.. class:: Builder
This is the base class for all builders.
These attributes should be set on builder classes:
It follows this basic workflow:
.. graphviz::
:caption: UML for the standard Sphinx build workflow
digraph build {
graph [
rankdir=LR
];
node [
shape=rect
style=rounded
];
"Sphinx" [
shape=record
label = "Sphinx | <init> __init__ | <build> build"
];
"Sphinx":init -> "Builder.init";
"Sphinx":build -> "Builder.build_all";
"Sphinx":build -> "Builder.build_specific";
"Builder.build_update" [
shape=record
label = "<p1> Builder.build_update | Builder.get_outdated_docs"
];
"Sphinx":build -> "Builder.build_update":p1 ;
"Builder.build_all" -> "Builder.build";
"Builder.build_specific" -> "Builder.build";
"Builder.build_update":p1 -> "Builder.build";
"Builder.build" -> "Builder.read";
"Builder.write" [
shape=record
label = "<p1> Builder.write | Builder._write_serial | Builder._write_parallel"
];
"Builder.build" -> "Builder.write";
"Builder.build" -> "Builder.finish";
"Builder.read" -> "Builder.read_doc";
"Builder.read_doc" -> "Builder.write_doctree";
"Builder.write":p1 -> "Builder.prepare_writing";
"Builder.write":p1 -> "Builder.copy_assets";
"Builder.write":p1 -> "Builder.write_doc";
"Builder.write_doc" -> "Builder.get_relative_uri";
"Builder.get_relative_uri" -> "Builder.get_target_uri";
}
.. rubric:: Overridable Attributes
These attributes should be set on builder sub-classes:
.. autoattribute:: name
.. autoattribute:: format
@@ -22,24 +73,39 @@ Builder API
.. autoattribute:: supported_data_uri_images
.. autoattribute:: default_translator_class
These methods are predefined and will be called from the application:
.. rubric:: Core Methods
These methods are predefined and should generally not be overridden,
since they form the core of the build process:
.. automethod:: get_relative_uri
.. automethod:: build_all
.. automethod:: build_specific
.. automethod:: build_update
.. automethod:: build
.. automethod:: read
.. automethod:: read_doc
.. automethod:: write_doctree
These methods can be overridden in concrete builder classes:
.. rubric:: Overridable Methods
These must be implemented in builder sub-classes:
.. automethod:: init
.. automethod:: get_outdated_docs
.. automethod:: get_target_uri
.. automethod:: prepare_writing
.. automethod:: write_doc
.. automethod:: get_target_uri
These methods can be overridden in builder sub-classes:
.. automethod:: init
.. automethod:: write
.. automethod:: copy_assets
.. automethod:: get_relative_uri
.. automethod:: finish
**Attributes**
.. rubric:: Attributes
Attributes that are callable from the builder instance:
.. attribute:: events
+10 -2
View File
@@ -6,7 +6,7 @@ import codecs
import pickle
import time
from os import path
from typing import TYPE_CHECKING, Any, Literal
from typing import TYPE_CHECKING, Any, Literal, final
from docutils import nodes
from docutils.utils import DependencyList
@@ -245,12 +245,14 @@ class Builder:
# build methods
@final
def build_all(self) -> None:
"""Build all source files."""
self.compile_all_catalogs()
self.build(None, summary=__('all source files'), method='all')
@final
def build_specific(self, filenames: list[str]) -> None:
"""Only rebuild as much as needed for changes in the *filenames*."""
docnames: list[str] = []
@@ -281,6 +283,7 @@ class Builder:
self.build(docnames, method='specific',
summary=__('%d source files given on command line') % len(docnames))
@final
def build_update(self) -> None:
"""Only rebuild what was changed or added since last build."""
self.compile_update_catalogs()
@@ -294,6 +297,7 @@ class Builder:
summary=__('targets for %d source files that are out of date') %
len(to_build))
@final
def build(
self,
docnames: Iterable[str] | None,
@@ -367,6 +371,7 @@ class Builder:
# wait for all tasks
self.finish_tasks.join()
@final
def read(self) -> list[str]:
"""(Re-)read all files new or changed since last update.
@@ -473,6 +478,7 @@ class Builder:
tasks.join()
logger.info('')
@final
def read_doc(self, docname: str, *, _cache: bool = True) -> None:
"""Parse a file and add/update inventory entries for the doctree."""
self.env.prepare_settings(docname)
@@ -507,10 +513,11 @@ class Builder:
self.write_doctree(docname, doctree, _cache=_cache)
@final
def write_doctree(
self, docname: str, doctree: nodes.document, *, _cache: bool = True,
) -> None:
"""Write the doctree to a file."""
"""Write the doctree to a file, to be used as a cache by re-builds."""
# make it picklable
doctree.reporter = None # type: ignore[assignment]
doctree.transformer = None # type: ignore[assignment]
@@ -539,6 +546,7 @@ class Builder:
updated_docnames: Sequence[str],
method: Literal['all', 'specific', 'update'] = 'update',
) -> None:
"""Write builder specific output files."""
if build_docnames is None or build_docnames == ['__all__']:
# build_all
build_docnames = self.env.found_docs
+1 -1
View File
@@ -257,7 +257,7 @@ class MessageCatalogBuilder(I18nBuilder):
msg = f'{template}: {exc!r}'
raise ThemeError(msg) from exc
def build(
def build( # type: ignore[misc]
self,
docnames: Iterable[str] | None,
summary: str | None = None,