Enable automatic formatting for `sphinx/application.py`

This commit is contained in:
Adam Turner 2024-12-11 00:27:24 +00:00
parent a025fe0c9c
commit 6e4c4f11eb
2 changed files with 334 additions and 225 deletions

View File

@ -393,7 +393,6 @@ required-imports = [
preview = true preview = true
quote-style = "single" quote-style = "single"
exclude = [ exclude = [
"sphinx/application.py",
"sphinx/builders/latex/constants.py", "sphinx/builders/latex/constants.py",
"sphinx/config.py", "sphinx/config.py",
"sphinx/domains/__init__.py", "sphinx/domains/__init__.py",

View File

@ -145,14 +145,25 @@ class Sphinx:
outdir = _StrPathProperty() outdir = _StrPathProperty()
doctreedir = _StrPathProperty() doctreedir = _StrPathProperty()
def __init__(self, srcdir: str | os.PathLike[str], confdir: str | os.PathLike[str] | None, def __init__(
outdir: str | os.PathLike[str], doctreedir: str | os.PathLike[str], self,
buildername: str, confoverrides: dict | None = None, srcdir: str | os.PathLike[str],
status: IO[str] | None = sys.stdout, warning: IO[str] | None = sys.stderr, confdir: str | os.PathLike[str] | None,
freshenv: bool = False, warningiserror: bool = False, outdir: str | os.PathLike[str],
tags: Sequence[str] = (), doctreedir: str | os.PathLike[str],
verbosity: int = 0, parallel: int = 0, keep_going: bool = False, buildername: str,
pdb: bool = False, exception_on_warning: bool = False) -> None: confoverrides: dict | None = None,
status: IO[str] | None = sys.stdout,
warning: IO[str] | None = sys.stderr,
freshenv: bool = False,
warningiserror: bool = False,
tags: Sequence[str] = (),
verbosity: int = 0,
parallel: int = 0,
keep_going: bool = False,
pdb: bool = False,
exception_on_warning: bool = False,
) -> None:
"""Initialize the Sphinx application. """Initialize the Sphinx application.
:param srcdir: The path to the source directory. :param srcdir: The path to the source directory.
@ -187,16 +198,19 @@ class Sphinx:
self.doctreedir = _StrPath(doctreedir).resolve() self.doctreedir = _StrPath(doctreedir).resolve()
if not self.srcdir.is_dir(): if not self.srcdir.is_dir():
raise ApplicationError(__('Cannot find source directory (%s)') % raise ApplicationError(
self.srcdir) __('Cannot find source directory (%s)') % self.srcdir
)
if self.outdir.exists() and not self.outdir.is_dir(): if self.outdir.exists() and not self.outdir.is_dir():
raise ApplicationError(__('Output directory (%s) is not a directory') % raise ApplicationError(
self.outdir) __('Output directory (%s) is not a directory') % self.outdir
)
if self.srcdir == self.outdir: if self.srcdir == self.outdir:
raise ApplicationError(__('Source directory and destination ' raise ApplicationError(
'directory cannot be identical')) __('Source directory and destination directory cannot be identical')
)
self.parallel = parallel self.parallel = parallel
@ -245,10 +259,17 @@ class Sphinx:
self._init_i18n() self._init_i18n()
# check the Sphinx version if requested # check the Sphinx version if requested
if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__: if (
self.config.needs_sphinx
and self.config.needs_sphinx > sphinx.__display_version__
):
raise VersionRequirementError( raise VersionRequirementError(
__('This project needs at least Sphinx v%s and therefore cannot ' __(
'be built with this version.') % self.config.needs_sphinx) 'This project needs at least Sphinx v%s and therefore cannot '
'be built with this version.'
)
% self.config.needs_sphinx
)
# load all built-in extension modules, first-party extension modules, # load all built-in extension modules, first-party extension modules,
# and first-party themes # and first-party themes
@ -268,15 +289,17 @@ class Sphinx:
# the config file itself can be an extension # the config file itself can be an extension
if self.config.setup: if self.config.setup:
prefix = __('while setting up extension %s:') % "conf.py" prefix = __('while setting up extension %s:') % 'conf.py'
with prefixed_warnings(prefix): with prefixed_warnings(prefix):
if callable(self.config.setup): if callable(self.config.setup):
self.config.setup(self) self.config.setup(self)
else: else:
raise ConfigError( raise ConfigError(
__("'setup' as currently defined in conf.py isn't a Python callable. " __(
"Please modify its definition to make it a callable function. " "'setup' as currently defined in conf.py isn't a Python callable. "
"This is needed for conf.py to behave as a Sphinx extension."), 'Please modify its definition to make it a callable function. '
'This is needed for conf.py to behave as a Sphinx extension.'
),
) )
# Report any warnings for overrides. # Report any warnings for overrides.
@ -309,22 +332,30 @@ class Sphinx:
"""Load translated strings from the configured localedirs if enabled in """Load translated strings from the configured localedirs if enabled in
the configuration. the configuration.
""" """
logger.info(bold(__('loading translations [%s]... ')), self.config.language, logger.info(
nonl=True) bold(__('loading translations [%s]... ')), self.config.language, nonl=True
)
# compile mo files if sphinx.po file in user locale directories are updated # compile mo files if sphinx.po file in user locale directories are updated
repo = CatalogRepository(self.srcdir, self.config.locale_dirs, repo = CatalogRepository(
self.config.language, self.config.source_encoding) self.srcdir,
self.config.locale_dirs,
self.config.language,
self.config.source_encoding,
)
for catalog in repo.catalogs: for catalog in repo.catalogs:
if catalog.domain == 'sphinx' and catalog.is_outdated(): if catalog.domain == 'sphinx' and catalog.is_outdated():
catalog.write_mo(self.config.language, catalog.write_mo(
self.config.gettext_allow_fuzzy_translations) self.config.language, self.config.gettext_allow_fuzzy_translations
)
locale_dirs: list[_StrPath | None] = list(repo.locale_dirs) locale_dirs: list[_StrPath | None] = list(repo.locale_dirs)
locale_dirs += [None] locale_dirs += [None]
locale_dirs += [_StrPath(package_dir, 'locale')] locale_dirs += [_StrPath(package_dir, 'locale')]
self.translator, has_translation = locale.init(locale_dirs, self.config.language) self.translator, has_translation = locale.init(
locale_dirs, self.config.language
)
if has_translation or self.config.language == 'en': if has_translation or self.config.language == 'en':
logger.info(__('done')) logger.info(__('done'))
else: else:
@ -374,7 +405,9 @@ class Sphinx:
# ---- main "build" method ------------------------------------------------- # ---- main "build" method -------------------------------------------------
def build(self, force_all: bool = False, filenames: list[str] | None = None) -> None: def build(
self, force_all: bool = False, filenames: list[str] | None = None
) -> None:
self.phase = BuildPhase.READING self.phase = BuildPhase.READING
try: try:
if force_all: if force_all:
@ -401,8 +434,10 @@ class Sphinx:
elif self._warncount == 1: elif self._warncount == 1:
if self._fail_on_warnings: if self._fail_on_warnings:
self.statuscode = 1 self.statuscode = 1
msg = __('build finished with problems, 1 warning ' msg = __(
'(with warnings treated as errors).') 'build finished with problems, 1 warning '
'(with warnings treated as errors).'
)
elif self.statuscode != 0: elif self.statuscode != 0:
msg = __('build finished with problems, 1 warning.') msg = __('build finished with problems, 1 warning.')
else: else:
@ -411,8 +446,10 @@ class Sphinx:
else: else:
if self._fail_on_warnings: if self._fail_on_warnings:
self.statuscode = 1 self.statuscode = 1
msg = __('build finished with problems, %s warnings ' msg = __(
'(with warnings treated as errors).') 'build finished with problems, %s warnings '
'(with warnings treated as errors).'
)
elif self.statuscode != 0: elif self.statuscode != 0:
msg = __('build finished with problems, %s warnings.') msg = __('build finished with problems, %s warnings.')
else: else:
@ -421,10 +458,13 @@ class Sphinx:
if self.statuscode == 0 and self.builder.epilog: if self.statuscode == 0 and self.builder.epilog:
logger.info('') logger.info('')
logger.info(self.builder.epilog, { logger.info(
'outdir': relpath(self.outdir), self.builder.epilog,
'project': self.config.project, {
}) 'outdir': relpath(self.outdir),
'project': self.config.project,
},
)
self.builder.cleanup() self.builder.cleanup()
@ -465,235 +505,214 @@ class Sphinx:
# ---- Core events ------------------------------------------------------- # ---- Core events -------------------------------------------------------
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['config-inited'], event: Literal['config-inited'],
callback: Callable[[Sphinx, Config], None], callback: Callable[[Sphinx, Config], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['builder-inited'], event: Literal['builder-inited'],
callback: Callable[[Sphinx], None], callback: Callable[[Sphinx], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-get-outdated'], event: Literal['env-get-outdated'],
callback: Callable[ callback: Callable[
[Sphinx, BuildEnvironment, Set[str], Set[str], Set[str]], Sequence[str] [Sphinx, BuildEnvironment, Set[str], Set[str], Set[str]], Sequence[str]
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-before-read-docs'], event: Literal['env-before-read-docs'],
callback: Callable[[Sphinx, BuildEnvironment, list[str]], None], callback: Callable[[Sphinx, BuildEnvironment, list[str]], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-purge-doc'], event: Literal['env-purge-doc'],
callback: Callable[[Sphinx, BuildEnvironment, str], None], callback: Callable[[Sphinx, BuildEnvironment, str], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['source-read'], event: Literal['source-read'],
callback: Callable[[Sphinx, str, list[str]], None], callback: Callable[[Sphinx, str, list[str]], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['include-read'], event: Literal['include-read'],
callback: Callable[[Sphinx, Path, str, list[str]], None], callback: Callable[[Sphinx, Path, str, list[str]], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['doctree-read'], event: Literal['doctree-read'],
callback: Callable[[Sphinx, nodes.document], None], callback: Callable[[Sphinx, nodes.document], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-merge-info'], event: Literal['env-merge-info'],
callback: Callable[ callback: Callable[
[Sphinx, BuildEnvironment, Set[str], BuildEnvironment], None [Sphinx, BuildEnvironment, Set[str], BuildEnvironment], None
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-updated'], event: Literal['env-updated'],
callback: Callable[[Sphinx, BuildEnvironment], str], callback: Callable[[Sphinx, BuildEnvironment], str],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-get-updated'], event: Literal['env-get-updated'],
callback: Callable[[Sphinx, BuildEnvironment], Iterable[str]], callback: Callable[[Sphinx, BuildEnvironment], Iterable[str]],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['env-check-consistency'], event: Literal['env-check-consistency'],
callback: Callable[[Sphinx, BuildEnvironment], None], callback: Callable[[Sphinx, BuildEnvironment], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['write-started'], event: Literal['write-started'],
callback: Callable[[Sphinx, Builder], None], callback: Callable[[Sphinx, Builder], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['doctree-resolved'], event: Literal['doctree-resolved'],
callback: Callable[[Sphinx, nodes.document, str], None], callback: Callable[[Sphinx, nodes.document, str], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['missing-reference'], event: Literal['missing-reference'],
callback: Callable[ callback: Callable[
[Sphinx, BuildEnvironment, addnodes.pending_xref, nodes.TextElement], [Sphinx, BuildEnvironment, addnodes.pending_xref, nodes.TextElement],
nodes.reference | None, nodes.reference | None,
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['warn-missing-reference'], event: Literal['warn-missing-reference'],
callback: Callable[[Sphinx, Domain, addnodes.pending_xref], bool | None], callback: Callable[[Sphinx, Domain, addnodes.pending_xref], bool | None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['build-finished'], event: Literal['build-finished'],
callback: Callable[[Sphinx, Exception | None], None], callback: Callable[[Sphinx, Exception | None], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
# ---- Events from builtin builders -------------------------------------- # ---- Events from builtin builders --------------------------------------
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['html-collect-pages'], event: Literal['html-collect-pages'],
callback: Callable[[Sphinx], Iterable[tuple[str, dict[str, Any], str]]], callback: Callable[[Sphinx], Iterable[tuple[str, dict[str, Any], str]]],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['html-page-context'], event: Literal['html-page-context'],
callback: Callable[ callback: Callable[
[Sphinx, str, str, dict[str, Any], nodes.document], str | None [Sphinx, str, str, dict[str, Any], nodes.document], str | None
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['linkcheck-process-uri'], event: Literal['linkcheck-process-uri'],
callback: Callable[[Sphinx, str], str | None], callback: Callable[[Sphinx, str], str | None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
# ---- Events from builtin extensions-- ---------------------------------- # ---- Events from builtin extensions-- ----------------------------------
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['object-description-transform'], event: Literal['object-description-transform'],
callback: Callable[[Sphinx, str, str, addnodes.desc_content], None], callback: Callable[[Sphinx, str, str, addnodes.desc_content], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
# ---- Events from first-party extensions -------------------------------- # ---- Events from first-party extensions --------------------------------
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['autodoc-process-docstring'], event: Literal['autodoc-process-docstring'],
callback: _AutodocProcessDocstringListener, callback: _AutodocProcessDocstringListener,
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['autodoc-before-process-signature'], event: Literal['autodoc-before-process-signature'],
callback: Callable[[Sphinx, Any, bool], None], callback: Callable[[Sphinx, Any, bool], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['autodoc-process-signature'], event: Literal['autodoc-process-signature'],
callback: Callable[ callback: Callable[
[ [
Sphinx, Sphinx,
Literal['module', 'class', 'exception', 'function', 'method', 'attribute'], Literal[
'module', 'class', 'exception', 'function', 'method', 'attribute'
],
str, str,
Any, Any,
dict[str, bool], dict[str, bool],
@ -702,27 +721,27 @@ class Sphinx:
], ],
tuple[str | None, str | None] | None, tuple[str | None, str | None] | None,
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['autodoc-process-bases'], event: Literal['autodoc-process-bases'],
callback: Callable[[Sphinx, str, Any, dict[str, bool], list[str]], None], callback: Callable[[Sphinx, str, Any, dict[str, bool], list[str]], None],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['autodoc-skip-member'], event: Literal['autodoc-skip-member'],
callback: Callable[ callback: Callable[
[ [
Sphinx, Sphinx,
Literal['module', 'class', 'exception', 'function', 'method', 'attribute'], Literal[
'module', 'class', 'exception', 'function', 'method', 'attribute'
],
str, str,
Any, Any,
bool, bool,
@ -730,21 +749,19 @@ class Sphinx:
], ],
bool, bool,
], ],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['todo-defined'], event: Literal['todo-defined'],
callback: Callable[[Sphinx, todo_node], None], callback: Callable[[Sphinx, todo_node], None],
priority: int = 500, priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['viewcode-find-source'], event: Literal['viewcode-find-source'],
callback: Callable[ callback: Callable[
@ -752,28 +769,25 @@ class Sphinx:
tuple[str, dict[str, tuple[Literal['class', 'def', 'other'], int, int]]], tuple[str, dict[str, tuple[Literal['class', 'def', 'other'], int, int]]],
], ],
priority: int = 500, priority: int = 500,
) -> int: ) -> int: ...
...
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: Literal['viewcode-follow-imported'], event: Literal['viewcode-follow-imported'],
callback: Callable[[Sphinx, str, str], str | None], callback: Callable[[Sphinx, str, str], str | None],
priority: int = 500, priority: int = 500,
) -> int: ) -> int: ...
...
# ---- Catch-all --------------------------------------------------------- # ---- Catch-all ---------------------------------------------------------
@overload @overload
def connect( def connect( # NoQA: E704
self, self,
event: str, event: str,
callback: Callable[..., Any], callback: Callable[..., Any],
priority: int = 500 priority: int = 500,
) -> int: ) -> int: ...
...
# event interface # event interface
def connect(self, event: str, callback: Callable, priority: int = 500) -> int: def connect(self, event: str, callback: Callable, priority: int = 500) -> int:
@ -793,8 +807,13 @@ class Sphinx:
Support *priority* Support *priority*
""" """
listener_id = self.events.connect(event, callback, priority) listener_id = self.events.connect(event, callback, priority)
logger.debug('[app] connecting event %r (%d): %r [id=%s]', logger.debug(
event, priority, callback, listener_id) '[app] connecting event %r (%d): %r [id=%s]',
event,
priority,
callback,
listener_id,
)
return listener_id return listener_id
def disconnect(self, listener_id: int) -> None: def disconnect(self, listener_id: int) -> None:
@ -805,8 +824,12 @@ class Sphinx:
logger.debug('[app] disconnecting event: [id=%s]', listener_id) logger.debug('[app] disconnecting event: [id=%s]', listener_id)
self.events.disconnect(listener_id) self.events.disconnect(listener_id)
def emit(self, event: str, *args: Any, def emit(
allowed_exceptions: tuple[type[Exception], ...] = ()) -> list: self,
event: str,
*args: Any,
allowed_exceptions: tuple[type[Exception], ...] = (),
) -> list:
"""Emit *event* and pass *arguments* to the callback functions. """Emit *event* and pass *arguments* to the callback functions.
Return the return values of all callbacks as a list. Do not emit core Return the return values of all callbacks as a list. Do not emit core
@ -822,8 +845,12 @@ class Sphinx:
""" """
return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions) return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions)
def emit_firstresult(self, event: str, *args: Any, def emit_firstresult(
allowed_exceptions: tuple[type[Exception], ...] = ()) -> Any: self,
event: str,
*args: Any,
allowed_exceptions: tuple[type[Exception], ...] = (),
) -> Any:
"""Emit *event* and pass *arguments* to the callback functions. """Emit *event* and pass *arguments* to the callback functions.
Return the result of the first callback that doesn't return ``None``. Return the result of the first callback that doesn't return ``None``.
@ -837,8 +864,9 @@ class Sphinx:
Added *allowed_exceptions* to specify path-through exceptions Added *allowed_exceptions* to specify path-through exceptions
""" """
return self.events.emit_firstresult(event, *args, return self.events.emit_firstresult(
allowed_exceptions=allowed_exceptions) event, *args, allowed_exceptions=allowed_exceptions
)
# registering addon parts # registering addon parts
@ -855,7 +883,10 @@ class Sphinx:
self.registry.add_builder(builder, override=override) self.registry.add_builder(builder, override=override)
def add_config_value( def add_config_value(
self, name: str, default: Any, rebuild: _ConfigRebuild, self,
name: str,
default: Any,
rebuild: _ConfigRebuild,
types: type | Collection[type] | ENUM = (), types: type | Collection[type] | ENUM = (),
description: str = '', description: str = '',
) -> None: ) -> None:
@ -908,8 +939,12 @@ class Sphinx:
logger.debug('[app] adding event: %r', name) logger.debug('[app] adding event: %r', name)
self.events.add(name) self.events.add(name)
def set_translator(self, name: str, translator_class: type[nodes.NodeVisitor], def set_translator(
override: bool = False) -> None: self,
name: str,
translator_class: type[nodes.NodeVisitor],
override: bool = False,
) -> None:
"""Register or override a Docutils translator class. """Register or override a Docutils translator class.
This is used to register a custom output translator or to replace a This is used to register a custom output translator or to replace a
@ -927,8 +962,12 @@ class Sphinx:
""" """
self.registry.add_translator(name, translator_class, override=override) self.registry.add_translator(name, translator_class, override=override)
def add_node(self, node: type[Element], override: bool = False, def add_node(
**kwargs: tuple[Callable, Callable | None]) -> None: self,
node: type[Element],
override: bool = False,
**kwargs: tuple[Callable, Callable | None],
) -> None:
"""Register a Docutils node class. """Register a Docutils node class.
This is necessary for Docutils internals. It may also be used in the This is necessary for Docutils internals. It may also be used in the
@ -965,15 +1004,26 @@ class Sphinx:
""" """
logger.debug('[app] adding node: %r', (node, kwargs)) logger.debug('[app] adding node: %r', (node, kwargs))
if not override and docutils.is_node_registered(node): if not override and docutils.is_node_registered(node):
logger.warning(__('node class %r is already registered, ' logger.warning(
'its visitors will be overridden'), __(
node.__name__, type='app', subtype='add_node') 'node class %r is already registered, '
'its visitors will be overridden'
),
node.__name__,
type='app',
subtype='add_node',
)
docutils.register_node(node) docutils.register_node(node)
self.registry.add_translation_handlers(node, **kwargs) self.registry.add_translation_handlers(node, **kwargs)
def add_enumerable_node(self, node: type[Element], figtype: str, def add_enumerable_node(
title_getter: TitleGetter | None = None, override: bool = False, self,
**kwargs: tuple[Callable, Callable]) -> None: node: type[Element],
figtype: str,
title_getter: TitleGetter | None = None,
override: bool = False,
**kwargs: tuple[Callable, Callable],
) -> None:
"""Register a Docutils node class as a numfig target. """Register a Docutils node class as a numfig target.
Sphinx numbers the node automatically. And then the users can refer it Sphinx numbers the node automatically. And then the users can refer it
@ -997,10 +1047,14 @@ class Sphinx:
.. versionadded:: 1.4 .. versionadded:: 1.4
""" """
self.registry.add_enumerable_node(node, figtype, title_getter, override=override) self.registry.add_enumerable_node(
node, figtype, title_getter, override=override
)
self.add_node(node, override=override, **kwargs) self.add_node(node, override=override, **kwargs)
def add_directive(self, name: str, cls: type[Directive], override: bool = False) -> None: def add_directive(
self, name: str, cls: type[Directive], override: bool = False
) -> None:
"""Register a Docutils directive. """Register a Docutils directive.
:param name: The name of the directive :param name: The name of the directive
@ -1044,8 +1098,12 @@ class Sphinx:
""" """
logger.debug('[app] adding directive: %r', (name, cls)) logger.debug('[app] adding directive: %r', (name, cls))
if not override and docutils.is_directive_registered(name): if not override and docutils.is_directive_registered(name):
logger.warning(__('directive %r is already registered, it will be overridden'), logger.warning(
name, type='app', subtype='add_directive') __('directive %r is already registered, it will be overridden'),
name,
type='app',
subtype='add_directive',
)
docutils.register_directive(name, cls) docutils.register_directive(name, cls)
@ -1066,13 +1124,16 @@ class Sphinx:
""" """
logger.debug('[app] adding role: %r', (name, role)) logger.debug('[app] adding role: %r', (name, role))
if not override and docutils.is_role_registered(name): if not override and docutils.is_role_registered(name):
logger.warning(__('role %r is already registered, it will be overridden'), logger.warning(
name, type='app', subtype='add_role') __('role %r is already registered, it will be overridden'),
name,
type='app',
subtype='add_role',
)
docutils.register_role(name, role) docutils.register_role(name, role)
def add_generic_role( def add_generic_role(
self, name: str, nodeclass: type[Node], override: bool = False self, name: str, nodeclass: type[Node], override: bool = False
) -> None: ) -> None:
"""Register a generic Docutils role. """Register a generic Docutils role.
@ -1091,8 +1152,12 @@ class Sphinx:
# ``register_canonical_role``. # ``register_canonical_role``.
logger.debug('[app] adding generic role: %r', (name, nodeclass)) logger.debug('[app] adding generic role: %r', (name, nodeclass))
if not override and docutils.is_role_registered(name): if not override and docutils.is_role_registered(name):
logger.warning(__('role %r is already registered, it will be overridden'), logger.warning(
name, type='app', subtype='add_generic_role') __('role %r is already registered, it will be overridden'),
name,
type='app',
subtype='add_generic_role',
)
role = roles.GenericRole(name, nodeclass) role = roles.GenericRole(name, nodeclass)
docutils.register_role(name, role) docutils.register_role(name, role)
@ -1110,8 +1175,9 @@ class Sphinx:
""" """
self.registry.add_domain(domain, override=override) self.registry.add_domain(domain, override=override)
def add_directive_to_domain(self, domain: str, name: str, def add_directive_to_domain(
cls: type[Directive], override: bool = False) -> None: self, domain: str, name: str, cls: type[Directive], override: bool = False
) -> None:
"""Register a Docutils directive in a domain. """Register a Docutils directive in a domain.
Like :meth:`add_directive`, but the directive is added to the domain Like :meth:`add_directive`, but the directive is added to the domain
@ -1130,8 +1196,13 @@ class Sphinx:
""" """
self.registry.add_directive_to_domain(domain, name, cls, override=override) self.registry.add_directive_to_domain(domain, name, cls, override=override)
def add_role_to_domain(self, domain: str, name: str, role: RoleFunction | XRefRole, def add_role_to_domain(
override: bool = False) -> None: self,
domain: str,
name: str,
role: RoleFunction | XRefRole,
override: bool = False,
) -> None:
"""Register a Docutils role in a domain. """Register a Docutils role in a domain.
Like :meth:`add_role`, but the role is added to the domain named Like :meth:`add_role`, but the role is added to the domain named
@ -1150,8 +1221,9 @@ class Sphinx:
""" """
self.registry.add_role_to_domain(domain, name, role, override=override) self.registry.add_role_to_domain(domain, name, role, override=override)
def add_index_to_domain(self, domain: str, index: type[Index], _override: bool = False, def add_index_to_domain(
) -> None: self, domain: str, index: type[Index], _override: bool = False
) -> None:
"""Register a custom index for a domain. """Register a custom index for a domain.
Add a custom *index* class to the domain named *domain*. Add a custom *index* class to the domain named *domain*.
@ -1168,12 +1240,17 @@ class Sphinx:
""" """
self.registry.add_index_to_domain(domain, index) self.registry.add_index_to_domain(domain, index)
def add_object_type(self, directivename: str, rolename: str, indextemplate: str = '', def add_object_type(
parse_node: Callable | None = None, self,
ref_nodeclass: type[nodes.TextElement] | None = None, directivename: str,
objname: str = '', doc_field_types: Sequence = (), rolename: str,
override: bool = False, indextemplate: str = '',
) -> None: parse_node: Callable | None = None,
ref_nodeclass: type[nodes.TextElement] | None = None,
objname: str = '',
doc_field_types: Sequence = (),
override: bool = False,
) -> None:
"""Register a new object type. """Register a new object type.
This method is a very convenient way to add a new :term:`object` type This method is a very convenient way to add a new :term:`object` type
@ -1233,13 +1310,24 @@ class Sphinx:
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
""" """
self.registry.add_object_type(directivename, rolename, indextemplate, parse_node, self.registry.add_object_type(
ref_nodeclass, objname, doc_field_types, directivename,
override=override) rolename,
indextemplate,
parse_node,
ref_nodeclass,
objname,
doc_field_types,
override=override,
)
def add_crossref_type( def add_crossref_type(
self, directivename: str, rolename: str, indextemplate: str = '', self,
ref_nodeclass: type[nodes.TextElement] | None = None, objname: str = '', directivename: str,
rolename: str,
indextemplate: str = '',
ref_nodeclass: type[nodes.TextElement] | None = None,
objname: str = '',
override: bool = False, override: bool = False,
) -> None: ) -> None:
"""Register a new crossref object type. """Register a new crossref object type.
@ -1276,9 +1364,14 @@ class Sphinx:
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
""" """
self.registry.add_crossref_type(directivename, rolename, self.registry.add_crossref_type(
indextemplate, ref_nodeclass, objname, directivename,
override=override) rolename,
indextemplate,
ref_nodeclass,
objname,
override=override,
)
def add_transform(self, transform: type[Transform]) -> None: def add_transform(self, transform: type[Transform]) -> None:
"""Register a Docutils transform to be applied after parsing. """Register a Docutils transform to be applied after parsing.
@ -1326,8 +1419,13 @@ class Sphinx:
""" """
self.registry.add_post_transform(transform) self.registry.add_post_transform(transform)
def add_js_file(self, filename: str | None, priority: int = 500, def add_js_file(
loading_method: str | None = None, **kwargs: Any) -> None: self,
filename: str | None,
priority: int = 500,
loading_method: str | None = None,
**kwargs: Any,
) -> None:
"""Register a JavaScript file to include in the HTML output. """Register a JavaScript file to include in the HTML output.
:param filename: The name of a JavaScript file that the default HTML :param filename: The name of a JavaScript file that the default HTML
@ -1393,7 +1491,7 @@ class Sphinx:
self.registry.add_js_file(filename, priority=priority, **kwargs) self.registry.add_js_file(filename, priority=priority, **kwargs)
with contextlib.suppress(AttributeError): with contextlib.suppress(AttributeError):
self.builder.add_js_file( # type: ignore[attr-defined] self.builder.add_js_file( # type: ignore[attr-defined]
filename, priority=priority, **kwargs, filename, priority=priority, **kwargs
) )
def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None: def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None:
@ -1457,11 +1555,12 @@ class Sphinx:
self.registry.add_css_files(filename, priority=priority, **kwargs) self.registry.add_css_files(filename, priority=priority, **kwargs)
with contextlib.suppress(AttributeError): with contextlib.suppress(AttributeError):
self.builder.add_css_file( # type: ignore[attr-defined] self.builder.add_css_file( # type: ignore[attr-defined]
filename, priority=priority, **kwargs, filename, priority=priority, **kwargs
) )
def add_latex_package(self, packagename: str, options: str | None = None, def add_latex_package(
after_hyperref: bool = False) -> None: self, packagename: str, options: str | None = None, after_hyperref: bool = False
) -> None:
r"""Register a package to include in the LaTeX source code. r"""Register a package to include in the LaTeX source code.
Add *packagename* to the list of packages that LaTeX source code will Add *packagename* to the list of packages that LaTeX source code will
@ -1517,11 +1616,13 @@ class Sphinx:
""" """
logger.debug('[app] adding autodocumenter: %r', cls) logger.debug('[app] adding autodocumenter: %r', cls)
from sphinx.ext.autodoc.directive import AutodocDirective from sphinx.ext.autodoc.directive import AutodocDirective
self.registry.add_documenter(cls.objtype, cls) self.registry.add_documenter(cls.objtype, cls)
self.add_directive('auto' + cls.objtype, AutodocDirective, override=override) self.add_directive('auto' + cls.objtype, AutodocDirective, override=override)
def add_autodoc_attrgetter(self, typ: type, getter: Callable[[Any, str, Any], Any], def add_autodoc_attrgetter(
) -> None: self, typ: type, getter: Callable[[Any, str, Any], Any]
) -> None:
"""Register a new ``getattr``-like function for the autodoc extension. """Register a new ``getattr``-like function for the autodoc extension.
Add *getter*, which must be a function with an interface compatible to Add *getter*, which must be a function with an interface compatible to
@ -1548,9 +1649,12 @@ class Sphinx:
""" """
logger.debug('[app] adding search language: %r', cls) logger.debug('[app] adding search language: %r', cls)
from sphinx.search import languages from sphinx.search import languages
languages[cls.lang] = cls languages[cls.lang] = cls
def add_source_suffix(self, suffix: str, filetype: str, override: bool = False) -> None: def add_source_suffix(
self, suffix: str, filetype: str, override: bool = False
) -> None:
"""Register a suffix of source files. """Register a suffix of source files.
Same as :confval:`source_suffix`. The users can override this Same as :confval:`source_suffix`. The users can override this
@ -1620,7 +1724,9 @@ class Sphinx:
""" """
self.registry.add_html_math_renderer(name, inline_renderers, block_renderers) self.registry.add_html_math_renderer(name, inline_renderers, block_renderers)
def add_message_catalog(self, catalog: str, locale_dir: str | os.PathLike[str]) -> None: def add_message_catalog(
self, catalog: str, locale_dir: str | os.PathLike[str]
) -> None:
"""Register a message catalog. """Register a message catalog.
:param catalog: The name of the catalog :param catalog: The name of the catalog
@ -1641,18 +1747,22 @@ class Sphinx:
""" """
if typ == 'read': if typ == 'read':
attrname = 'parallel_read_safe' attrname = 'parallel_read_safe'
message_not_declared = __("the %s extension does not declare if it " message_not_declared = __(
"is safe for parallel reading, assuming " 'the %s extension does not declare if it '
"it isn't - please ask the extension author " 'is safe for parallel reading, assuming '
"to check and make it explicit") "it isn't - please ask the extension author "
message_not_safe = __("the %s extension is not safe for parallel reading") 'to check and make it explicit'
)
message_not_safe = __('the %s extension is not safe for parallel reading')
elif typ == 'write': elif typ == 'write':
attrname = 'parallel_write_safe' attrname = 'parallel_write_safe'
message_not_declared = __("the %s extension does not declare if it " message_not_declared = __(
"is safe for parallel writing, assuming " 'the %s extension does not declare if it '
"it isn't - please ask the extension author " 'is safe for parallel writing, assuming '
"to check and make it explicit") "it isn't - please ask the extension author "
message_not_safe = __("the %s extension is not safe for parallel writing") 'to check and make it explicit'
)
message_not_safe = __('the %s extension is not safe for parallel writing')
else: else:
raise ValueError('parallel type %s is not supported' % typ) raise ValueError('parallel type %s is not supported' % typ)