Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

馃憣 Add CoreEvent enum as argument for Sphinx.callback #12259

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 9 additions & 3 deletions doc/extdev/appapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions sphinx/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
111 changes: 110 additions & 1 deletion sphinx/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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."""

Expand All @@ -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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could take this further and make the CoreEvent enum the preferred approach (without breaking existing code)

Suggested change
def connect(self, name: str | CoreEvent, callback: Callable, priority: int) -> int:
@deprecated(reason="...")
@overload
def connect(self, name: str, callback: Callable, priority: int) -> int: ...
@overload
def connect(self, name: CoreEvent, callback: Callable, priority: int) -> int: ...
def connect(self, name: str | CoreEvent, callback: Callable, priority: int) -> int:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deprecated decorator is only a 3.13 feature :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(In addition, you still want to connect with your own events)

"""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)

Expand Down