diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst index 10d030be14c..4e0f719bd37 100644 --- a/doc/extdev/appapi.rst +++ b/doc/extdev/appapi.rst @@ -202,6 +202,10 @@ type for that event: Here is a more detailed list of these events. +.. seealso:: + + .. autoclass:: CoreEvent + .. event:: builder-inited (app) Emitted when the builder object has been created. It is available as @@ -260,7 +264,7 @@ Here is a more detailed list of these events. .. versionadded:: 0.5 -.. event:: include-read (app, relative_path, parent_docname, content) +.. event:: include-read (app, relative_path, parent_docname, source) Emitted when a file has been read with the :dudir:`include` directive. The *relative_path* argument is a :py:class:`~pathlib.Path` object representing @@ -361,8 +365,10 @@ Here is a more detailed list of these events. .. event:: env-check-consistency (app, env) - Emitted when Consistency checks phase. You can check consistency of - metadata for whole of documents. + Emitted before caching the environment. + + Here you can check for consistency of data in the environment, + before it is stored. .. versionadded:: 1.6 diff --git a/sphinx/application.py b/sphinx/application.py index 7d16d9ab2b2..d257fde7c32 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -25,7 +25,7 @@ from sphinx.config import ENUM, Config, _ConfigRebuild from sphinx.environment import BuildEnvironment from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError -from sphinx.events import EventManager +from sphinx.events import CoreEvent, EventManager from sphinx.highlighting import lexer_classes from sphinx.locale import __ from sphinx.project import Project @@ -424,7 +424,7 @@ def require_sphinx(version: tuple[int, int] | str) -> None: raise VersionRequirementError(req) # event interface - def connect(self, event: str, callback: Callable, priority: int = 500) -> int: + def connect(self, event: str | CoreEvent, callback: Callable, priority: int = 500) -> int: """Register *callback* to be called when *event* is emitted. For details on available core events and the arguments of callback diff --git a/sphinx/events.py b/sphinx/events.py index af8dfb4e2cf..6e196c0239a 100644 --- a/sphinx/events.py +++ b/sphinx/events.py @@ -7,6 +7,7 @@ import contextlib from collections import defaultdict +from enum import Enum from operator import attrgetter from typing import TYPE_CHECKING, Any, Callable, NamedTuple @@ -49,6 +50,112 @@ class EventListener(NamedTuple): } +class CoreEvent(Enum): + """Enumeration of core events. + + .. versionadded:: 7.3 + """ + + builder_inited = 'builder-inited' + """Emitted when the builder object has been created:: + + func(app: Sphinx) + """ + config_inited = 'config-inited' + """Emitted when the config object has been initialized:: + + func(app: Sphinx, config: Config) + """ + env_get_outdated = 'env-get-outdated' + """Emitted when the environment determines which source files + have changed and should be re-read:: + + func(app: Sphinx, env: BuildEnvironment, added: set, changed: set, removed: set) + """ + env_get_updated = 'env-get-updated' + """Emitted when the environment has been updated:: + + func(app: Sphinx, env: BuildEnvironment) + """ + env_purge_doc = 'env-purge-doc' + """Emitted when all traces of a source file should be cleaned from the:: + + func(app: Sphinx, env: BuildEnvironment, docname: str) + """ + env_before_read_docs = 'env-before-read-docs' + """Emitted after the environment has determined the list of all added and + changed files and just before it reads them:: + + func(app: Sphinx, env: BuildEnvironment, docnames: list[str]) + """ + env_check_consistency = 'env-check-consistency' + """Emitted before caching the environment:: + + func(app: Sphinx, env: BuildEnvironment) + """ + source_read = 'source-read' + """Emitted when a source file has been read:: + + func(app: Sphinx, docname: str, source: list[str]) + + The *source* argument is a list whose single element is the contents of the source file. + + .. versionadded:: 7.2.5 + """ + include_read = 'include-read' + """Emitted when a file has been read with the ``include`` directive.:: + + func(app: Sphinx, relative_path: Path, parent_docname: str, source: list[str]) + + The *source* argument is a list whose single element is the contents of the source file. + """ + doctree_read = 'doctree-read' + """Emitted when a doctree has been parsed and read by the environment, + and is about to be pickled:: + + func(app: Sphinx, doctree: nodes.document) + + The *doctree* can be modified in-place. + """ + env_merge_info = 'env-merge-info' + """Emitted once for every subprocess that has read some documents:: + + func(app: Sphinx, env: BuildEnvironment, + docnames: set[str], other_env: BuildEnvironment) + + This event is only emitted when parallel reading of documents is enabled. + """ + missing_reference = 'missing-reference' + """Emitted when a cross-reference to an object cannot be resolved.:: + + func(app: Sphinx, env: BuildEnvironment, node: nodes.Element, contnode: nodes.Element) + """ + warn_missing_reference = 'warn-missing-reference' + """Emitted when a cross-reference to an object cannot be resolved + (even after ``missing-reference``):: + + func(app: Sphinx, domain: Domain, node: nodes.Element) + """ + doctree_resolved = 'doctree-resolved' + """Emitted when a doctree has been "resolved" by the environment:: + + func(app: Sphinx, doctree: nodes.document, docname: str) + + The *doctree* can be modified in place. + """ + env_updated = 'env-updated' + """Emitted after reading all documents, + when the environment and all doctrees are now up-to-date:: + + func(app: Sphinx, env: BuildEnvironment) + """ + build_finished = 'build-finished' + """Emitted when a build has finished, before Sphinx exits:: + + func(app: Sphinx, exception: Exception | None) + """ + + class EventManager: """Event manager for Sphinx.""" @@ -64,8 +171,10 @@ def add(self, name: str) -> None: raise ExtensionError(__('Event %r already present') % name) self.events[name] = '' - def connect(self, name: str, callback: Callable, priority: int) -> int: + def connect(self, name: str | CoreEvent, callback: Callable, priority: int) -> int: """Connect a handler to specific event.""" + if isinstance(name, CoreEvent): + name = name.value if name not in self.events: raise ExtensionError(__('Unknown event name: %s') % name)