Sphinx 7.2.6__py3-none-any.whl → 7.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -9
- sphinx/addnodes.py +31 -28
- sphinx/application.py +9 -15
- sphinx/builders/__init__.py +5 -6
- sphinx/builders/_epub_base.py +17 -9
- sphinx/builders/changes.py +10 -5
- sphinx/builders/dirhtml.py +4 -2
- sphinx/builders/dummy.py +3 -2
- sphinx/builders/epub3.py +5 -3
- sphinx/builders/gettext.py +24 -7
- sphinx/builders/html/__init__.py +88 -96
- sphinx/builders/html/_assets.py +16 -16
- sphinx/builders/html/transforms.py +4 -2
- sphinx/builders/latex/__init__.py +40 -33
- sphinx/builders/latex/nodes.py +6 -2
- sphinx/builders/latex/transforms.py +17 -8
- sphinx/builders/latex/util.py +1 -1
- sphinx/builders/linkcheck.py +86 -27
- sphinx/builders/manpage.py +8 -6
- sphinx/builders/singlehtml.py +5 -4
- sphinx/builders/texinfo.py +18 -14
- sphinx/builders/text.py +3 -2
- sphinx/builders/xml.py +5 -2
- sphinx/cmd/build.py +119 -76
- sphinx/cmd/make_mode.py +4 -9
- sphinx/cmd/quickstart.py +13 -16
- sphinx/config.py +432 -250
- sphinx/deprecation.py +23 -13
- sphinx/directives/__init__.py +8 -8
- sphinx/directives/code.py +7 -7
- sphinx/directives/other.py +23 -13
- sphinx/directives/patches.py +7 -6
- sphinx/domains/__init__.py +2 -2
- sphinx/domains/c/__init__.py +796 -0
- sphinx/domains/c/_ast.py +1421 -0
- sphinx/domains/c/_ids.py +65 -0
- sphinx/domains/c/_parser.py +1048 -0
- sphinx/domains/c/_symbol.py +700 -0
- sphinx/domains/changeset.py +11 -7
- sphinx/domains/citation.py +5 -2
- sphinx/domains/cpp/__init__.py +1089 -0
- sphinx/domains/cpp/_ast.py +3635 -0
- sphinx/domains/cpp/_ids.py +537 -0
- sphinx/domains/cpp/_parser.py +2117 -0
- sphinx/domains/cpp/_symbol.py +1092 -0
- sphinx/domains/index.py +6 -4
- sphinx/domains/javascript.py +16 -13
- sphinx/domains/math.py +9 -4
- sphinx/domains/python/__init__.py +890 -0
- sphinx/domains/python/_annotations.py +507 -0
- sphinx/domains/python/_object.py +426 -0
- sphinx/domains/rst.py +12 -7
- sphinx/domains/{std.py → std/__init__.py} +19 -16
- sphinx/environment/__init__.py +21 -19
- sphinx/environment/adapters/indexentries.py +2 -2
- sphinx/environment/adapters/toctree.py +10 -9
- sphinx/environment/collectors/__init__.py +6 -3
- sphinx/environment/collectors/asset.py +4 -3
- sphinx/environment/collectors/dependencies.py +3 -2
- sphinx/environment/collectors/metadata.py +6 -5
- sphinx/environment/collectors/title.py +3 -2
- sphinx/environment/collectors/toctree.py +5 -4
- sphinx/errors.py +13 -2
- sphinx/events.py +14 -9
- sphinx/ext/apidoc.py +9 -11
- sphinx/ext/autodoc/__init__.py +105 -71
- sphinx/ext/autodoc/directive.py +7 -6
- sphinx/ext/autodoc/importer.py +102 -36
- sphinx/ext/autodoc/mock.py +7 -5
- sphinx/ext/autodoc/preserve_defaults.py +4 -3
- sphinx/ext/autodoc/type_comment.py +2 -1
- sphinx/ext/autodoc/typehints.py +5 -4
- sphinx/ext/autosectionlabel.py +3 -2
- sphinx/ext/autosummary/__init__.py +21 -17
- sphinx/ext/autosummary/generate.py +9 -9
- sphinx/ext/coverage.py +26 -20
- sphinx/ext/doctest.py +38 -33
- sphinx/ext/duration.py +1 -0
- sphinx/ext/extlinks.py +4 -3
- sphinx/ext/githubpages.py +3 -2
- sphinx/ext/graphviz.py +10 -7
- sphinx/ext/ifconfig.py +5 -5
- sphinx/ext/imgconverter.py +6 -5
- sphinx/ext/imgmath.py +9 -8
- sphinx/ext/inheritance_diagram.py +31 -31
- sphinx/ext/intersphinx.py +140 -23
- sphinx/ext/linkcode.py +3 -2
- sphinx/ext/mathjax.py +2 -1
- sphinx/ext/napoleon/__init__.py +12 -7
- sphinx/ext/napoleon/docstring.py +34 -32
- sphinx/ext/todo.py +10 -7
- sphinx/ext/viewcode.py +12 -11
- sphinx/extension.py +18 -8
- sphinx/highlighting.py +39 -20
- sphinx/io.py +17 -8
- sphinx/jinja2glue.py +16 -15
- sphinx/locale/__init__.py +30 -23
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
- sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
- sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
- sphinx/locale/sphinx.pot +813 -755
- sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
- sphinx/parsers.py +7 -5
- sphinx/project.py +18 -11
- sphinx/pycode/__init__.py +6 -5
- sphinx/pycode/ast.py +23 -8
- sphinx/pycode/parser.py +6 -5
- sphinx/registry.py +12 -6
- sphinx/roles.py +103 -57
- sphinx/search/__init__.py +17 -18
- sphinx/search/da.py +2 -2
- sphinx/search/de.py +2 -2
- sphinx/search/en.py +1 -1
- sphinx/search/es.py +2 -2
- sphinx/search/fi.py +2 -2
- sphinx/search/fr.py +2 -2
- sphinx/search/hu.py +2 -2
- sphinx/search/it.py +2 -2
- sphinx/search/ja.py +13 -22
- sphinx/search/nl.py +2 -2
- sphinx/search/no.py +2 -2
- sphinx/search/pt.py +2 -2
- sphinx/search/ro.py +1 -1
- sphinx/search/ru.py +2 -2
- sphinx/search/sv.py +2 -2
- sphinx/search/tr.py +1 -1
- sphinx/search/zh.py +2 -3
- sphinx/templates/graphviz/graphviz.css +1 -1
- sphinx/testing/fixtures.py +41 -24
- sphinx/testing/path.py +1 -1
- sphinx/testing/util.py +142 -53
- sphinx/texinputs/sphinx.xdy +1 -1
- sphinx/texinputs/sphinxlatextables.sty +1 -1
- sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
- sphinx/themes/agogo/layout.html +4 -4
- sphinx/themes/agogo/static/agogo.css_t +1 -1
- sphinx/themes/agogo/theme.toml +22 -0
- sphinx/themes/basic/defindex.html +1 -1
- sphinx/themes/basic/domainindex.html +1 -1
- sphinx/themes/basic/genindex-single.html +1 -1
- sphinx/themes/basic/genindex-split.html +1 -1
- sphinx/themes/basic/genindex.html +1 -1
- sphinx/themes/basic/globaltoc.html +1 -1
- sphinx/themes/basic/layout.html +1 -1
- sphinx/themes/basic/localtoc.html +1 -1
- sphinx/themes/basic/page.html +1 -1
- sphinx/themes/basic/relations.html +1 -1
- sphinx/themes/basic/search.html +5 -20
- sphinx/themes/basic/searchbox.html +3 -3
- sphinx/themes/basic/searchfield.html +3 -3
- sphinx/themes/basic/sourcelink.html +1 -1
- sphinx/themes/basic/static/basic.css_t +1 -1
- sphinx/themes/basic/static/doctools.js +1 -1
- sphinx/themes/basic/static/language_data.js_t +2 -2
- sphinx/themes/basic/static/searchtools.js +105 -60
- sphinx/themes/basic/theme.toml +23 -0
- sphinx/themes/bizstyle/layout.html +1 -6
- sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
- sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
- sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
- sphinx/themes/bizstyle/theme.toml +12 -0
- sphinx/themes/classic/layout.html +1 -1
- sphinx/themes/classic/static/classic.css_t +1 -1
- sphinx/themes/classic/static/sidebar.js_t +1 -1
- sphinx/themes/classic/theme.toml +34 -0
- sphinx/themes/default/theme.toml +2 -0
- sphinx/themes/epub/epub-cover.html +1 -1
- sphinx/themes/epub/layout.html +1 -1
- sphinx/themes/epub/static/epub.css_t +1 -1
- sphinx/themes/epub/theme.toml +10 -0
- sphinx/themes/haiku/layout.html +3 -3
- sphinx/themes/haiku/static/haiku.css_t +2 -2
- sphinx/themes/haiku/theme.toml +16 -0
- sphinx/themes/nature/static/nature.css_t +1 -1
- sphinx/themes/nature/theme.toml +6 -0
- sphinx/themes/nonav/layout.html +1 -1
- sphinx/themes/nonav/static/nonav.css_t +1 -1
- sphinx/themes/nonav/theme.toml +10 -0
- sphinx/themes/pyramid/static/epub.css_t +1 -1
- sphinx/themes/pyramid/static/pyramid.css_t +1 -1
- sphinx/themes/pyramid/theme.toml +6 -0
- sphinx/themes/scrolls/artwork/logo.svg +1 -1
- sphinx/themes/scrolls/layout.html +2 -2
- sphinx/themes/scrolls/static/scrolls.css_t +1 -1
- sphinx/themes/scrolls/theme.toml +15 -0
- sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
- sphinx/themes/sphinxdoc/theme.toml +6 -0
- sphinx/themes/traditional/static/traditional.css_t +1 -1
- sphinx/themes/traditional/theme.toml +9 -0
- sphinx/theming.py +427 -131
- sphinx/transforms/__init__.py +21 -24
- sphinx/transforms/compact_bullet_list.py +5 -5
- sphinx/transforms/i18n.py +30 -28
- sphinx/transforms/post_transforms/__init__.py +9 -7
- sphinx/transforms/post_transforms/code.py +4 -1
- sphinx/transforms/post_transforms/images.py +17 -13
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +15 -11
- sphinx/util/_io.py +34 -0
- sphinx/util/_pathlib.py +23 -18
- sphinx/util/build_phase.py +1 -0
- sphinx/util/cfamily.py +19 -11
- sphinx/util/console.py +101 -21
- sphinx/util/display.py +3 -2
- sphinx/util/docfields.py +12 -8
- sphinx/util/docutils.py +21 -35
- sphinx/util/exceptions.py +3 -2
- sphinx/util/fileutil.py +5 -5
- sphinx/util/http_date.py +9 -2
- sphinx/util/i18n.py +40 -9
- sphinx/util/inspect.py +317 -245
- sphinx/util/inventory.py +22 -5
- sphinx/util/logging.py +81 -7
- sphinx/util/matching.py +2 -1
- sphinx/util/math.py +1 -2
- sphinx/util/nodes.py +39 -29
- sphinx/util/osutil.py +25 -6
- sphinx/util/parallel.py +6 -1
- sphinx/util/requests.py +8 -5
- sphinx/util/rst.py +8 -6
- sphinx/util/tags.py +3 -3
- sphinx/util/template.py +8 -3
- sphinx/util/typing.py +76 -42
- sphinx/versioning.py +6 -2
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +17 -13
- sphinx/writers/latex.py +12 -12
- sphinx/writers/manpage.py +13 -7
- sphinx/writers/texinfo.py +13 -10
- sphinx/writers/text.py +13 -23
- sphinx/writers/xml.py +1 -1
- sphinx-7.2.6.dist-info/LICENSE → sphinx-7.3.1.dist-info/LICENSE.rst +1 -1
- {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/METADATA +14 -12
- sphinx-7.3.1.dist-info/RECORD +581 -0
- sphinx/domains/c.py +0 -3906
- sphinx/domains/cpp.py +0 -8233
- sphinx/domains/python.py +0 -1769
- sphinx/themes/agogo/theme.conf +0 -20
- sphinx/themes/basic/theme.conf +0 -16
- sphinx/themes/bizstyle/theme.conf +0 -10
- sphinx/themes/classic/theme.conf +0 -32
- sphinx/themes/default/theme.conf +0 -2
- sphinx/themes/epub/theme.conf +0 -8
- sphinx/themes/haiku/theme.conf +0 -14
- sphinx/themes/nature/theme.conf +0 -4
- sphinx/themes/nonav/theme.conf +0 -8
- sphinx/themes/pyramid/theme.conf +0 -4
- sphinx/themes/scrolls/theme.conf +0 -13
- sphinx/themes/sphinxdoc/theme.conf +0 -4
- sphinx/themes/traditional/theme.conf +0 -7
- sphinx-7.2.6.dist-info/RECORD +0 -569
- {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/WHEEL +0 -0
- {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/entry_points.txt +0 -0
sphinx/config.py
CHANGED
|
@@ -2,33 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
import time
|
|
6
7
|
import traceback
|
|
7
8
|
import types
|
|
9
|
+
import warnings
|
|
8
10
|
from os import getenv, path
|
|
9
|
-
from typing import TYPE_CHECKING, Any,
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Literal, NamedTuple, Union
|
|
10
12
|
|
|
13
|
+
from sphinx.deprecation import RemovedInSphinx90Warning
|
|
11
14
|
from sphinx.errors import ConfigError, ExtensionError
|
|
12
15
|
from sphinx.locale import _, __
|
|
13
16
|
from sphinx.util import logging
|
|
14
17
|
from sphinx.util.osutil import fs_encoding
|
|
15
|
-
from sphinx.util.typing import NoneType
|
|
18
|
+
from sphinx.util.typing import ExtensionMetadata, NoneType
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
from contextlib import chdir
|
|
19
|
-
|
|
20
|
+
if sys.version_info >= (3, 11):
|
|
21
|
+
from contextlib import chdir
|
|
22
|
+
else:
|
|
20
23
|
from sphinx.util.osutil import _chdir as chdir
|
|
21
24
|
|
|
22
25
|
if TYPE_CHECKING:
|
|
23
26
|
import os
|
|
24
|
-
from collections.abc import
|
|
27
|
+
from collections.abc import Collection, Iterator, Sequence, Set
|
|
25
28
|
|
|
26
29
|
from sphinx.application import Sphinx
|
|
27
30
|
from sphinx.environment import BuildEnvironment
|
|
28
31
|
from sphinx.util.tags import Tags
|
|
32
|
+
from sphinx.util.typing import _ExtensionSetupFunc
|
|
29
33
|
|
|
30
34
|
logger = logging.getLogger(__name__)
|
|
31
35
|
|
|
36
|
+
_ConfigRebuild = Literal[
|
|
37
|
+
'', 'env', 'epub', 'gettext', 'html',
|
|
38
|
+
# sphinxcontrib-applehelp
|
|
39
|
+
'applehelp',
|
|
40
|
+
# sphinxcontrib-devhelp
|
|
41
|
+
'devhelp',
|
|
42
|
+
]
|
|
43
|
+
|
|
32
44
|
CONFIG_FILENAME = 'conf.py'
|
|
33
45
|
UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType)
|
|
34
46
|
|
|
@@ -36,20 +48,33 @@ UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType)
|
|
|
36
48
|
class ConfigValue(NamedTuple):
|
|
37
49
|
name: str
|
|
38
50
|
value: Any
|
|
39
|
-
rebuild:
|
|
51
|
+
rebuild: _ConfigRebuild
|
|
40
52
|
|
|
41
53
|
|
|
42
|
-
def is_serializable(obj:
|
|
54
|
+
def is_serializable(obj: object, *, _recursive_guard: frozenset[int] = frozenset()) -> bool:
|
|
43
55
|
"""Check if object is serializable or not."""
|
|
44
56
|
if isinstance(obj, UNSERIALIZABLE_TYPES):
|
|
45
57
|
return False
|
|
46
|
-
|
|
58
|
+
|
|
59
|
+
# use id() to handle un-hashable objects
|
|
60
|
+
if id(obj) in _recursive_guard:
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
if isinstance(obj, dict):
|
|
64
|
+
guard = _recursive_guard | {id(obj)}
|
|
47
65
|
for key, value in obj.items():
|
|
48
|
-
if
|
|
66
|
+
if (
|
|
67
|
+
not is_serializable(key, _recursive_guard=guard)
|
|
68
|
+
or not is_serializable(value, _recursive_guard=guard)
|
|
69
|
+
):
|
|
49
70
|
return False
|
|
50
|
-
elif isinstance(obj, (list, tuple, set)):
|
|
51
|
-
|
|
71
|
+
elif isinstance(obj, (list, tuple, set, frozenset)):
|
|
72
|
+
guard = _recursive_guard | {id(obj)}
|
|
73
|
+
return all(is_serializable(item, _recursive_guard=guard) for item in obj)
|
|
52
74
|
|
|
75
|
+
# if an issue occurs for a non-serializable type, pickle will complain
|
|
76
|
+
# since the object is likely coming from a third-party extension (we
|
|
77
|
+
# natively expect 'simple' types and not weird ones)
|
|
53
78
|
return True
|
|
54
79
|
|
|
55
80
|
|
|
@@ -59,6 +84,7 @@ class ENUM:
|
|
|
59
84
|
Example:
|
|
60
85
|
app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline'))
|
|
61
86
|
"""
|
|
87
|
+
|
|
62
88
|
def __init__(self, *candidates: str | bool | None) -> None:
|
|
63
89
|
self.candidates = candidates
|
|
64
90
|
|
|
@@ -69,10 +95,92 @@ class ENUM:
|
|
|
69
95
|
return value in self.candidates
|
|
70
96
|
|
|
71
97
|
|
|
98
|
+
_OptValidTypes = Union[tuple[()], tuple[type, ...], frozenset[type], ENUM]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class _Opt:
|
|
102
|
+
__slots__ = 'default', 'rebuild', 'valid_types'
|
|
103
|
+
|
|
104
|
+
default: Any
|
|
105
|
+
rebuild: _ConfigRebuild
|
|
106
|
+
valid_types: _OptValidTypes
|
|
107
|
+
|
|
108
|
+
def __init__(
|
|
109
|
+
self,
|
|
110
|
+
default: Any,
|
|
111
|
+
rebuild: _ConfigRebuild,
|
|
112
|
+
valid_types: _OptValidTypes,
|
|
113
|
+
) -> None:
|
|
114
|
+
"""Configuration option type for Sphinx.
|
|
115
|
+
|
|
116
|
+
The type is intended to be immutable; changing the field values
|
|
117
|
+
is an unsupported action.
|
|
118
|
+
No validation is performed on the values, though consumers will
|
|
119
|
+
likely expect them to be of the types advertised.
|
|
120
|
+
The old tuple-based interface will be removed in Sphinx 9.
|
|
121
|
+
"""
|
|
122
|
+
super().__setattr__('default', default)
|
|
123
|
+
super().__setattr__('rebuild', rebuild)
|
|
124
|
+
super().__setattr__('valid_types', valid_types)
|
|
125
|
+
|
|
126
|
+
def __repr__(self) -> str:
|
|
127
|
+
return (
|
|
128
|
+
f'{self.__class__.__qualname__}('
|
|
129
|
+
f'default={self.default!r}, '
|
|
130
|
+
f'rebuild={self.rebuild!r}, '
|
|
131
|
+
f'valid_types={self.valid_types!r})'
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def __eq__(self, other: object) -> bool:
|
|
135
|
+
if isinstance(other, _Opt):
|
|
136
|
+
self_tpl = (self.default, self.rebuild, self.valid_types)
|
|
137
|
+
other_tpl = (other.default, other.rebuild, other.valid_types)
|
|
138
|
+
return self_tpl == other_tpl
|
|
139
|
+
return NotImplemented
|
|
140
|
+
|
|
141
|
+
def __lt__(self, other: _Opt) -> bool:
|
|
142
|
+
if self.__class__ is other.__class__:
|
|
143
|
+
self_tpl = (self.default, self.rebuild, self.valid_types)
|
|
144
|
+
other_tpl = (other.default, other.rebuild, other.valid_types)
|
|
145
|
+
return self_tpl > other_tpl
|
|
146
|
+
return NotImplemented
|
|
147
|
+
|
|
148
|
+
def __hash__(self) -> int:
|
|
149
|
+
return hash((self.default, self.rebuild, self.valid_types))
|
|
150
|
+
|
|
151
|
+
def __setattr__(self, key: str, value: Any) -> None:
|
|
152
|
+
if key in {'default', 'rebuild', 'valid_types'}:
|
|
153
|
+
msg = f'{self.__class__.__name__!r} object does not support assignment to {key!r}'
|
|
154
|
+
raise TypeError(msg)
|
|
155
|
+
super().__setattr__(key, value)
|
|
156
|
+
|
|
157
|
+
def __delattr__(self, key: str) -> None:
|
|
158
|
+
if key in {'default', 'rebuild', 'valid_types'}:
|
|
159
|
+
msg = f'{self.__class__.__name__!r} object does not support deletion of {key!r}'
|
|
160
|
+
raise TypeError(msg)
|
|
161
|
+
super().__delattr__(key)
|
|
162
|
+
|
|
163
|
+
def __getstate__(self) -> tuple[Any, _ConfigRebuild, _OptValidTypes]:
|
|
164
|
+
return self.default, self.rebuild, self.valid_types
|
|
165
|
+
|
|
166
|
+
def __setstate__(self, state: tuple[Any, _ConfigRebuild, _OptValidTypes]) -> None:
|
|
167
|
+
default, rebuild, valid_types = state
|
|
168
|
+
super().__setattr__('default', default)
|
|
169
|
+
super().__setattr__('rebuild', rebuild)
|
|
170
|
+
super().__setattr__('valid_types', valid_types)
|
|
171
|
+
|
|
172
|
+
def __getitem__(self, item: int | slice) -> Any:
|
|
173
|
+
warnings.warn(
|
|
174
|
+
f'The {self.__class__.__name__!r} object tuple interface is deprecated, '
|
|
175
|
+
"use attribute access instead for 'default', 'rebuild', and 'valid_types'.",
|
|
176
|
+
RemovedInSphinx90Warning, stacklevel=2)
|
|
177
|
+
return (self.default, self.rebuild, self.valid_types)[item]
|
|
178
|
+
|
|
179
|
+
|
|
72
180
|
class Config:
|
|
73
181
|
r"""Configuration file abstraction.
|
|
74
182
|
|
|
75
|
-
The
|
|
183
|
+
The Config object makes the values of all config options available as
|
|
76
184
|
attributes.
|
|
77
185
|
|
|
78
186
|
It is exposed via the :py:class:`~sphinx.application.Sphinx`\ ``.config``
|
|
@@ -81,97 +189,119 @@ class Config:
|
|
|
81
189
|
``app.config.language`` or ``env.config.language``.
|
|
82
190
|
"""
|
|
83
191
|
|
|
84
|
-
#
|
|
192
|
+
# The values are:
|
|
193
|
+
# 1. Default
|
|
194
|
+
# 2. What needs to be rebuilt if changed
|
|
195
|
+
# 3. Valid types
|
|
85
196
|
|
|
86
|
-
# If you add a value here,
|
|
87
|
-
# quickstart.py file template as well as in the docs!
|
|
197
|
+
# If you add a value here, remember to include it in the docs!
|
|
88
198
|
|
|
89
|
-
config_values: dict[str,
|
|
199
|
+
config_values: dict[str, _Opt] = {
|
|
90
200
|
# general options
|
|
91
|
-
'project': ('Python', 'env',
|
|
92
|
-
'author': ('unknown', 'env',
|
|
93
|
-
'project_copyright': ('', 'html',
|
|
94
|
-
'copyright': (
|
|
95
|
-
|
|
96
|
-
'
|
|
97
|
-
'
|
|
201
|
+
'project': _Opt('Python', 'env', ()),
|
|
202
|
+
'author': _Opt('unknown', 'env', ()),
|
|
203
|
+
'project_copyright': _Opt('', 'html', frozenset((str, tuple, list))),
|
|
204
|
+
'copyright': _Opt(
|
|
205
|
+
lambda c: c.project_copyright, 'html', frozenset((str, tuple, list))),
|
|
206
|
+
'version': _Opt('', 'env', ()),
|
|
207
|
+
'release': _Opt('', 'env', ()),
|
|
208
|
+
'today': _Opt('', 'env', ()),
|
|
98
209
|
# the real default is locale-dependent
|
|
99
|
-
'today_fmt': (None, 'env',
|
|
100
|
-
|
|
101
|
-
'language': ('en', 'env',
|
|
102
|
-
'locale_dirs': (['locales'], 'env',
|
|
103
|
-
'figure_language_filename': ('{root}.{language}{ext}', 'env',
|
|
104
|
-
'gettext_allow_fuzzy_translations': (False, 'gettext',
|
|
105
|
-
'translation_progress_classes': (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
'master_doc': ('index', 'env',
|
|
109
|
-
'root_doc': (lambda config: config.master_doc, 'env',
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
'
|
|
113
|
-
|
|
114
|
-
'
|
|
115
|
-
'
|
|
116
|
-
'
|
|
117
|
-
'
|
|
118
|
-
'
|
|
119
|
-
|
|
120
|
-
'
|
|
121
|
-
'
|
|
122
|
-
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
'
|
|
127
|
-
'
|
|
128
|
-
'
|
|
129
|
-
'
|
|
130
|
-
'
|
|
131
|
-
'
|
|
132
|
-
'
|
|
133
|
-
'
|
|
134
|
-
'
|
|
135
|
-
'
|
|
136
|
-
'
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'
|
|
144
|
-
'
|
|
145
|
-
'
|
|
146
|
-
'
|
|
147
|
-
'
|
|
148
|
-
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
'
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
'
|
|
210
|
+
'today_fmt': _Opt(None, 'env', frozenset((str,))),
|
|
211
|
+
|
|
212
|
+
'language': _Opt('en', 'env', frozenset((str,))),
|
|
213
|
+
'locale_dirs': _Opt(['locales'], 'env', ()),
|
|
214
|
+
'figure_language_filename': _Opt('{root}.{language}{ext}', 'env', frozenset((str,))),
|
|
215
|
+
'gettext_allow_fuzzy_translations': _Opt(False, 'gettext', ()),
|
|
216
|
+
'translation_progress_classes': _Opt(
|
|
217
|
+
False, 'env', ENUM(True, False, 'translated', 'untranslated')),
|
|
218
|
+
|
|
219
|
+
'master_doc': _Opt('index', 'env', ()),
|
|
220
|
+
'root_doc': _Opt(lambda config: config.master_doc, 'env', ()),
|
|
221
|
+
# ``source_suffix`` type is actually ``dict[str, str | None]``:
|
|
222
|
+
# see ``convert_source_suffix()`` below.
|
|
223
|
+
'source_suffix': _Opt(
|
|
224
|
+
{'.rst': 'restructuredtext'}, 'env', Any), # type: ignore[arg-type]
|
|
225
|
+
'source_encoding': _Opt('utf-8-sig', 'env', ()),
|
|
226
|
+
'exclude_patterns': _Opt([], 'env', frozenset((str,))),
|
|
227
|
+
'include_patterns': _Opt(["**"], 'env', frozenset((str,))),
|
|
228
|
+
'default_role': _Opt(None, 'env', frozenset((str,))),
|
|
229
|
+
'add_function_parentheses': _Opt(True, 'env', ()),
|
|
230
|
+
'add_module_names': _Opt(True, 'env', ()),
|
|
231
|
+
'toc_object_entries': _Opt(True, 'env', frozenset((bool,))),
|
|
232
|
+
'toc_object_entries_show_parents': _Opt(
|
|
233
|
+
'domain', 'env', ENUM('domain', 'all', 'hide')),
|
|
234
|
+
'trim_footnote_reference_space': _Opt(False, 'env', ()),
|
|
235
|
+
'show_authors': _Opt(False, 'env', ()),
|
|
236
|
+
'pygments_style': _Opt(None, 'html', frozenset((str,))),
|
|
237
|
+
'highlight_language': _Opt('default', 'env', ()),
|
|
238
|
+
'highlight_options': _Opt({}, 'env', ()),
|
|
239
|
+
'templates_path': _Opt([], 'html', ()),
|
|
240
|
+
'template_bridge': _Opt(None, 'html', frozenset((str,))),
|
|
241
|
+
'keep_warnings': _Opt(False, 'env', ()),
|
|
242
|
+
'suppress_warnings': _Opt([], 'env', ()),
|
|
243
|
+
'show_warning_types': _Opt(False, 'env', frozenset((bool,))),
|
|
244
|
+
'modindex_common_prefix': _Opt([], 'html', ()),
|
|
245
|
+
'rst_epilog': _Opt(None, 'env', frozenset((str,))),
|
|
246
|
+
'rst_prolog': _Opt(None, 'env', frozenset((str,))),
|
|
247
|
+
'trim_doctest_flags': _Opt(True, 'env', ()),
|
|
248
|
+
'primary_domain': _Opt('py', 'env', frozenset((NoneType,))),
|
|
249
|
+
'needs_sphinx': _Opt(None, '', frozenset((str,))),
|
|
250
|
+
'needs_extensions': _Opt({}, '', ()),
|
|
251
|
+
'manpages_url': _Opt(None, 'env', ()),
|
|
252
|
+
'nitpicky': _Opt(False, '', ()),
|
|
253
|
+
'nitpick_ignore': _Opt([], '', frozenset((set, list, tuple))),
|
|
254
|
+
'nitpick_ignore_regex': _Opt([], '', frozenset((set, list, tuple))),
|
|
255
|
+
'numfig': _Opt(False, 'env', ()),
|
|
256
|
+
'numfig_secnum_depth': _Opt(1, 'env', ()),
|
|
257
|
+
'numfig_format': _Opt({}, 'env', ()), # will be initialized in init_numfig_format()
|
|
258
|
+
'maximum_signature_line_length': _Opt(
|
|
259
|
+
None, 'env', frozenset((int, NoneType))),
|
|
260
|
+
'math_number_all': _Opt(False, 'env', ()),
|
|
261
|
+
'math_eqref_format': _Opt(None, 'env', frozenset((str,))),
|
|
262
|
+
'math_numfig': _Opt(True, 'env', ()),
|
|
263
|
+
'tls_verify': _Opt(True, 'env', ()),
|
|
264
|
+
'tls_cacerts': _Opt(None, 'env', ()),
|
|
265
|
+
'user_agent': _Opt(None, 'env', frozenset((str,))),
|
|
266
|
+
'smartquotes': _Opt(True, 'env', ()),
|
|
267
|
+
'smartquotes_action': _Opt('qDe', 'env', ()),
|
|
268
|
+
'smartquotes_excludes': _Opt(
|
|
269
|
+
{'languages': ['ja'], 'builders': ['man', 'text']}, 'env', ()),
|
|
270
|
+
'option_emphasise_placeholders': _Opt(False, 'env', ()),
|
|
156
271
|
}
|
|
157
272
|
|
|
158
273
|
def __init__(self, config: dict[str, Any] | None = None,
|
|
159
274
|
overrides: dict[str, Any] | None = None) -> None:
|
|
160
|
-
|
|
161
|
-
self.
|
|
162
|
-
self.
|
|
163
|
-
self._raw_config =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
275
|
+
raw_config: dict[str, Any] = config or {}
|
|
276
|
+
self._overrides = dict(overrides) if overrides is not None else {}
|
|
277
|
+
self._options = Config.config_values.copy()
|
|
278
|
+
self._raw_config = raw_config
|
|
279
|
+
|
|
280
|
+
for name in list(self._overrides.keys()):
|
|
281
|
+
if '.' in name:
|
|
282
|
+
real_name, key = name.split('.', 1)
|
|
283
|
+
raw_config.setdefault(real_name, {})[key] = self._overrides.pop(name)
|
|
284
|
+
|
|
285
|
+
self.setup: _ExtensionSetupFunc | None = raw_config.get('setup')
|
|
286
|
+
|
|
287
|
+
if 'extensions' in self._overrides:
|
|
288
|
+
extensions = self._overrides.pop('extensions')
|
|
289
|
+
if isinstance(extensions, str):
|
|
290
|
+
raw_config['extensions'] = extensions.split(',')
|
|
169
291
|
else:
|
|
170
|
-
|
|
171
|
-
self.extensions: list[str] =
|
|
292
|
+
raw_config['extensions'] = extensions
|
|
293
|
+
self.extensions: list[str] = raw_config.get('extensions', [])
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def values(self) -> dict[str, _Opt]:
|
|
297
|
+
return self._options
|
|
298
|
+
|
|
299
|
+
@property
|
|
300
|
+
def overrides(self) -> dict[str, Any]:
|
|
301
|
+
return self._overrides
|
|
172
302
|
|
|
173
303
|
@classmethod
|
|
174
|
-
def read(cls, confdir: str | os.PathLike[str], overrides: dict | None = None,
|
|
304
|
+
def read(cls: type[Config], confdir: str | os.PathLike[str], overrides: dict | None = None,
|
|
175
305
|
tags: Tags | None = None) -> Config:
|
|
176
306
|
"""Create a Config object from configuration file."""
|
|
177
307
|
filename = path.join(confdir, CONFIG_FILENAME)
|
|
@@ -190,106 +320,103 @@ class Config:
|
|
|
190
320
|
"Falling back to 'en' (English)."))
|
|
191
321
|
namespace["language"] = "en"
|
|
192
322
|
|
|
193
|
-
return cls(namespace, overrides
|
|
323
|
+
return cls(namespace, overrides)
|
|
194
324
|
|
|
195
|
-
def convert_overrides(self, name: str, value:
|
|
196
|
-
|
|
325
|
+
def convert_overrides(self, name: str, value: str) -> Any:
|
|
326
|
+
opt = self._options[name]
|
|
327
|
+
default = opt.default
|
|
328
|
+
valid_types = opt.valid_types
|
|
329
|
+
if valid_types == Any:
|
|
197
330
|
return value
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# given falsy string from command line option
|
|
205
|
-
return False
|
|
206
|
-
elif value == '1':
|
|
207
|
-
return True
|
|
208
|
-
else:
|
|
209
|
-
return value
|
|
210
|
-
elif type(defvalue) is bool or self.values[name][2] == [bool]:
|
|
211
|
-
if value == '0':
|
|
212
|
-
# given falsy string from command line option
|
|
213
|
-
return False
|
|
214
|
-
else:
|
|
215
|
-
return bool(value)
|
|
216
|
-
elif isinstance(defvalue, dict):
|
|
217
|
-
raise ValueError(__('cannot override dictionary config setting %r, '
|
|
218
|
-
'ignoring (use %r to set individual elements)') %
|
|
219
|
-
(name, name + '.key=value'))
|
|
220
|
-
elif isinstance(defvalue, list):
|
|
221
|
-
return value.split(',')
|
|
222
|
-
elif isinstance(defvalue, int):
|
|
223
|
-
try:
|
|
224
|
-
return int(value)
|
|
225
|
-
except ValueError as exc:
|
|
226
|
-
raise ValueError(__('invalid number %r for config value %r, ignoring') %
|
|
227
|
-
(value, name)) from exc
|
|
228
|
-
elif callable(defvalue):
|
|
331
|
+
elif (type(default) is bool
|
|
332
|
+
or (not isinstance(valid_types, ENUM)
|
|
333
|
+
and len(valid_types) == 1 and bool in valid_types)):
|
|
334
|
+
if isinstance(valid_types, ENUM) or len(valid_types) > 1:
|
|
335
|
+
# if valid_types are given, and non-bool valid types exist,
|
|
336
|
+
# return the value without coercing to a Boolean.
|
|
229
337
|
return value
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
extensions.
|
|
240
|
-
"""
|
|
241
|
-
variables = ['needs_sphinx', 'suppress_warnings', 'language', 'locale_dirs']
|
|
242
|
-
for name in variables:
|
|
338
|
+
# given falsy string from a command line option
|
|
339
|
+
return value not in {'0', ''}
|
|
340
|
+
elif isinstance(default, dict):
|
|
341
|
+
raise ValueError(__('cannot override dictionary config setting %r, '
|
|
342
|
+
'ignoring (use %r to set individual elements)') %
|
|
343
|
+
(name, f'{name}.key=value'))
|
|
344
|
+
elif isinstance(default, list):
|
|
345
|
+
return value.split(',')
|
|
346
|
+
elif isinstance(default, int):
|
|
243
347
|
try:
|
|
244
|
-
|
|
245
|
-
self.__dict__[name] = self.convert_overrides(name, self.overrides[name])
|
|
246
|
-
elif name in self._raw_config:
|
|
247
|
-
self.__dict__[name] = self._raw_config[name]
|
|
348
|
+
return int(value)
|
|
248
349
|
except ValueError as exc:
|
|
249
|
-
|
|
350
|
+
raise ValueError(__('invalid number %r for config value %r, ignoring') %
|
|
351
|
+
(value, name)) from exc
|
|
352
|
+
elif callable(default):
|
|
353
|
+
return value
|
|
354
|
+
elif default is not None and not isinstance(default, str):
|
|
355
|
+
raise ValueError(__('cannot override config setting %r with unsupported '
|
|
356
|
+
'type, ignoring') % name)
|
|
357
|
+
else:
|
|
358
|
+
return value
|
|
359
|
+
|
|
360
|
+
@staticmethod
|
|
361
|
+
def pre_init_values() -> None:
|
|
362
|
+
# method only retained for compatibility
|
|
363
|
+
pass
|
|
364
|
+
# warnings.warn(
|
|
365
|
+
# 'Config.pre_init_values() will be removed in Sphinx 9.0 or later',
|
|
366
|
+
# RemovedInSphinx90Warning, stacklevel=2)
|
|
250
367
|
|
|
251
368
|
def init_values(self) -> None:
|
|
252
|
-
|
|
253
|
-
|
|
369
|
+
# method only retained for compatibility
|
|
370
|
+
self._report_override_warnings()
|
|
371
|
+
# warnings.warn(
|
|
372
|
+
# 'Config.init_values() will be removed in Sphinx 9.0 or later',
|
|
373
|
+
# RemovedInSphinx90Warning, stacklevel=2)
|
|
374
|
+
|
|
375
|
+
def _report_override_warnings(self) -> None:
|
|
376
|
+
for name in self._overrides:
|
|
377
|
+
if name not in self._options:
|
|
378
|
+
logger.warning(__('unknown config value %r in override, ignoring'), name)
|
|
379
|
+
|
|
380
|
+
def __repr__(self) -> str:
|
|
381
|
+
values = []
|
|
382
|
+
for opt_name in self._options:
|
|
254
383
|
try:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
logger.warning(__('unknown config value %r in override, ignoring'),
|
|
261
|
-
valname)
|
|
262
|
-
continue
|
|
263
|
-
if isinstance(value, str):
|
|
264
|
-
config[valname] = self.convert_overrides(valname, value)
|
|
265
|
-
else:
|
|
266
|
-
config[valname] = value
|
|
267
|
-
except ValueError as exc:
|
|
268
|
-
logger.warning("%s", exc)
|
|
269
|
-
for name in config:
|
|
270
|
-
if name in self.values:
|
|
271
|
-
self.__dict__[name] = config[name]
|
|
272
|
-
|
|
273
|
-
def post_init_values(self) -> None:
|
|
274
|
-
"""
|
|
275
|
-
Initialize additional config variables that are added after init_values() called.
|
|
276
|
-
"""
|
|
277
|
-
config = self._raw_config
|
|
278
|
-
for name in config:
|
|
279
|
-
if name not in self.__dict__ and name in self.values:
|
|
280
|
-
self.__dict__[name] = config[name]
|
|
281
|
-
|
|
282
|
-
check_confval_types(None, self)
|
|
384
|
+
opt_value = getattr(self, opt_name)
|
|
385
|
+
except Exception:
|
|
386
|
+
opt_value = '<error!>'
|
|
387
|
+
values.append(f"{opt_name}={opt_value!r}")
|
|
388
|
+
return self.__class__.__qualname__ + '(' + ', '.join(values) + ')'
|
|
283
389
|
|
|
284
390
|
def __getattr__(self, name: str) -> Any:
|
|
391
|
+
if name in self._options:
|
|
392
|
+
# first check command-line overrides
|
|
393
|
+
if name in self._overrides:
|
|
394
|
+
value = self._overrides[name]
|
|
395
|
+
if not isinstance(value, str):
|
|
396
|
+
self.__dict__[name] = value
|
|
397
|
+
return value
|
|
398
|
+
try:
|
|
399
|
+
value = self.convert_overrides(name, value)
|
|
400
|
+
except ValueError as exc:
|
|
401
|
+
logger.warning("%s", exc)
|
|
402
|
+
else:
|
|
403
|
+
self.__dict__[name] = value
|
|
404
|
+
return value
|
|
405
|
+
# then check values from 'conf.py'
|
|
406
|
+
if name in self._raw_config:
|
|
407
|
+
self.__dict__[name] = value = self._raw_config[name]
|
|
408
|
+
return value
|
|
409
|
+
# finally, fall back to the default value
|
|
410
|
+
default = self._options[name].default
|
|
411
|
+
if callable(default):
|
|
412
|
+
return default(self)
|
|
413
|
+
self.__dict__[name] = default
|
|
414
|
+
return default
|
|
285
415
|
if name.startswith('_'):
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if callable(default):
|
|
291
|
-
return default(self)
|
|
292
|
-
return default
|
|
416
|
+
msg = f'{self.__class__.__name__!r} object has no attribute {name!r}'
|
|
417
|
+
raise AttributeError(msg)
|
|
418
|
+
msg = __('No such config value: %r') % name
|
|
419
|
+
raise AttributeError(msg)
|
|
293
420
|
|
|
294
421
|
def __getitem__(self, name: str) -> Any:
|
|
295
422
|
return getattr(self, name)
|
|
@@ -301,46 +428,68 @@ class Config:
|
|
|
301
428
|
delattr(self, name)
|
|
302
429
|
|
|
303
430
|
def __contains__(self, name: str) -> bool:
|
|
304
|
-
return name in self.
|
|
431
|
+
return name in self._options
|
|
305
432
|
|
|
306
|
-
def __iter__(self) ->
|
|
307
|
-
for name,
|
|
308
|
-
yield ConfigValue(name, getattr(self, name),
|
|
433
|
+
def __iter__(self) -> Iterator[ConfigValue]:
|
|
434
|
+
for name, opt in self._options.items():
|
|
435
|
+
yield ConfigValue(name, getattr(self, name), opt.rebuild)
|
|
309
436
|
|
|
310
|
-
def add(self, name: str, default: Any, rebuild:
|
|
311
|
-
|
|
437
|
+
def add(self, name: str, default: Any, rebuild: _ConfigRebuild,
|
|
438
|
+
types: type | Collection[type] | ENUM) -> None:
|
|
439
|
+
if name in self._options:
|
|
312
440
|
raise ExtensionError(__('Config value %r already present') % name)
|
|
313
|
-
self.values[name] = (default, rebuild, types)
|
|
314
441
|
|
|
315
|
-
|
|
442
|
+
# standardise rebuild
|
|
443
|
+
if isinstance(rebuild, bool):
|
|
444
|
+
rebuild = 'env' if rebuild else ''
|
|
445
|
+
|
|
446
|
+
# standardise valid_types
|
|
447
|
+
valid_types = _validate_valid_types(types)
|
|
448
|
+
self._options[name] = _Opt(default, rebuild, valid_types)
|
|
449
|
+
|
|
450
|
+
def filter(self, rebuild: Set[_ConfigRebuild]) -> Iterator[ConfigValue]:
|
|
316
451
|
if isinstance(rebuild, str):
|
|
317
|
-
rebuild
|
|
452
|
+
return (value for value in self if value.rebuild == rebuild)
|
|
318
453
|
return (value for value in self if value.rebuild in rebuild)
|
|
319
454
|
|
|
320
455
|
def __getstate__(self) -> dict:
|
|
321
456
|
"""Obtains serializable data for pickling."""
|
|
322
457
|
# remove potentially pickling-problematic values from config
|
|
323
|
-
__dict__ = {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
for key, value in self.values.items():
|
|
333
|
-
real_value = getattr(self, key)
|
|
458
|
+
__dict__ = {
|
|
459
|
+
key: value
|
|
460
|
+
for key, value in self.__dict__.items()
|
|
461
|
+
if not key.startswith('_') and is_serializable(value)
|
|
462
|
+
}
|
|
463
|
+
# create a picklable copy of ``self._options``
|
|
464
|
+
__dict__['_options'] = _options = {}
|
|
465
|
+
for name, opt in self._options.items():
|
|
466
|
+
real_value = getattr(self, name)
|
|
334
467
|
if not is_serializable(real_value):
|
|
468
|
+
if opt.rebuild:
|
|
469
|
+
# if the value is not cached, then any build that utilises this cache
|
|
470
|
+
# will always mark the config value as changed,
|
|
471
|
+
# and thus always invalidate the cache and perform a rebuild.
|
|
472
|
+
logger.warning(
|
|
473
|
+
__('cannot cache unpickable configuration value: %r'),
|
|
474
|
+
name,
|
|
475
|
+
type='config',
|
|
476
|
+
subtype='cache',
|
|
477
|
+
once=True,
|
|
478
|
+
)
|
|
335
479
|
# omit unserializable value
|
|
336
480
|
real_value = None
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
__dict__['values'][key] = (real_value, value[1], None)
|
|
481
|
+
# valid_types is also omitted
|
|
482
|
+
_options[name] = real_value, opt.rebuild
|
|
340
483
|
|
|
341
484
|
return __dict__
|
|
342
485
|
|
|
343
486
|
def __setstate__(self, state: dict) -> None:
|
|
487
|
+
self._overrides = {}
|
|
488
|
+
self._options = {
|
|
489
|
+
name: _Opt(real_value, rebuild, ())
|
|
490
|
+
for name, (real_value, rebuild) in state.pop('_options').items()
|
|
491
|
+
}
|
|
492
|
+
self._raw_config = {}
|
|
344
493
|
self.__dict__.update(state)
|
|
345
494
|
|
|
346
495
|
|
|
@@ -373,6 +522,29 @@ def eval_config_file(filename: str, tags: Tags | None) -> dict[str, Any]:
|
|
|
373
522
|
return namespace
|
|
374
523
|
|
|
375
524
|
|
|
525
|
+
def _validate_valid_types(
|
|
526
|
+
valid_types: type | Collection[type] | ENUM, /,
|
|
527
|
+
) -> tuple[()] | tuple[type, ...] | frozenset[type] | ENUM:
|
|
528
|
+
if not valid_types:
|
|
529
|
+
return ()
|
|
530
|
+
if isinstance(valid_types, (frozenset, ENUM)):
|
|
531
|
+
return valid_types
|
|
532
|
+
if isinstance(valid_types, type):
|
|
533
|
+
return frozenset((valid_types,))
|
|
534
|
+
if isinstance(valid_types, set):
|
|
535
|
+
return frozenset(valid_types)
|
|
536
|
+
if not isinstance(valid_types, tuple):
|
|
537
|
+
try:
|
|
538
|
+
valid_types = tuple(valid_types)
|
|
539
|
+
except TypeError:
|
|
540
|
+
logger.warning(__('Failed to convert %r to a set or tuple'), valid_types)
|
|
541
|
+
return valid_types # type: ignore[return-value]
|
|
542
|
+
try:
|
|
543
|
+
return frozenset(valid_types)
|
|
544
|
+
except TypeError:
|
|
545
|
+
return valid_types
|
|
546
|
+
|
|
547
|
+
|
|
376
548
|
def convert_source_suffix(app: Sphinx, config: Config) -> None:
|
|
377
549
|
"""Convert old styled source_suffix to new styled one.
|
|
378
550
|
|
|
@@ -388,7 +560,7 @@ def convert_source_suffix(app: Sphinx, config: Config) -> None:
|
|
|
388
560
|
config.source_suffix = {source_suffix: None} # type: ignore[attr-defined]
|
|
389
561
|
elif isinstance(source_suffix, (list, tuple)):
|
|
390
562
|
# if list, considers as all of them are default filetype
|
|
391
|
-
config.source_suffix =
|
|
563
|
+
config.source_suffix = dict.fromkeys(source_suffix, None) # type: ignore[attr-defined]
|
|
392
564
|
elif not isinstance(source_suffix, dict):
|
|
393
565
|
logger.warning(__("The config value `source_suffix' expects "
|
|
394
566
|
"a string, list of strings, or dictionary. "
|
|
@@ -463,7 +635,7 @@ def _substitute_copyright_year(copyright_line: str, replace_year: str) -> str:
|
|
|
463
635
|
if copyright_line[4] != '-':
|
|
464
636
|
return copyright_line
|
|
465
637
|
|
|
466
|
-
if copyright_line[5:9].isdigit() and copyright_line[9] in ' ,':
|
|
638
|
+
if copyright_line[5:9].isdigit() and copyright_line[9:10] in {'', ' ', ','}:
|
|
467
639
|
return copyright_line[:5] + replace_year + copyright_line[9:]
|
|
468
640
|
|
|
469
641
|
return copyright_line
|
|
@@ -473,54 +645,64 @@ def check_confval_types(app: Sphinx | None, config: Config) -> None:
|
|
|
473
645
|
"""Check all values for deviation from the default value's type, since
|
|
474
646
|
that can result in TypeErrors all over the place NB.
|
|
475
647
|
"""
|
|
476
|
-
for
|
|
477
|
-
default
|
|
648
|
+
for name, opt in config._options.items():
|
|
649
|
+
default = opt.default
|
|
650
|
+
valid_types = opt.valid_types
|
|
651
|
+
value = getattr(config, name)
|
|
478
652
|
|
|
479
653
|
if callable(default):
|
|
480
654
|
default = default(config) # evaluate default value
|
|
481
|
-
if default is None and not
|
|
482
|
-
continue # neither inferable nor
|
|
483
|
-
|
|
484
|
-
if
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if not
|
|
655
|
+
if default is None and not valid_types:
|
|
656
|
+
continue # neither inferable nor explicitly annotated types
|
|
657
|
+
|
|
658
|
+
if valid_types is Any: # any type of value is accepted
|
|
659
|
+
continue
|
|
660
|
+
|
|
661
|
+
if isinstance(valid_types, ENUM):
|
|
662
|
+
if not valid_types.match(value):
|
|
489
663
|
msg = __("The config value `{name}` has to be a one of {candidates}, "
|
|
490
664
|
"but `{current}` is given.")
|
|
491
|
-
logger.warning(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
665
|
+
logger.warning(
|
|
666
|
+
msg.format(name=name, current=value, candidates=valid_types.candidates),
|
|
667
|
+
once=True,
|
|
668
|
+
)
|
|
669
|
+
continue
|
|
670
|
+
|
|
671
|
+
type_value = type(value)
|
|
672
|
+
type_default = type(default)
|
|
673
|
+
|
|
674
|
+
if type_value is type_default: # attempt to infer the type
|
|
675
|
+
continue
|
|
676
|
+
|
|
677
|
+
if type_value in valid_types: # check explicitly listed types
|
|
678
|
+
continue
|
|
679
|
+
|
|
680
|
+
common_bases = ({*type_value.__bases__, type_value}
|
|
681
|
+
& set(type_default.__bases__))
|
|
682
|
+
common_bases.discard(object)
|
|
683
|
+
if common_bases:
|
|
684
|
+
continue # at least we share a non-trivial base class
|
|
685
|
+
|
|
686
|
+
if valid_types:
|
|
687
|
+
msg = __("The config value `{name}' has type `{current.__name__}'; "
|
|
688
|
+
"expected {permitted}.")
|
|
689
|
+
wrapped_valid_types = sorted(f"`{c.__name__}'" for c in valid_types)
|
|
690
|
+
if len(wrapped_valid_types) > 2:
|
|
691
|
+
permitted = (", ".join(wrapped_valid_types[:-1])
|
|
692
|
+
+ f", or {wrapped_valid_types[-1]}")
|
|
518
693
|
else:
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
694
|
+
permitted = " or ".join(wrapped_valid_types)
|
|
695
|
+
logger.warning(
|
|
696
|
+
msg.format(name=name, current=type_value, permitted=permitted),
|
|
697
|
+
once=True,
|
|
698
|
+
)
|
|
699
|
+
else:
|
|
700
|
+
msg = __("The config value `{name}' has type `{current.__name__}', "
|
|
701
|
+
"defaults to `{default.__name__}'.")
|
|
702
|
+
logger.warning(
|
|
703
|
+
msg.format(name=name, current=type_value, default=type_default),
|
|
704
|
+
once=True,
|
|
705
|
+
)
|
|
524
706
|
|
|
525
707
|
|
|
526
708
|
def check_primary_domain(app: Sphinx, config: Config) -> None:
|
|
@@ -545,7 +727,7 @@ def check_root_doc(app: Sphinx, env: BuildEnvironment, added: set[str],
|
|
|
545
727
|
return changed
|
|
546
728
|
|
|
547
729
|
|
|
548
|
-
def setup(app: Sphinx) ->
|
|
730
|
+
def setup(app: Sphinx) -> ExtensionMetadata:
|
|
549
731
|
app.connect('config-inited', convert_source_suffix, priority=800)
|
|
550
732
|
app.connect('config-inited', convert_highlight_options, priority=800)
|
|
551
733
|
app.connect('config-inited', init_numfig_format, priority=800)
|