diff --git a/sphinx/application.py b/sphinx/application.py index d5fbaa9f3..4e1b4b7ba 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -22,7 +22,7 @@ from pygments.lexer import Lexer # NoQA: TCH002 import sphinx from sphinx import locale, package_dir -from sphinx.config import Config +from sphinx.config import Config, _ConfigRebuild from sphinx.environment import BuildEnvironment from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError from sphinx.events import EventManager @@ -507,7 +507,7 @@ class Sphinx: self.registry.add_builder(builder, override=override) # TODO(stephenfin): Describe 'types' parameter - def add_config_value(self, name: str, default: Any, rebuild: bool | str, + def add_config_value(self, name: str, default: Any, rebuild: _ConfigRebuild, types: Any = ()) -> None: """Register a configuration value. diff --git a/sphinx/builders/epub3.py b/sphinx/builders/epub3.py index 40d3ce7ee..0b438cce7 100644 --- a/sphinx/builders/epub3.py +++ b/sphinx/builders/epub3.py @@ -260,7 +260,7 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_builder(Epub3Builder) # config values - app.add_config_value('epub_basename', lambda self: make_filename(self.project), False) + app.add_config_value('epub_basename', lambda self: make_filename(self.project), '') app.add_config_value('epub_version', 3.0, 'epub') # experimental app.add_config_value('epub_theme', 'epub', 'epub') app.add_config_value('epub_theme_options', {}, 'epub') diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index 52fd6b2c6..16e7fe519 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -526,26 +526,26 @@ def setup(app: Sphinx) -> dict[str, Any]: app.connect('config-inited', validate_latex_theme_options, priority=800) app.connect('builder-inited', install_packages_for_ja) - app.add_config_value('latex_engine', default_latex_engine, False, + app.add_config_value('latex_engine', default_latex_engine, '', ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex')) - app.add_config_value('latex_documents', default_latex_documents, False) - app.add_config_value('latex_logo', None, False, [str]) - app.add_config_value('latex_appendices', [], False) - app.add_config_value('latex_use_latex_multicolumn', False, False) - app.add_config_value('latex_use_xindy', default_latex_use_xindy, False, [bool]) - app.add_config_value('latex_toplevel_sectioning', None, False, + app.add_config_value('latex_documents', default_latex_documents, '') + app.add_config_value('latex_logo', None, '', [str]) + app.add_config_value('latex_appendices', [], '') + app.add_config_value('latex_use_latex_multicolumn', False, '') + app.add_config_value('latex_use_xindy', default_latex_use_xindy, '', [bool]) + app.add_config_value('latex_toplevel_sectioning', None, '', ENUM(None, 'part', 'chapter', 'section')) - app.add_config_value('latex_domain_indices', True, False, [list]) - app.add_config_value('latex_show_urls', 'no', False) - app.add_config_value('latex_show_pagerefs', False, False) - app.add_config_value('latex_elements', {}, False) - app.add_config_value('latex_additional_files', [], False) - app.add_config_value('latex_table_style', ['booktabs', 'colorrows'], False, [list]) - app.add_config_value('latex_theme', 'manual', False, [str]) - app.add_config_value('latex_theme_options', {}, False) - app.add_config_value('latex_theme_path', [], False, [list]) + app.add_config_value('latex_domain_indices', True, '', [list]) + app.add_config_value('latex_show_urls', 'no', '') + app.add_config_value('latex_show_pagerefs', False, '') + app.add_config_value('latex_elements', {}, '') + app.add_config_value('latex_additional_files', [], '') + app.add_config_value('latex_table_style', ['booktabs', 'colorrows'], '', [list]) + app.add_config_value('latex_theme', 'manual', '', [str]) + app.add_config_value('latex_theme_options', {}, '') + app.add_config_value('latex_theme_path', [], '', [list]) - app.add_config_value('latex_docclass', default_latex_docclass, False) + app.add_config_value('latex_docclass', default_latex_docclass, '') return { 'version': 'builtin', diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index f2509582b..460598ef2 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -611,20 +611,20 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_builder(CheckExternalLinksBuilder) app.add_post_transform(HyperlinkCollector) - app.add_config_value('linkcheck_ignore', [], False) - app.add_config_value('linkcheck_exclude_documents', [], False) - app.add_config_value('linkcheck_allowed_redirects', {}, False) - app.add_config_value('linkcheck_auth', [], False) - app.add_config_value('linkcheck_request_headers', {}, False) - app.add_config_value('linkcheck_retries', 1, False) - app.add_config_value('linkcheck_timeout', None, False, [int, float]) - app.add_config_value('linkcheck_workers', 5, False) - app.add_config_value('linkcheck_anchors', True, False) + app.add_config_value('linkcheck_ignore', [], '') + app.add_config_value('linkcheck_exclude_documents', [], '') + app.add_config_value('linkcheck_allowed_redirects', {}, '') + app.add_config_value('linkcheck_auth', [], '') + app.add_config_value('linkcheck_request_headers', {}, '') + app.add_config_value('linkcheck_retries', 1, '') + app.add_config_value('linkcheck_timeout', None, '', (int, float)) + app.add_config_value('linkcheck_workers', 5, '') + app.add_config_value('linkcheck_anchors', True, '') # Anchors starting with ! are ignored since they are # commonly used for dynamic pages - app.add_config_value('linkcheck_anchors_ignore', ['^!'], False) - app.add_config_value('linkcheck_anchors_ignore_for_url', (), False, (tuple, list)) - app.add_config_value('linkcheck_rate_limit_timeout', 300.0, False) + app.add_config_value('linkcheck_anchors_ignore', ['^!'], '') + app.add_config_value('linkcheck_anchors_ignore_for_url', (), '', (tuple, list)) + app.add_config_value('linkcheck_rate_limit_timeout', 300.0, '') app.add_event('linkcheck-process-uri') diff --git a/sphinx/builders/manpage.py b/sphinx/builders/manpage.py index 2d35d2047..a5ef29794 100644 --- a/sphinx/builders/manpage.py +++ b/sphinx/builders/manpage.py @@ -116,9 +116,9 @@ def default_man_pages(config: Config) -> list[tuple[str, str, str, list[str], in def setup(app: Sphinx) -> dict[str, Any]: app.add_builder(ManualPageBuilder) - app.add_config_value('man_pages', default_man_pages, False) - app.add_config_value('man_show_urls', False, False) - app.add_config_value('man_make_section_directory', False, False) + app.add_config_value('man_pages', default_man_pages, '') + app.add_config_value('man_show_urls', False, '') + app.add_config_value('man_make_section_directory', False, '') return { 'version': 'builtin', diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 441b598ba..cd3a80777 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -214,13 +214,13 @@ def default_texinfo_documents( def setup(app: Sphinx) -> dict[str, Any]: app.add_builder(TexinfoBuilder) - app.add_config_value('texinfo_documents', default_texinfo_documents, False) - app.add_config_value('texinfo_appendices', [], False) - app.add_config_value('texinfo_elements', {}, False) - app.add_config_value('texinfo_domain_indices', True, False, [list]) - app.add_config_value('texinfo_show_urls', 'footnote', False) - app.add_config_value('texinfo_no_detailmenu', False, False) - app.add_config_value('texinfo_cross_references', True, False) + app.add_config_value('texinfo_documents', default_texinfo_documents, '') + app.add_config_value('texinfo_appendices', [], '') + app.add_config_value('texinfo_elements', {}, '') + app.add_config_value('texinfo_domain_indices', True, '', [list]) + app.add_config_value('texinfo_show_urls', 'footnote', '') + app.add_config_value('texinfo_no_detailmenu', False, '') + app.add_config_value('texinfo_cross_references', True, '') return { 'version': 'builtin', diff --git a/sphinx/config.py b/sphinx/config.py index e831605c4..f6a5ba1b2 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -7,7 +7,7 @@ import time import traceback import types from os import getenv, path -from typing import TYPE_CHECKING, Any, Callable, NamedTuple +from typing import TYPE_CHECKING, Any, Callable, Literal, NamedTuple from sphinx.errors import ConfigError, ExtensionError from sphinx.locale import _, __ @@ -30,6 +30,8 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) +_ConfigRebuild = Literal['', 'env', 'epub', 'gettext', 'html'] + CONFIG_FILENAME = 'conf.py' UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType) @@ -37,7 +39,7 @@ UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType) class ConfigValue(NamedTuple): name: str value: Any - rebuild: bool | str + rebuild: _ConfigRebuild def is_serializable(obj: Any) -> bool: @@ -89,7 +91,7 @@ class Config: # If you add a value here, remember to include it in the docs! - config_values: dict[str, tuple] = { + config_values: dict[str, tuple[Any, _ConfigRebuild, Sequence[type] | ENUM | Any]] = { # general options 'project': ('Python', 'env', []), 'author': ('unknown', 'env', []), @@ -134,12 +136,12 @@ class Config: 'rst_prolog': (None, 'env', [str]), 'trim_doctest_flags': (True, 'env', []), 'primary_domain': ('py', 'env', [NoneType]), - 'needs_sphinx': (None, None, [str]), - 'needs_extensions': ({}, None, []), + 'needs_sphinx': (None, '', [str]), + 'needs_extensions': ({}, '', []), 'manpages_url': (None, 'env', []), - 'nitpicky': (False, None, []), - 'nitpick_ignore': ([], None, [set, list, tuple]), - 'nitpick_ignore_regex': ([], None, [set, list, tuple]), + 'nitpicky': (False, '', []), + 'nitpick_ignore': ([], '', [set, list, tuple]), + 'nitpick_ignore_regex': ([], '', [set, list, tuple]), 'numfig': (False, 'env', []), 'numfig_secnum_depth': (1, 'env', []), 'numfig_format': ({}, 'env', []), # will be initialized in init_numfig_format() @@ -321,7 +323,8 @@ class Config: for name, (_default, rebuild, _valid_types) in self.values.items(): yield ConfigValue(name, getattr(self, name), rebuild) - def add(self, name: str, default: Any, rebuild: bool | str, types: Any) -> None: + def add(self, name: str, default: Any, rebuild: _ConfigRebuild, + types: Sequence[type] | ENUM | Any) -> None: valid_types = types if name in self.values: raise ExtensionError(__('Config value %r already present') % name) diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 3f1ed98ae..14292d10f 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -2821,22 +2821,22 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_autodocumenter(AttributeDocumenter) app.add_autodocumenter(PropertyDocumenter) - app.add_config_value('autoclass_content', 'class', True, ENUM('both', 'class', 'init')) - app.add_config_value('autodoc_member_order', 'alphabetical', True, + app.add_config_value('autoclass_content', 'class', 'env', ENUM('both', 'class', 'init')) + app.add_config_value('autodoc_member_order', 'alphabetical', 'env', ENUM('alphabetical', 'bysource', 'groupwise')) - app.add_config_value('autodoc_class_signature', 'mixed', True, ENUM('mixed', 'separated')) - app.add_config_value('autodoc_default_options', {}, True) - app.add_config_value('autodoc_docstring_signature', True, True) - app.add_config_value('autodoc_mock_imports', [], True) - app.add_config_value('autodoc_typehints', "signature", True, + app.add_config_value('autodoc_class_signature', 'mixed', 'env', ENUM('mixed', 'separated')) + app.add_config_value('autodoc_default_options', {}, 'env') + app.add_config_value('autodoc_docstring_signature', True, 'env') + app.add_config_value('autodoc_mock_imports', [], 'env') + app.add_config_value('autodoc_typehints', "signature", 'env', ENUM("signature", "description", "none", "both")) - app.add_config_value('autodoc_typehints_description_target', 'all', True, + app.add_config_value('autodoc_typehints_description_target', 'all', 'env', ENUM('all', 'documented', 'documented_params')) - app.add_config_value('autodoc_type_aliases', {}, True) + app.add_config_value('autodoc_type_aliases', {}, 'env') app.add_config_value('autodoc_typehints_format', "short", 'env', ENUM("fully-qualified", "short")) - app.add_config_value('autodoc_warningiserror', True, True) - app.add_config_value('autodoc_inherit_docstrings', True, True) + app.add_config_value('autodoc_warningiserror', True, 'env') + app.add_config_value('autodoc_inherit_docstrings', True, 'env') app.add_event('autodoc-before-process-signature') app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') diff --git a/sphinx/ext/autodoc/preserve_defaults.py b/sphinx/ext/autodoc/preserve_defaults.py index 5f957ce21..5305c6ac9 100644 --- a/sphinx/ext/autodoc/preserve_defaults.py +++ b/sphinx/ext/autodoc/preserve_defaults.py @@ -190,7 +190,7 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None: def setup(app: Sphinx) -> dict[str, Any]: - app.add_config_value('autodoc_preserve_defaults', False, True) + app.add_config_value('autodoc_preserve_defaults', False, 'env') app.connect('autodoc-before-process-signature', update_defvalue) return { diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index edb8f0d5f..a13b38790 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -162,7 +162,7 @@ class FakeDirective(DocumenterBridge): settings = Struct(tab_width=8) document = Struct(settings=settings) app = FakeApplication() - app.config.add('autodoc_class_signature', 'mixed', True, None) + app.config.add('autodoc_class_signature', 'mixed', 'env', None) env = BuildEnvironment(app) # type: ignore[arg-type] state = Struct(document=document) super().__init__(env, None, Options(), 0, state) @@ -835,13 +835,13 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_directive('autosummary', Autosummary) app.add_role('autolink', AutoLink()) app.connect('builder-inited', process_generate_options) - app.add_config_value('autosummary_context', {}, True) + app.add_config_value('autosummary_context', {}, 'env') app.add_config_value('autosummary_filename_map', {}, 'html') - app.add_config_value('autosummary_generate', True, True, [bool, list]) - app.add_config_value('autosummary_generate_overwrite', True, False) + app.add_config_value('autosummary_generate', True, 'env', [bool, list]) + app.add_config_value('autosummary_generate_overwrite', True, '') app.add_config_value('autosummary_mock_imports', lambda config: config.autodoc_mock_imports, 'env') - app.add_config_value('autosummary_imported_members', [], False, [bool]) + app.add_config_value('autosummary_imported_members', [], '', [bool]) app.add_config_value('autosummary_ignore_module_all', True, 'env', bool) return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index 06814f9ba..c78c15be6 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -71,8 +71,8 @@ class DummyApplication: self._warncount = 0 self.warningiserror = False - self.config.add('autosummary_context', {}, True, None) - self.config.add('autosummary_filename_map', {}, True, None) + self.config.add('autosummary_context', {}, 'env', None) + self.config.add('autosummary_filename_map', {}, 'env', None) self.config.add('autosummary_ignore_module_all', True, 'env', bool) self.config.init_values() diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py index 02096afbc..3cf57ef62 100644 --- a/sphinx/ext/coverage.py +++ b/sphinx/ext/coverage.py @@ -389,16 +389,16 @@ class CoverageBuilder(Builder): def setup(app: Sphinx) -> dict[str, Any]: app.add_builder(CoverageBuilder) - app.add_config_value('coverage_ignore_modules', [], False) - app.add_config_value('coverage_ignore_functions', [], False) - app.add_config_value('coverage_ignore_classes', [], False) - app.add_config_value('coverage_ignore_pyobjects', [], False) - app.add_config_value('coverage_c_path', [], False) - app.add_config_value('coverage_c_regexes', {}, False) - app.add_config_value('coverage_ignore_c_items', {}, False) - app.add_config_value('coverage_write_headline', True, False) - app.add_config_value('coverage_statistics_to_report', True, False, (bool,)) - app.add_config_value('coverage_statistics_to_stdout', True, False, (bool,)) - app.add_config_value('coverage_skip_undoc_in_source', False, False) - app.add_config_value('coverage_show_missing_items', False, False) + app.add_config_value('coverage_ignore_modules', [], '') + app.add_config_value('coverage_ignore_functions', [], '') + app.add_config_value('coverage_ignore_classes', [], '') + app.add_config_value('coverage_ignore_pyobjects', [], '') + app.add_config_value('coverage_c_path', [], '') + app.add_config_value('coverage_c_regexes', {}, '') + app.add_config_value('coverage_ignore_c_items', {}, '') + app.add_config_value('coverage_write_headline', True, '') + app.add_config_value('coverage_statistics_to_report', True, '', (bool,)) + app.add_config_value('coverage_statistics_to_stdout', True, '', (bool,)) + app.add_config_value('coverage_skip_undoc_in_source', False, '') + app.add_config_value('coverage_show_missing_items', False, '') return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index c55ef2fa7..ef93df42d 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -563,13 +563,13 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_directive('testoutput', TestoutputDirective) app.add_builder(DocTestBuilder) # this config value adds to sys.path - app.add_config_value('doctest_show_successes', True, False, (bool,)) - app.add_config_value('doctest_path', [], False) - app.add_config_value('doctest_test_doctest_blocks', 'default', False) - app.add_config_value('doctest_global_setup', '', False) - app.add_config_value('doctest_global_cleanup', '', False) + app.add_config_value('doctest_show_successes', True, '', (bool,)) + app.add_config_value('doctest_path', [], '') + app.add_config_value('doctest_test_doctest_blocks', 'default', '') + app.add_config_value('doctest_global_setup', '', '') + app.add_config_value('doctest_global_cleanup', '', '') app.add_config_value( 'doctest_default_flags', doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL, - False) + '') return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 3a015a2b1..f737d05cf 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -487,8 +487,8 @@ def setup(app: Sphinx) -> dict[str, Any]: man=(skip, None), texinfo=(texinfo_visit_inheritance_diagram, None)) app.add_directive('inheritance-diagram', InheritanceDiagram) - app.add_config_value('inheritance_graph_attrs', {}, False) - app.add_config_value('inheritance_node_attrs', {}, False) - app.add_config_value('inheritance_edge_attrs', {}, False) - app.add_config_value('inheritance_alias', {}, False) + app.add_config_value('inheritance_graph_attrs', {}, '') + app.add_config_value('inheritance_node_attrs', {}, '') + app.add_config_value('inheritance_edge_attrs', {}, '') + app.add_config_value('inheritance_alias', {}, '') return {'version': sphinx.__display_version__, 'parallel_read_safe': True} diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 453bb6e98..d2b14bf04 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -682,10 +682,10 @@ def normalize_intersphinx_mapping(app: Sphinx, config: Config) -> None: def setup(app: Sphinx) -> dict[str, Any]: - app.add_config_value('intersphinx_mapping', {}, True) - app.add_config_value('intersphinx_cache_limit', 5, False) - app.add_config_value('intersphinx_timeout', None, False) - app.add_config_value('intersphinx_disabled_reftypes', ['std:doc'], True) + app.add_config_value('intersphinx_mapping', {}, 'env') + app.add_config_value('intersphinx_cache_limit', 5, '') + app.add_config_value('intersphinx_timeout', None, '') + app.add_config_value('intersphinx_disabled_reftypes', ['std:doc'], 'env') app.connect('config-inited', normalize_intersphinx_mapping, priority=800) app.connect('builder-inited', load_mappings) app.connect('source-read', install_dispatcher) diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py index 61aa3d83f..fd98ffbcd 100644 --- a/sphinx/ext/napoleon/__init__.py +++ b/sphinx/ext/napoleon/__init__.py @@ -2,13 +2,16 @@ from __future__ import annotations -from typing import Any +from typing import TYPE_CHECKING, Any import sphinx from sphinx.application import Sphinx from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring from sphinx.util import inspect +if TYPE_CHECKING: + from sphinx.config import _ConfigRebuild + class Config: """Sphinx napoleon extension settings in `conf.py`. @@ -262,7 +265,7 @@ class Config: but do not have a type in the docstring. """ - _config_values = { + _config_values: dict[str, tuple[Any, _ConfigRebuild]] = { 'napoleon_google_docstring': (True, 'env'), 'napoleon_numpy_docstring': (True, 'env'), 'napoleon_include_init_with_doc': (False, 'env'), diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index c5fcda537..e8794aec0 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -341,9 +341,9 @@ def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], Non def setup(app: Sphinx) -> dict[str, Any]: - app.add_config_value('viewcode_import', None, False) - app.add_config_value('viewcode_enable_epub', False, False) - app.add_config_value('viewcode_follow_imported_members', True, False) + app.add_config_value('viewcode_import', None, '') + app.add_config_value('viewcode_enable_epub', False, '') + app.add_config_value('viewcode_follow_imported_members', True, '') app.add_config_value('viewcode_line_numbers', False, 'env', (bool,)) app.connect('doctree-read', doctree_read) app.connect('env-merge-info', env_merge_info)