diff --git a/doc/_static/diagrams/sphinx_build_flow.dot b/doc/_static/diagrams/sphinx_build_flow.dot new file mode 100644 index 000000000..0e736f537 --- /dev/null +++ b/doc/_static/diagrams/sphinx_build_flow.dot @@ -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__ | build" + ]; + "Sphinx":init -> "Builder.init"; + "Sphinx":build -> "Builder.build_all"; + "Sphinx":build -> "Builder.build_specific"; + "Builder.build_update" [ + shape=record + label = " 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 = " 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"; +} diff --git a/doc/_static/diagrams/sphinx_core_events_flow.dot b/doc/_static/diagrams/sphinx_core_events_flow.dot new file mode 100644 index 000000000..f60076089 --- /dev/null +++ b/doc/_static/diagrams/sphinx_core_events_flow.dot @@ -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 = " Sphinx.__init__() | 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 | + read | + after read | + write | + 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"}; +} diff --git a/doc/conf.py b/doc/conf.py index 41018240b..abcd2acbd 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -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 diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index 10d030be1..c47b6090a 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -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 --------------------------- diff --git a/doc/extdev/builderapi.rst b/doc/extdev/builderapi.rst index 648431dd3..9259aaa73 100644 --- a/doc/extdev/builderapi.rst +++ b/doc/extdev/builderapi.rst @@ -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__ | build" - ]; - "Sphinx":init -> "Builder.init"; - "Sphinx":build -> "Builder.build_all"; - "Sphinx":build -> "Builder.build_specific"; - "Builder.build_update" [ - shape=record - label = " 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 = " 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: diff --git a/doc/extdev/event_callbacks.rst b/doc/extdev/event_callbacks.rst new file mode 100644 index 000000000..684102fc0 --- /dev/null +++ b/doc/extdev/event_callbacks.rst @@ -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 diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst index 8332315ff..a451f80f9 100644 --- a/doc/extdev/index.rst +++ b/doc/extdev/index.rst @@ -204,6 +204,7 @@ disposal when developing Sphinx extensions. Some are core to Sphinx :maxdepth: 2 appapi + event_callbacks projectapi envapi builderapi diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py index c12dd50b3..52b5a60b4 100644 --- a/sphinx/environment/collectors/__init__.py +++ b/sphinx/environment/collectors/__init__.py @@ -15,9 +15,13 @@ class EnvironmentCollector: """An EnvironmentCollector is a specific data collector from each document. It gathers data and stores :py:class:`BuildEnvironment - ` as a database. Examples of specific - data would be images, download files, section titles, metadatas, index + ` 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 `. """ 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 []