mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
[DOCS] Improve events (#12446)
Split the events callback API into a separate document, add a flow graph of the events within the build process, add parameters to the events, and link the `EnvironmentCollector` docs to the relevant events. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
parent
ee92847a0a
commit
0e3f5b4ab2
47
doc/_static/diagrams/sphinx_build_flow.dot
vendored
Normal file
47
doc/_static/diagrams/sphinx_build_flow.dot
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// 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";
|
||||
}
|
123
doc/_static/diagrams/sphinx_core_events_flow.dot
vendored
Normal file
123
doc/_static/diagrams/sphinx_core_events_flow.dot
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
// A flow graph of the Sphinx build process, highlighting event callbacks
|
||||
|
||||
digraph events {
|
||||
graph [
|
||||
rankdir=TB
|
||||
];
|
||||
node [
|
||||
shape=rect
|
||||
style=rounded
|
||||
];
|
||||
"Sphinx" [
|
||||
shape=record
|
||||
label = "<init> Sphinx.__init__() | <build> Sphinx.build()"
|
||||
];
|
||||
|
||||
// During initialization
|
||||
"config-inited"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Sphinx":init -> "config-inited";
|
||||
"builder-inited"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Sphinx":init -> "builder-inited";
|
||||
|
||||
// During build
|
||||
"Builder" [label = "Builder.build()"]
|
||||
"Sphinx":build -> "Builder";
|
||||
"Builder.build" [
|
||||
shape=record
|
||||
label = "
|
||||
<before_read> before read |
|
||||
<read> read |
|
||||
<after_read> after read |
|
||||
<write> write |
|
||||
<finalize> finalize"
|
||||
];
|
||||
"Builder" -> "Builder.build";
|
||||
|
||||
"env-get-outdated"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.build":before_read -> "env-get-outdated";
|
||||
remove_each_doc [shape="ellipse", label="for removed"];
|
||||
"Builder.build":before_read -> "remove_each_doc";
|
||||
"env-purge-doc"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"remove_each_doc" -> "env-purge-doc";
|
||||
"env-before-read-docs"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.build":before_read -> "env-before-read-docs";
|
||||
|
||||
// during read phase
|
||||
"Builder.read" [label = "Builder.read()"]
|
||||
"Builder.build":read -> "Builder.read";
|
||||
read_each_doc [shape="ellipse", label="for added | changed"];
|
||||
"Builder.read" -> "read_each_doc";
|
||||
merge_each_process [
|
||||
shape="ellipse", label="for each process\n(parallel only)"
|
||||
];
|
||||
"Builder.read" -> merge_each_process;
|
||||
"env-updated"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.read" -> "env-updated"
|
||||
|
||||
// during read phase, for each document/process
|
||||
"env-purge-doc"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"read_each_doc" -> "env-purge-doc";
|
||||
"source-read"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"read_each_doc" -> "source-read";
|
||||
"Include" [label="Include\ndirective"]
|
||||
"read_each_doc" -> "Include";
|
||||
"include-read"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Include" -> "include-read";
|
||||
"ObjectDescription" [label="ObjectDescription\ndirective"]
|
||||
"read_each_doc" -> "ObjectDescription";
|
||||
"object-description-transform"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"ObjectDescription" -> "object-description-transform";
|
||||
"doctree-read"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"read_each_doc" -> "doctree-read";
|
||||
"env-merge-info"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"merge_each_process" -> "env-merge-info";
|
||||
|
||||
// after read phase
|
||||
"env-get-updated"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.build":after_read -> "env-get-updated";
|
||||
if_read_changes [shape="diamond", label="if changed\ndocuments"];
|
||||
"Builder.build":after_read -> if_read_changes;
|
||||
if_read_changes -> "cache the\nBuild.Environment";
|
||||
"env-check-consistency"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
if_read_changes -> "env-check-consistency";
|
||||
|
||||
// during write phase
|
||||
"Builder.write" [label = "Builder.write()"]
|
||||
"Builder.build":write -> "Builder.write";
|
||||
write_each_doc [shape="ellipse", label="for updated"];
|
||||
"Builder.write" -> write_each_doc;
|
||||
"ReferenceResolver" [
|
||||
label="ReferenceResolver\nPost-transform"
|
||||
]
|
||||
write_each_doc -> "ReferenceResolver";
|
||||
"missing-reference"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
ReferenceResolver -> "missing-reference";
|
||||
"warn-missing-reference"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
ReferenceResolver -> "warn-missing-reference";
|
||||
"HyperlinkCollector" [
|
||||
label="HyperlinkCollector\nPost-transform"
|
||||
]
|
||||
write_each_doc -> "HyperlinkCollector";
|
||||
"linkcheck-process-uri"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
HyperlinkCollector -> "linkcheck-process-uri";
|
||||
"doctree-resolved"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
write_each_doc -> "doctree-resolved";
|
||||
"html-page-context"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
write_each_doc -> "html-page-context";
|
||||
|
||||
// html only
|
||||
"html-collect-pages"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.build":finalize -> "html-collect-pages";
|
||||
|
||||
// finalize build
|
||||
"build-finished"[style=filled fillcolor="#D5FFFF" color=blue penwidth=2];
|
||||
"Builder.build":finalize -> "build-finished";
|
||||
|
||||
// constrain layout ordering
|
||||
{rank=same "config-inited" "builder-inited"};
|
||||
{rank=same; "env-get-outdated" "env-before-read-docs" "env-get-updated"};
|
||||
{rank=same; "env-purge-doc" "source-read" "doctree-read", "merge_each_process"};
|
||||
{rank=same; "env-updated" "env-check-consistency"};
|
||||
{rank=same; "env-merge-info" "Builder.write"};
|
||||
{rank=max; "build-finished"};
|
||||
}
|
@ -5,6 +5,7 @@ import re
|
||||
import time
|
||||
|
||||
import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
os.environ['SPHINX_AUTODOC_RELOAD_MODULES'] = '1'
|
||||
|
||||
@ -275,7 +276,7 @@ def linkify_issues_in_changelog(app, docname, source):
|
||||
source[0] = source[0].replace('.. include:: ../CHANGES.rst', linkified_changelog)
|
||||
|
||||
|
||||
def setup(app):
|
||||
def setup(app: Sphinx) -> None:
|
||||
from sphinx.ext.autodoc import cut_lines
|
||||
from sphinx.util.docfields import GroupedField
|
||||
|
||||
|
@ -137,294 +137,10 @@ The application object also provides runtime information as attributes.
|
||||
|
||||
Directory for storing built document.
|
||||
|
||||
|
||||
.. _events:
|
||||
|
||||
Sphinx core events
|
||||
------------------
|
||||
|
||||
These events are known to the core. The arguments shown are given to the
|
||||
registered event handlers. Use :meth:`.Sphinx.connect` in an extension's
|
||||
``setup`` function (note that ``conf.py`` can also have a ``setup`` function) to
|
||||
connect handlers to the events. Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def source_read_handler(app, docname, source):
|
||||
print('do something here...')
|
||||
|
||||
def setup(app):
|
||||
app.connect('source-read', source_read_handler)
|
||||
|
||||
|
||||
Below is an overview of each event that happens during a build. In the list
|
||||
below, we include the event name, its callback parameters, and the input and output
|
||||
type for that event:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
1. event.config-inited(app,config)
|
||||
2. event.builder-inited(app)
|
||||
3. event.env-get-outdated(app, env, added, changed, removed)
|
||||
4. event.env-before-read-docs(app, env, docnames)
|
||||
|
||||
for docname in docnames:
|
||||
5. event.env-purge-doc(app, env, docname)
|
||||
|
||||
if doc changed and not removed:
|
||||
6. source-read(app, docname, source)
|
||||
7. run source parsers: text -> docutils.document
|
||||
- parsers can be added with the app.add_source_parser() API
|
||||
8. apply transforms based on priority: docutils.document -> docutils.document
|
||||
- event.doctree-read(app, doctree) is called in the middle of transforms,
|
||||
transforms come before/after this event depending on their priority.
|
||||
|
||||
9. event.env-merge-info(app, env, docnames, other)
|
||||
- if running in parallel mode, this event will be emitted for each process
|
||||
|
||||
10. event.env-updated(app, env)
|
||||
11. event.env-get-updated(app, env)
|
||||
12. event.env-check-consistency(app, env)
|
||||
|
||||
# The updated-docs list can be builder dependent, but generally includes all new/changed documents,
|
||||
# plus any output from `env-get-updated`, and then all "parent" documents in the ToC tree
|
||||
# For builders that output a single page, they are first joined into a single doctree before post-transforms
|
||||
# or the doctree-resolved event is emitted
|
||||
for docname in updated-docs:
|
||||
13. apply post-transforms (by priority): docutils.document -> docutils.document
|
||||
14. event.doctree-resolved(app, doctree, docname)
|
||||
- In the event that any reference nodes fail to resolve, the following may emit:
|
||||
- event.missing-reference(env, node, contnode)
|
||||
- event.warn-missing-reference(domain, node)
|
||||
|
||||
15. Generate output files
|
||||
16. event.build-finished(app, exception)
|
||||
|
||||
Here is a more detailed list of these events.
|
||||
|
||||
.. event:: builder-inited (app)
|
||||
|
||||
Emitted when the builder object has been created. It is available as
|
||||
``app.builder``.
|
||||
|
||||
.. event:: config-inited (app, config)
|
||||
|
||||
Emitted when the config object has been initialized.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
.. event:: env-get-outdated (app, env, added, changed, removed)
|
||||
|
||||
Emitted when the environment determines which source files have changed and
|
||||
should be re-read. *added*, *changed* and *removed* are sets of docnames
|
||||
that the environment has determined. You can return a list of docnames to
|
||||
re-read in addition to these.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. event:: env-purge-doc (app, env, docname)
|
||||
|
||||
Emitted when all traces of a source file should be cleaned from the
|
||||
environment, that is, if the source file is removed or before it is freshly
|
||||
read. This is for extensions that keep their own caches in attributes of the
|
||||
environment.
|
||||
|
||||
For example, there is a cache of all modules on the environment. When a
|
||||
source file has been changed, the cache's entries for the file are cleared,
|
||||
since the module declarations could have been removed from the file.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: env-before-read-docs (app, env, docnames)
|
||||
|
||||
Emitted after the environment has determined the list of all added and
|
||||
changed files and just before it reads them. It allows extension authors to
|
||||
reorder the list of docnames (*inplace*) before processing, or add more
|
||||
docnames that Sphinx did not consider changed (but never add any docnames
|
||||
that are not in ``env.found_docs``).
|
||||
|
||||
You can also remove document names; do this with caution since it will make
|
||||
Sphinx treat changed files as unchanged.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: source-read (app, docname, source)
|
||||
|
||||
Emitted when a source file has been read. The *source* argument is a list
|
||||
whose single element is the contents of the source file. You can process the
|
||||
contents and replace this item to implement source-level transformations.
|
||||
|
||||
For example, if you want to use ``$`` signs to delimit inline math, like in
|
||||
LaTeX, you can use a regular expression to replace ``$...$`` by
|
||||
``:math:`...```.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: include-read (app, relative_path, parent_docname, content)
|
||||
|
||||
Emitted when a file has been read with the :dudir:`include` directive.
|
||||
The *relative_path* argument is a :py:class:`~pathlib.Path` object representing
|
||||
the relative path of the included file from the :term:`source directory`.
|
||||
The *parent_docname* argument is the name of the document that
|
||||
contains the :dudir:`include` directive.
|
||||
The *source* argument is a list whose single element is
|
||||
the contents of the included file.
|
||||
You can process the contents and replace this item
|
||||
to transform the included content,
|
||||
as with the :event:`source-read` event.
|
||||
|
||||
.. versionadded:: 7.2.5
|
||||
|
||||
.. seealso:: The :dudir:`include` directive and the :event:`source-read` event.
|
||||
|
||||
.. event:: object-description-transform (app, domain, objtype, contentnode)
|
||||
|
||||
Emitted when an object description directive has run. The *domain* and
|
||||
*objtype* arguments are strings indicating object description of the object.
|
||||
And *contentnode* is a content for the object. It can be modified in-place.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
.. event:: doctree-read (app, doctree)
|
||||
|
||||
Emitted when a doctree has been parsed and read by the environment, and is
|
||||
about to be pickled. The *doctree* can be modified in-place.
|
||||
|
||||
.. event:: missing-reference (app, env, node, contnode)
|
||||
|
||||
Emitted when a cross-reference to an object cannot be resolved.
|
||||
If the event handler can resolve the reference, it should return a
|
||||
new docutils node to be inserted in the document tree in place of the node
|
||||
*node*. Usually this node is a :class:`~nodes.reference` node containing
|
||||
*contnode* as a child.
|
||||
If the handler can not resolve the cross-reference,
|
||||
it can either return ``None`` to let other handlers try,
|
||||
or raise :class:`~sphinx.errors.NoUri` to prevent other handlers in
|
||||
trying and suppress a warning about this cross-reference being unresolved.
|
||||
|
||||
:param env: The build environment (``app.builder.env``).
|
||||
:param node: The :class:`~sphinx.addnodes.pending_xref` node to be resolved.
|
||||
Its ``reftype``, ``reftarget``, ``modname`` and ``classname`` attributes
|
||||
determine the type and target of the reference.
|
||||
:param contnode: The node that carries the text and formatting inside the
|
||||
future reference and should be a child of the returned reference node.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: warn-missing-reference (app, domain, node)
|
||||
|
||||
Emitted when a cross-reference to an object cannot be resolved even after
|
||||
:event:`missing-reference`. If the event handler can emit warnings for
|
||||
the missing reference, it should return ``True``. The configuration variables
|
||||
:confval:`nitpick_ignore` and :confval:`nitpick_ignore_regex` prevent the
|
||||
event from being emitted for the corresponding nodes.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. event:: doctree-resolved (app, doctree, docname)
|
||||
|
||||
Emitted when a doctree has been "resolved" by the environment, that is, all
|
||||
references have been resolved and TOCs have been inserted. The *doctree* can
|
||||
be modified in place.
|
||||
|
||||
Here is the place to replace custom nodes that don't have visitor methods in
|
||||
the writers, so that they don't cause errors when the writers encounter them.
|
||||
|
||||
.. event:: env-merge-info (app, env, docnames, other)
|
||||
|
||||
This event is only emitted when parallel reading of documents is enabled. It
|
||||
is emitted once for every subprocess that has read some documents.
|
||||
|
||||
You must handle this event in an extension that stores data in the
|
||||
environment in a custom location. Otherwise the environment in the main
|
||||
process will not be aware of the information stored in the subprocess.
|
||||
|
||||
*other* is the environment object from the subprocess, *env* is the
|
||||
environment from the main process. *docnames* is a set of document names
|
||||
that have been read in the subprocess.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: env-updated (app, env)
|
||||
|
||||
Emitted after reading all documents, when the environment and all
|
||||
doctrees are now up-to-date.
|
||||
|
||||
You can return an iterable of docnames from the handler. These documents
|
||||
will then be considered updated, and will be (re-)written during the writing
|
||||
phase.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The handlers' return value is now used.
|
||||
|
||||
.. event:: env-check-consistency (app, env)
|
||||
|
||||
Emitted when Consistency checks phase. You can check consistency of
|
||||
metadata for whole of documents.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
As a **experimental** event
|
||||
|
||||
.. event:: html-collect-pages (app)
|
||||
|
||||
Emitted when the HTML builder is starting to write non-document pages. You
|
||||
can add pages to write by returning an iterable from this event consisting of
|
||||
``(pagename, context, templatename)``.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. event:: html-page-context (app, pagename, templatename, context, doctree)
|
||||
|
||||
Emitted when the HTML builder has created a context dictionary to render a
|
||||
template with -- this can be used to add custom elements to the context.
|
||||
|
||||
The *pagename* argument is the canonical name of the page being rendered,
|
||||
that is, without ``.html`` suffix and using slashes as path separators. The
|
||||
*templatename* is the name of the template to render, this will be
|
||||
``'page.html'`` for all pages from reST documents.
|
||||
|
||||
The *context* argument is a dictionary of values that are given to the
|
||||
template engine to render the page and can be modified to include custom
|
||||
values. Keys must be strings.
|
||||
|
||||
The *doctree* argument will be a doctree when the page is created from a reST
|
||||
documents; it will be ``None`` when the page is created from an HTML template
|
||||
alone.
|
||||
|
||||
You can return a string from the handler, it will then replace
|
||||
``'page.html'`` as the HTML template for this page.
|
||||
|
||||
.. note:: You can install JS/CSS files for the specific page via
|
||||
:meth:`Sphinx.add_js_file` and :meth:`Sphinx.add_css_file` since
|
||||
v3.5.0.
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The return value can now specify a template name.
|
||||
|
||||
.. event:: linkcheck-process-uri (app, uri)
|
||||
|
||||
Emitted when the linkcheck builder collects hyperlinks from document. *uri*
|
||||
is a collected URI. The event handlers can modify the URI by returning a
|
||||
string.
|
||||
|
||||
.. versionadded:: 4.1
|
||||
|
||||
.. event:: build-finished (app, exception)
|
||||
|
||||
Emitted when a build has finished, before Sphinx exits, usually used for
|
||||
cleanup. This event is emitted even when the build process raised an
|
||||
exception, given as the *exception* argument. The exception is reraised in
|
||||
the application after the event handlers have run. If the build process
|
||||
raised no exception, *exception* will be ``None``. This allows to customize
|
||||
cleanup actions depending on the exception status.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. note:: Moved to :ref:`events`.
|
||||
|
||||
Checking the Sphinx version
|
||||
---------------------------
|
||||
|
@ -11,55 +11,9 @@ Builder API
|
||||
|
||||
It follows this basic workflow:
|
||||
|
||||
.. graphviz::
|
||||
.. graphviz:: /_static/diagrams/sphinx_build_flow.dot
|
||||
: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:
|
||||
|
406
doc/extdev/event_callbacks.rst
Normal file
406
doc/extdev/event_callbacks.rst
Normal file
@ -0,0 +1,406 @@
|
||||
.. _events:
|
||||
|
||||
Event callbacks API
|
||||
===================
|
||||
|
||||
Connecting callback functions to events is a simple way to extend Sphinx,
|
||||
by hooking into the build process at various points.
|
||||
|
||||
Use :meth:`.Sphinx.connect` in an extension's ``setup`` function,
|
||||
or a ``setup`` function in your projects :file:`conf.py`,
|
||||
to connect functions to the events:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def source_read_handler(app, docname, source):
|
||||
print('do something here...')
|
||||
|
||||
def setup(app):
|
||||
app.connect('source-read', source_read_handler)
|
||||
|
||||
.. seealso::
|
||||
|
||||
Extensions can add their own events by using :meth:`.Sphinx.add_event`,
|
||||
and calling them them with
|
||||
:meth:`.Sphinx.emit` or :meth:`.Sphinx.emit_firstresult`.
|
||||
|
||||
Core events overview
|
||||
--------------------
|
||||
|
||||
Below is an overview of the core event that happens during a build.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
1. event.config-inited(app,config)
|
||||
2. event.builder-inited(app)
|
||||
3. event.env-get-outdated(app, env, added, changed, removed)
|
||||
4. event.env-before-read-docs(app, env, docnames)
|
||||
|
||||
for docname in docnames:
|
||||
5. event.env-purge-doc(app, env, docname)
|
||||
|
||||
if doc changed and not removed:
|
||||
6. source-read(app, docname, source)
|
||||
7. run source parsers: text -> docutils.document
|
||||
- parsers can be added with the app.add_source_parser() API
|
||||
8. apply transforms based on priority: docutils.document -> docutils.document
|
||||
- event.doctree-read(app, doctree) is called in the middle of transforms,
|
||||
transforms come before/after this event depending on their priority.
|
||||
|
||||
9. event.env-merge-info(app, env, docnames, other)
|
||||
- if running in parallel mode, this event will be emitted for each process
|
||||
|
||||
10. event.env-updated(app, env)
|
||||
11. event.env-get-updated(app, env)
|
||||
12. event.env-check-consistency(app, env)
|
||||
|
||||
# The updated-docs list can be builder dependent, but generally includes all new/changed documents,
|
||||
# plus any output from `env-get-updated`, and then all "parent" documents in the ToC tree
|
||||
# For builders that output a single page, they are first joined into a single doctree before post-transforms
|
||||
# or the doctree-resolved event is emitted
|
||||
for docname in updated-docs:
|
||||
13. apply post-transforms (by priority): docutils.document -> docutils.document
|
||||
14. event.doctree-resolved(app, doctree, docname)
|
||||
- In the event that any reference nodes fail to resolve, the following may emit:
|
||||
- event.missing-reference(env, node, contnode)
|
||||
- event.warn-missing-reference(domain, node)
|
||||
|
||||
15. Generate output files
|
||||
16. event.build-finished(app, exception)
|
||||
|
||||
Here is also a flow diagram of the events,
|
||||
within the context of the Sphinx build process:
|
||||
|
||||
.. graphviz:: /_static/diagrams/sphinx_core_events_flow.dot
|
||||
:caption: Sphinx core events flow
|
||||
|
||||
Core event details
|
||||
------------------
|
||||
|
||||
Here is a more detailed list of these events.
|
||||
|
||||
.. event:: config-inited (app, config)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param config: :class:`.Config`
|
||||
|
||||
Emitted when the config object has been initialized.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
.. event:: builder-inited (app)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
|
||||
Emitted when the builder object has been created
|
||||
(available as ``app.builder``).
|
||||
|
||||
.. event:: env-get-outdated (app, env, added, changed, removed)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:param added: ``set[str]``
|
||||
:param changed: ``set[str]``
|
||||
:param removed: ``set[str]``
|
||||
:returns: ``list[str]`` of additional docnames to re-read
|
||||
|
||||
Emitted when the environment determines which source files have changed and
|
||||
should be re-read.
|
||||
*added*, *changed* and *removed* are sets of docnames
|
||||
that the environment has determined.
|
||||
You can return a list of docnames to re-read in addition to these.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. event:: env-purge-doc (app, env, docname)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:param docname: ``str``
|
||||
|
||||
Emitted when all traces of a source file should be cleaned from the
|
||||
environment, that is, if the source file is removed or before it is freshly read.
|
||||
This is for extensions that keep their own caches
|
||||
in attributes of the environment.
|
||||
|
||||
For example, there is a cache of all modules on the environment.
|
||||
When a source file has been changed, the cache's entries for the file are cleared,
|
||||
since the module declarations could have been removed from the file.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: env-before-read-docs (app, env, docnames)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:param docnames: ``list[str]``
|
||||
|
||||
Emitted after the environment has determined the list of all added and
|
||||
changed files and just before it reads them.
|
||||
It allows extension authors to reorder
|
||||
the list of docnames (*inplace*) before processing,
|
||||
or add more docnames that Sphinx did not consider changed
|
||||
(but never add any docnames that are not in :attr:`.found_docs`).
|
||||
|
||||
You can also remove document names; do this with caution since it will make
|
||||
Sphinx treat changed files as unchanged.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: source-read (app, docname, content)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param docname: ``str``
|
||||
:param content: ``list[str]``
|
||||
with a single element,
|
||||
representing the content of the included file.
|
||||
|
||||
Emitted when a source file has been read.
|
||||
|
||||
You can process the ``content`` and
|
||||
replace this item to implement source-level transformations.
|
||||
|
||||
For example, if you want to use ``$`` signs to delimit inline math, like in
|
||||
LaTeX, you can use a regular expression to replace ``$...$`` by
|
||||
``:math:`...```.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: include-read (app, relative_path, parent_docname, content)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param relative_path: :class:`~pathlib.Path`
|
||||
representing the included file
|
||||
relative to the :term:`source directory`.
|
||||
:param parent_docname: ``str``
|
||||
of the document name that
|
||||
contains the :dudir:`include` directive.
|
||||
:param content: ``list[str]``
|
||||
with a single element,
|
||||
representing the content of the included file.
|
||||
|
||||
Emitted when a file has been read with the :dudir:`include` directive.
|
||||
|
||||
You can process the ``content`` and replace this item
|
||||
to transform the included content, as with the :event:`source-read` event.
|
||||
|
||||
.. versionadded:: 7.2.5
|
||||
|
||||
.. seealso:: The :dudir:`include` directive and the :event:`source-read` event.
|
||||
|
||||
.. event:: object-description-transform (app, domain, objtype, contentnode)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param domain: ``str``
|
||||
:param objtype: ``str``
|
||||
:param contentnode: :class:`.desc_content`
|
||||
|
||||
Emitted when an object description directive has run. The *domain* and
|
||||
*objtype* arguments are strings indicating object description of the object.
|
||||
And *contentnode* is a content for the object. It can be modified in-place.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
.. event:: doctree-read (app, doctree)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param doctree: :class:`docutils.nodes.document`
|
||||
|
||||
Emitted when a doctree has been parsed and read by the environment, and is
|
||||
about to be pickled.
|
||||
The ``doctree`` can be modified in-place.
|
||||
|
||||
.. event:: missing-reference (app, env, node, contnode)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:param node: The :class:`.pending_xref` node to be resolved.
|
||||
Its ``reftype``, ``reftarget``, ``modname`` and ``classname`` attributes
|
||||
determine the type and target of the reference.
|
||||
:param contnode: The node that carries the text and formatting inside the
|
||||
future reference and should be a child of the returned reference node.
|
||||
:returns: A new node to be inserted in the document tree in place of the node,
|
||||
or ``None`` to let other handlers try.
|
||||
|
||||
Emitted when a cross-reference to an object cannot be resolved.
|
||||
If the event handler can resolve the reference, it should return a
|
||||
new docutils node to be inserted in the document tree in place of the node
|
||||
*node*. Usually this node is a :class:`~nodes.reference` node containing
|
||||
*contnode* as a child.
|
||||
If the handler can not resolve the cross-reference,
|
||||
it can either return ``None`` to let other handlers try,
|
||||
or raise :class:`~sphinx.errors.NoUri` to prevent other handlers in
|
||||
trying and suppress a warning about this cross-reference being unresolved.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. event:: warn-missing-reference (app, domain, node)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param domain: The :class:`.Domain` of the missing reference.
|
||||
:param node: The :class:`.pending_xref` node that could not be resolved.
|
||||
:returns: ``True`` if a warning was emitted, else ``None``
|
||||
|
||||
Emitted when a cross-reference to an object cannot be resolved even after
|
||||
:event:`missing-reference`.
|
||||
If the event handler can emit warnings for the missing reference,
|
||||
it should return ``True``.
|
||||
The configuration variables
|
||||
:confval:`nitpick_ignore` and :confval:`nitpick_ignore_regex`
|
||||
prevent the event from being emitted for the corresponding nodes.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. event:: doctree-resolved (app, doctree, docname)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param doctree: :class:`docutils.nodes.document`
|
||||
:param docname: ``str``
|
||||
|
||||
Emitted when a doctree has been "resolved" by the environment, that is, all
|
||||
references have been resolved and TOCs have been inserted. The *doctree* can
|
||||
be modified in place.
|
||||
|
||||
Here is the place to replace custom nodes that don't have visitor methods in
|
||||
the writers, so that they don't cause errors when the writers encounter them.
|
||||
|
||||
.. event:: env-merge-info (app, env, docnames, other)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:param docnames: ``list[str]``
|
||||
:param other: :class:`.BuildEnvironment`
|
||||
|
||||
This event is only emitted when parallel reading of documents is enabled. It
|
||||
is emitted once for every subprocess that has read some documents.
|
||||
|
||||
You must handle this event in an extension that stores data in the
|
||||
environment in a custom location. Otherwise the environment in the main
|
||||
process will not be aware of the information stored in the subprocess.
|
||||
|
||||
*other* is the environment object from the subprocess, *env* is the
|
||||
environment from the main process. *docnames* is a set of document names
|
||||
that have been read in the subprocess.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: env-updated (app, env)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:returns: iterable of ``str``
|
||||
|
||||
Emitted after reading all documents, when the environment and all
|
||||
doctrees are now up-to-date.
|
||||
|
||||
You can return an iterable of docnames from the handler. These documents
|
||||
will then be considered updated, and will be (re-)written during the writing
|
||||
phase.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The handlers' return value is now used.
|
||||
|
||||
.. event:: env-get-updated (app, env)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
:returns: iterable of ``str``
|
||||
|
||||
Emitted when the environment determines which source files have changed and
|
||||
should be re-read.
|
||||
You can return an iterable of docnames to re-read.
|
||||
|
||||
.. event:: env-check-consistency (app, env)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param env: :class:`.BuildEnvironment`
|
||||
|
||||
Emitted when Consistency checks phase. You can check consistency of
|
||||
metadata for whole of documents.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
.. event:: build-finished (app, exception)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param exception: ``Exception`` or ``None``
|
||||
|
||||
Emitted when a build has finished, before Sphinx exits, usually used for
|
||||
cleanup. This event is emitted even when the build process raised an
|
||||
exception, given as the *exception* argument. The exception is reraised in
|
||||
the application after the event handlers have run. If the build process
|
||||
raised no exception, *exception* will be ``None``. This allows to customize
|
||||
cleanup actions depending on the exception status.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
Builder specific events
|
||||
-----------------------
|
||||
|
||||
These events are emitted by specific builders.
|
||||
|
||||
.. event:: html-collect-pages (app)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:returns: iterable of ``(pagename, context, templatename)``
|
||||
where *pagename* and *templatename* are strings and
|
||||
*context* is a ``dict[str, Any]``.
|
||||
|
||||
Emitted when the HTML builder is starting to write non-document pages.
|
||||
|
||||
You can add pages to write by returning an iterable from this event.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. event:: html-page-context (app, pagename, templatename, context, doctree)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param pagename: ``str``
|
||||
:param templatename: ``str``
|
||||
:param context: ``dict[str, Any]``
|
||||
:param doctree: :class:`docutils.nodes.document` or ``None``
|
||||
:returns: ``str`` or ``None``
|
||||
|
||||
Emitted when the HTML builder has created a context dictionary to render a
|
||||
template with -- this can be used to add custom elements to the context.
|
||||
|
||||
The *pagename* argument is the canonical name of the page being rendered,
|
||||
that is, without ``.html`` suffix and using slashes as path separators.
|
||||
The *templatename* is the name of the template to render, this will be
|
||||
``'page.html'`` for all pages from reST documents.
|
||||
|
||||
The *context* argument is a dictionary of values that are given to the
|
||||
template engine to render the page and can be modified to include custom
|
||||
values.
|
||||
|
||||
The *doctree* argument will be a doctree when the page is created from a reST
|
||||
documents; it will be ``None`` when the page is created from an HTML template
|
||||
alone.
|
||||
|
||||
You can return a string from the handler, it will then replace
|
||||
``'page.html'`` as the HTML template for this page.
|
||||
|
||||
.. tip::
|
||||
|
||||
You can install JS/CSS files for the specific page via
|
||||
:meth:`.Sphinx.add_js_file` and :meth:`.Sphinx.add_css_file`
|
||||
(since v3.5.0).
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
The return value can now specify a template name.
|
||||
|
||||
.. event:: linkcheck-process-uri (app, uri)
|
||||
|
||||
:param app: :class:`.Sphinx`
|
||||
:param uri: ``str`` of the collected URI
|
||||
:returns: ``str`` or ``None``
|
||||
|
||||
Emitted when the linkcheck builder collects hyperlinks from document.
|
||||
|
||||
The event handlers can modify the URI by returning a string.
|
||||
|
||||
.. versionadded:: 4.1
|
@ -204,6 +204,7 @@ disposal when developing Sphinx extensions. Some are core to Sphinx
|
||||
:maxdepth: 2
|
||||
|
||||
appapi
|
||||
event_callbacks
|
||||
projectapi
|
||||
envapi
|
||||
builderapi
|
||||
|
@ -15,9 +15,13 @@ class EnvironmentCollector:
|
||||
"""An EnvironmentCollector is a specific data collector from each document.
|
||||
|
||||
It gathers data and stores :py:class:`BuildEnvironment
|
||||
<sphinx.environment.BuildEnvironment>` as a database. Examples of specific
|
||||
data would be images, download files, section titles, metadatas, index
|
||||
<sphinx.environment.BuildEnvironment>` as a database.
|
||||
Examples of specific data would be images, download files, section titles, metadatas, index
|
||||
entries and toctrees, etc.
|
||||
|
||||
.. note::
|
||||
|
||||
This class essentially wraps a sub-set of :ref:`Sphinx event callbacks <events>`.
|
||||
"""
|
||||
|
||||
listener_ids: dict[str, int] | None = None
|
||||
@ -42,6 +46,8 @@ class EnvironmentCollector:
|
||||
"""Remove specified data of a document.
|
||||
|
||||
This method is called on the removal of the document.
|
||||
|
||||
.. seealso:: :event:`env-purge-doc`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -49,6 +55,8 @@ class EnvironmentCollector:
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
"""Merge in specified data regarding docnames from a different `BuildEnvironment`
|
||||
object which coming from a subprocess in parallel builds.
|
||||
|
||||
.. seealso:: :event:`env-merge-info`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -56,13 +64,17 @@ class EnvironmentCollector:
|
||||
"""Process a document and gather specific data from it.
|
||||
|
||||
This method is called after the document is read.
|
||||
|
||||
.. seealso:: :event:`doctree-read`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_updated_docs(self, app: Sphinx, env: BuildEnvironment) -> list[str]:
|
||||
"""Return a list of docnames to re-read.
|
||||
|
||||
This methods is called after reading the whole of documents (experimental).
|
||||
This method is called after reading the whole of documents.
|
||||
|
||||
.. seealso:: :event:`env-get-updated`
|
||||
"""
|
||||
return []
|
||||
|
||||
@ -70,6 +82,8 @@ class EnvironmentCollector:
|
||||
added: set[str], changed: set[str], removed: set[str]) -> list[str]:
|
||||
"""Return a list of docnames to re-read.
|
||||
|
||||
This methods is called before reading the documents.
|
||||
This method is called before reading the documents.
|
||||
|
||||
.. seealso:: :event:`env-get-outdated`
|
||||
"""
|
||||
return []
|
||||
|
Loading…
Reference in New Issue
Block a user