Sphinx 7.2.5__py3-none-any.whl → 7.3.0__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 +21 -20
- 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 +132 -52
- 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.5.dist-info/LICENSE → sphinx-7.3.0.dist-info/LICENSE.rst +1 -1
- {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/METADATA +13 -12
- sphinx-7.3.0.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.5.dist-info/RECORD +0 -569
- {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/WHEEL +0 -0
- {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,890 @@
|
|
|
1
|
+
"""The Python domain."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import builtins
|
|
6
|
+
import inspect
|
|
7
|
+
import typing
|
|
8
|
+
from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple, cast
|
|
9
|
+
|
|
10
|
+
from docutils import nodes
|
|
11
|
+
from docutils.parsers.rst import directives
|
|
12
|
+
|
|
13
|
+
from sphinx import addnodes
|
|
14
|
+
from sphinx.domains import Domain, Index, IndexEntry, ObjType
|
|
15
|
+
from sphinx.domains.python._annotations import _parse_annotation
|
|
16
|
+
from sphinx.domains.python._object import PyObject
|
|
17
|
+
from sphinx.locale import _, __
|
|
18
|
+
from sphinx.roles import XRefRole
|
|
19
|
+
from sphinx.util import logging
|
|
20
|
+
from sphinx.util.docutils import SphinxDirective
|
|
21
|
+
from sphinx.util.nodes import (
|
|
22
|
+
find_pending_xref_condition,
|
|
23
|
+
make_id,
|
|
24
|
+
make_refnode,
|
|
25
|
+
nested_parse_with_titles,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from collections.abc import Iterable, Iterator
|
|
30
|
+
|
|
31
|
+
from docutils.nodes import Element, Node
|
|
32
|
+
|
|
33
|
+
from sphinx.addnodes import desc_signature, pending_xref
|
|
34
|
+
from sphinx.application import Sphinx
|
|
35
|
+
from sphinx.builders import Builder
|
|
36
|
+
from sphinx.environment import BuildEnvironment
|
|
37
|
+
from sphinx.util.typing import ExtensionMetadata, OptionSpec
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
pairindextypes = {
|
|
42
|
+
'module': 'module',
|
|
43
|
+
'keyword': 'keyword',
|
|
44
|
+
'operator': 'operator',
|
|
45
|
+
'object': 'object',
|
|
46
|
+
'exception': 'exception',
|
|
47
|
+
'statement': 'statement',
|
|
48
|
+
'builtin': 'built-in function',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ObjectEntry(NamedTuple):
|
|
53
|
+
docname: str
|
|
54
|
+
node_id: str
|
|
55
|
+
objtype: str
|
|
56
|
+
aliased: bool
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ModuleEntry(NamedTuple):
|
|
60
|
+
docname: str
|
|
61
|
+
node_id: str
|
|
62
|
+
synopsis: str
|
|
63
|
+
platform: str
|
|
64
|
+
deprecated: bool
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PyFunction(PyObject):
|
|
68
|
+
"""Description of a function."""
|
|
69
|
+
|
|
70
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy() # noqa: F821
|
|
71
|
+
option_spec.update({
|
|
72
|
+
'async': directives.flag,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
76
|
+
if 'async' in self.options:
|
|
77
|
+
return [addnodes.desc_sig_keyword('', 'async'),
|
|
78
|
+
addnodes.desc_sig_space()]
|
|
79
|
+
else:
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
def needs_arglist(self) -> bool:
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
def add_target_and_index(self, name_cls: tuple[str, str], sig: str,
|
|
86
|
+
signode: desc_signature) -> None:
|
|
87
|
+
super().add_target_and_index(name_cls, sig, signode)
|
|
88
|
+
if 'no-index-entry' not in self.options:
|
|
89
|
+
modname = self.options.get('module', self.env.ref_context.get('py:module'))
|
|
90
|
+
node_id = signode['ids'][0]
|
|
91
|
+
|
|
92
|
+
name, cls = name_cls
|
|
93
|
+
if modname:
|
|
94
|
+
text = _('%s() (in module %s)') % (name, modname)
|
|
95
|
+
self.indexnode['entries'].append(('single', text, node_id, '', None))
|
|
96
|
+
else:
|
|
97
|
+
text = f'built-in function; {name}()'
|
|
98
|
+
self.indexnode['entries'].append(('pair', text, node_id, '', None))
|
|
99
|
+
|
|
100
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
101
|
+
# add index in own add_target_and_index() instead.
|
|
102
|
+
return ''
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class PyDecoratorFunction(PyFunction):
|
|
106
|
+
"""Description of a decorator."""
|
|
107
|
+
|
|
108
|
+
def run(self) -> list[Node]:
|
|
109
|
+
# a decorator function is a function after all
|
|
110
|
+
self.name = 'py:function'
|
|
111
|
+
return super().run()
|
|
112
|
+
|
|
113
|
+
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
114
|
+
ret = super().handle_signature(sig, signode)
|
|
115
|
+
signode.insert(0, addnodes.desc_addname('@', '@'))
|
|
116
|
+
return ret
|
|
117
|
+
|
|
118
|
+
def needs_arglist(self) -> bool:
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class PyVariable(PyObject):
|
|
123
|
+
"""Description of a variable."""
|
|
124
|
+
|
|
125
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
126
|
+
option_spec.update({
|
|
127
|
+
'type': directives.unchanged,
|
|
128
|
+
'value': directives.unchanged,
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
132
|
+
fullname, prefix = super().handle_signature(sig, signode)
|
|
133
|
+
|
|
134
|
+
typ = self.options.get('type')
|
|
135
|
+
if typ:
|
|
136
|
+
annotations = _parse_annotation(typ, self.env)
|
|
137
|
+
signode += addnodes.desc_annotation(typ, '',
|
|
138
|
+
addnodes.desc_sig_punctuation('', ':'),
|
|
139
|
+
addnodes.desc_sig_space(), *annotations)
|
|
140
|
+
|
|
141
|
+
value = self.options.get('value')
|
|
142
|
+
if value:
|
|
143
|
+
signode += addnodes.desc_annotation(value, '',
|
|
144
|
+
addnodes.desc_sig_space(),
|
|
145
|
+
addnodes.desc_sig_punctuation('', '='),
|
|
146
|
+
addnodes.desc_sig_space(),
|
|
147
|
+
nodes.Text(value))
|
|
148
|
+
|
|
149
|
+
return fullname, prefix
|
|
150
|
+
|
|
151
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
152
|
+
name, cls = name_cls
|
|
153
|
+
if modname:
|
|
154
|
+
return _('%s (in module %s)') % (name, modname)
|
|
155
|
+
else:
|
|
156
|
+
return _('%s (built-in variable)') % name
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class PyClasslike(PyObject):
|
|
160
|
+
"""
|
|
161
|
+
Description of a class-like object (classes, interfaces, exceptions).
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
165
|
+
option_spec.update({
|
|
166
|
+
'final': directives.flag,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
allow_nesting = True
|
|
170
|
+
|
|
171
|
+
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
172
|
+
if 'final' in self.options:
|
|
173
|
+
return [nodes.Text('final'), addnodes.desc_sig_space(),
|
|
174
|
+
nodes.Text(self.objtype), addnodes.desc_sig_space()]
|
|
175
|
+
else:
|
|
176
|
+
return [nodes.Text(self.objtype), addnodes.desc_sig_space()]
|
|
177
|
+
|
|
178
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
179
|
+
if self.objtype == 'class':
|
|
180
|
+
if not modname:
|
|
181
|
+
return _('%s (built-in class)') % name_cls[0]
|
|
182
|
+
return _('%s (class in %s)') % (name_cls[0], modname)
|
|
183
|
+
elif self.objtype == 'exception':
|
|
184
|
+
return name_cls[0]
|
|
185
|
+
else:
|
|
186
|
+
return ''
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class PyMethod(PyObject):
|
|
190
|
+
"""Description of a method."""
|
|
191
|
+
|
|
192
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
193
|
+
option_spec.update({
|
|
194
|
+
'abstractmethod': directives.flag,
|
|
195
|
+
'async': directives.flag,
|
|
196
|
+
'classmethod': directives.flag,
|
|
197
|
+
'final': directives.flag,
|
|
198
|
+
'staticmethod': directives.flag,
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
def needs_arglist(self) -> bool:
|
|
202
|
+
return True
|
|
203
|
+
|
|
204
|
+
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
205
|
+
prefix: list[nodes.Node] = []
|
|
206
|
+
if 'final' in self.options:
|
|
207
|
+
prefix.append(nodes.Text('final'))
|
|
208
|
+
prefix.append(addnodes.desc_sig_space())
|
|
209
|
+
if 'abstractmethod' in self.options:
|
|
210
|
+
prefix.append(nodes.Text('abstract'))
|
|
211
|
+
prefix.append(addnodes.desc_sig_space())
|
|
212
|
+
if 'async' in self.options:
|
|
213
|
+
prefix.append(nodes.Text('async'))
|
|
214
|
+
prefix.append(addnodes.desc_sig_space())
|
|
215
|
+
if 'classmethod' in self.options:
|
|
216
|
+
prefix.append(nodes.Text('classmethod'))
|
|
217
|
+
prefix.append(addnodes.desc_sig_space())
|
|
218
|
+
if 'staticmethod' in self.options:
|
|
219
|
+
prefix.append(nodes.Text('static'))
|
|
220
|
+
prefix.append(addnodes.desc_sig_space())
|
|
221
|
+
return prefix
|
|
222
|
+
|
|
223
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
224
|
+
name, cls = name_cls
|
|
225
|
+
try:
|
|
226
|
+
clsname, methname = name.rsplit('.', 1)
|
|
227
|
+
if modname and self.env.config.add_module_names:
|
|
228
|
+
clsname = f'{modname}.{clsname}'
|
|
229
|
+
except ValueError:
|
|
230
|
+
if modname:
|
|
231
|
+
return _('%s() (in module %s)') % (name, modname)
|
|
232
|
+
else:
|
|
233
|
+
return '%s()' % name
|
|
234
|
+
|
|
235
|
+
if 'classmethod' in self.options:
|
|
236
|
+
return _('%s() (%s class method)') % (methname, clsname)
|
|
237
|
+
elif 'staticmethod' in self.options:
|
|
238
|
+
return _('%s() (%s static method)') % (methname, clsname)
|
|
239
|
+
else:
|
|
240
|
+
return _('%s() (%s method)') % (methname, clsname)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class PyClassMethod(PyMethod):
|
|
244
|
+
"""Description of a classmethod."""
|
|
245
|
+
|
|
246
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
247
|
+
|
|
248
|
+
def run(self) -> list[Node]:
|
|
249
|
+
self.name = 'py:method'
|
|
250
|
+
self.options['classmethod'] = True
|
|
251
|
+
|
|
252
|
+
return super().run()
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class PyStaticMethod(PyMethod):
|
|
256
|
+
"""Description of a staticmethod."""
|
|
257
|
+
|
|
258
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
259
|
+
|
|
260
|
+
def run(self) -> list[Node]:
|
|
261
|
+
self.name = 'py:method'
|
|
262
|
+
self.options['staticmethod'] = True
|
|
263
|
+
|
|
264
|
+
return super().run()
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class PyDecoratorMethod(PyMethod):
|
|
268
|
+
"""Description of a decoratormethod."""
|
|
269
|
+
|
|
270
|
+
def run(self) -> list[Node]:
|
|
271
|
+
self.name = 'py:method'
|
|
272
|
+
return super().run()
|
|
273
|
+
|
|
274
|
+
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
275
|
+
ret = super().handle_signature(sig, signode)
|
|
276
|
+
signode.insert(0, addnodes.desc_addname('@', '@'))
|
|
277
|
+
return ret
|
|
278
|
+
|
|
279
|
+
def needs_arglist(self) -> bool:
|
|
280
|
+
return False
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class PyAttribute(PyObject):
|
|
284
|
+
"""Description of an attribute."""
|
|
285
|
+
|
|
286
|
+
option_spec: ClassVar[OptionSpec] = PyObject.option_spec.copy()
|
|
287
|
+
option_spec.update({
|
|
288
|
+
'type': directives.unchanged,
|
|
289
|
+
'value': directives.unchanged,
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
293
|
+
fullname, prefix = super().handle_signature(sig, signode)
|
|
294
|
+
|
|
295
|
+
typ = self.options.get('type')
|
|
296
|
+
if typ:
|
|
297
|
+
annotations = _parse_annotation(typ, self.env)
|
|
298
|
+
signode += addnodes.desc_annotation(typ, '',
|
|
299
|
+
addnodes.desc_sig_punctuation('', ':'),
|
|
300
|
+
addnodes.desc_sig_space(),
|
|
301
|
+
*annotations)
|
|
302
|
+
|
|
303
|
+
value = self.options.get('value')
|
|
304
|
+
if value:
|
|
305
|
+
signode += addnodes.desc_annotation(value, '',
|
|
306
|
+
addnodes.desc_sig_space(),
|
|
307
|
+
addnodes.desc_sig_punctuation('', '='),
|
|
308
|
+
addnodes.desc_sig_space(),
|
|
309
|
+
nodes.Text(value))
|
|
310
|
+
|
|
311
|
+
return fullname, prefix
|
|
312
|
+
|
|
313
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
314
|
+
name, cls = name_cls
|
|
315
|
+
try:
|
|
316
|
+
clsname, attrname = name.rsplit('.', 1)
|
|
317
|
+
if modname and self.env.config.add_module_names:
|
|
318
|
+
clsname = f'{modname}.{clsname}'
|
|
319
|
+
except ValueError:
|
|
320
|
+
if modname:
|
|
321
|
+
return _('%s (in module %s)') % (name, modname)
|
|
322
|
+
else:
|
|
323
|
+
return name
|
|
324
|
+
|
|
325
|
+
return _('%s (%s attribute)') % (attrname, clsname)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class PyProperty(PyObject):
|
|
329
|
+
"""Description of an attribute."""
|
|
330
|
+
|
|
331
|
+
option_spec = PyObject.option_spec.copy()
|
|
332
|
+
option_spec.update({
|
|
333
|
+
'abstractmethod': directives.flag,
|
|
334
|
+
'classmethod': directives.flag,
|
|
335
|
+
'type': directives.unchanged,
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
339
|
+
fullname, prefix = super().handle_signature(sig, signode)
|
|
340
|
+
|
|
341
|
+
typ = self.options.get('type')
|
|
342
|
+
if typ:
|
|
343
|
+
annotations = _parse_annotation(typ, self.env)
|
|
344
|
+
signode += addnodes.desc_annotation(typ, '',
|
|
345
|
+
addnodes.desc_sig_punctuation('', ':'),
|
|
346
|
+
addnodes.desc_sig_space(),
|
|
347
|
+
*annotations)
|
|
348
|
+
|
|
349
|
+
return fullname, prefix
|
|
350
|
+
|
|
351
|
+
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
352
|
+
prefix: list[nodes.Node] = []
|
|
353
|
+
if 'abstractmethod' in self.options:
|
|
354
|
+
prefix.append(nodes.Text('abstract'))
|
|
355
|
+
prefix.append(addnodes.desc_sig_space())
|
|
356
|
+
if 'classmethod' in self.options:
|
|
357
|
+
prefix.append(nodes.Text('class'))
|
|
358
|
+
prefix.append(addnodes.desc_sig_space())
|
|
359
|
+
|
|
360
|
+
prefix.append(nodes.Text('property'))
|
|
361
|
+
prefix.append(addnodes.desc_sig_space())
|
|
362
|
+
return prefix
|
|
363
|
+
|
|
364
|
+
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
365
|
+
name, cls = name_cls
|
|
366
|
+
try:
|
|
367
|
+
clsname, attrname = name.rsplit('.', 1)
|
|
368
|
+
if modname and self.env.config.add_module_names:
|
|
369
|
+
clsname = f'{modname}.{clsname}'
|
|
370
|
+
except ValueError:
|
|
371
|
+
if modname:
|
|
372
|
+
return _('%s (in module %s)') % (name, modname)
|
|
373
|
+
else:
|
|
374
|
+
return name
|
|
375
|
+
|
|
376
|
+
return _('%s (%s property)') % (attrname, clsname)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class PyModule(SphinxDirective):
|
|
380
|
+
"""
|
|
381
|
+
Directive to mark description of a new module.
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
has_content = True
|
|
385
|
+
required_arguments = 1
|
|
386
|
+
optional_arguments = 0
|
|
387
|
+
final_argument_whitespace = False
|
|
388
|
+
option_spec: ClassVar[OptionSpec] = {
|
|
389
|
+
'platform': lambda x: x,
|
|
390
|
+
'synopsis': lambda x: x,
|
|
391
|
+
'no-index': directives.flag,
|
|
392
|
+
'no-contents-entry': directives.flag,
|
|
393
|
+
'no-typesetting': directives.flag,
|
|
394
|
+
'noindex': directives.flag,
|
|
395
|
+
'nocontentsentry': directives.flag,
|
|
396
|
+
'deprecated': directives.flag,
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
def run(self) -> list[Node]:
|
|
400
|
+
domain = cast(PythonDomain, self.env.get_domain('py'))
|
|
401
|
+
|
|
402
|
+
modname = self.arguments[0].strip()
|
|
403
|
+
no_index = 'no-index' in self.options or 'noindex' in self.options
|
|
404
|
+
self.env.ref_context['py:module'] = modname
|
|
405
|
+
|
|
406
|
+
content_node: Element = nodes.section()
|
|
407
|
+
# necessary so that the child nodes get the right source/line set
|
|
408
|
+
content_node.document = self.state.document
|
|
409
|
+
nested_parse_with_titles(self.state, self.content, content_node, self.content_offset)
|
|
410
|
+
|
|
411
|
+
ret: list[Node] = []
|
|
412
|
+
if not no_index:
|
|
413
|
+
# note module to the domain
|
|
414
|
+
node_id = make_id(self.env, self.state.document, 'module', modname)
|
|
415
|
+
target = nodes.target('', '', ids=[node_id], ismod=True)
|
|
416
|
+
self.set_source_info(target)
|
|
417
|
+
self.state.document.note_explicit_target(target)
|
|
418
|
+
|
|
419
|
+
domain.note_module(modname,
|
|
420
|
+
node_id,
|
|
421
|
+
self.options.get('synopsis', ''),
|
|
422
|
+
self.options.get('platform', ''),
|
|
423
|
+
'deprecated' in self.options)
|
|
424
|
+
domain.note_object(modname, 'module', node_id, location=target)
|
|
425
|
+
|
|
426
|
+
# the platform and synopsis aren't printed; in fact, they are only
|
|
427
|
+
# used in the modindex currently
|
|
428
|
+
indextext = f'module; {modname}'
|
|
429
|
+
inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
|
|
430
|
+
# The node order is: index node first, then target node.
|
|
431
|
+
ret.append(inode)
|
|
432
|
+
ret.append(target)
|
|
433
|
+
ret.extend(content_node.children)
|
|
434
|
+
return ret
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class PyCurrentModule(SphinxDirective):
|
|
438
|
+
"""
|
|
439
|
+
This directive is just to tell Sphinx that we're documenting
|
|
440
|
+
stuff in module foo, but links to module foo won't lead here.
|
|
441
|
+
"""
|
|
442
|
+
|
|
443
|
+
has_content = False
|
|
444
|
+
required_arguments = 1
|
|
445
|
+
optional_arguments = 0
|
|
446
|
+
final_argument_whitespace = False
|
|
447
|
+
option_spec: ClassVar[OptionSpec] = {}
|
|
448
|
+
|
|
449
|
+
def run(self) -> list[Node]:
|
|
450
|
+
modname = self.arguments[0].strip()
|
|
451
|
+
if modname == 'None':
|
|
452
|
+
self.env.ref_context.pop('py:module', None)
|
|
453
|
+
else:
|
|
454
|
+
self.env.ref_context['py:module'] = modname
|
|
455
|
+
return []
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class PyXRefRole(XRefRole):
|
|
459
|
+
def process_link(self, env: BuildEnvironment, refnode: Element,
|
|
460
|
+
has_explicit_title: bool, title: str, target: str) -> tuple[str, str]:
|
|
461
|
+
refnode['py:module'] = env.ref_context.get('py:module')
|
|
462
|
+
refnode['py:class'] = env.ref_context.get('py:class')
|
|
463
|
+
if not has_explicit_title:
|
|
464
|
+
title = title.lstrip('.') # only has a meaning for the target
|
|
465
|
+
target = target.lstrip('~') # only has a meaning for the title
|
|
466
|
+
# if the first character is a tilde, don't display the module/class
|
|
467
|
+
# parts of the contents
|
|
468
|
+
if title[0:1] == '~':
|
|
469
|
+
title = title[1:]
|
|
470
|
+
dot = title.rfind('.')
|
|
471
|
+
if dot != -1:
|
|
472
|
+
title = title[dot + 1:]
|
|
473
|
+
# if the first character is a dot, search more specific namespaces first
|
|
474
|
+
# else search builtins first
|
|
475
|
+
if target[0:1] == '.':
|
|
476
|
+
target = target[1:]
|
|
477
|
+
refnode['refspecific'] = True
|
|
478
|
+
return title, target
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def filter_meta_fields(app: Sphinx, domain: str, objtype: str, content: Element) -> None:
|
|
482
|
+
"""Filter ``:meta:`` field from its docstring."""
|
|
483
|
+
if domain != 'py':
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
for node in content:
|
|
487
|
+
if isinstance(node, nodes.field_list):
|
|
488
|
+
fields = cast(list[nodes.field], node)
|
|
489
|
+
# removing list items while iterating the list needs reversed()
|
|
490
|
+
for field in reversed(fields):
|
|
491
|
+
field_name = cast(nodes.field_body, field[0]).astext().strip()
|
|
492
|
+
if field_name == 'meta' or field_name.startswith('meta '):
|
|
493
|
+
node.remove(field)
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
class PythonModuleIndex(Index):
|
|
497
|
+
"""
|
|
498
|
+
Index subclass to provide the Python module index.
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
name = 'modindex'
|
|
502
|
+
localname = _('Python Module Index')
|
|
503
|
+
shortname = _('modules')
|
|
504
|
+
|
|
505
|
+
def generate(self, docnames: Iterable[str] | None = None,
|
|
506
|
+
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
|
|
507
|
+
content: dict[str, list[IndexEntry]] = {}
|
|
508
|
+
# list of prefixes to ignore
|
|
509
|
+
ignores: list[str] = self.domain.env.config['modindex_common_prefix']
|
|
510
|
+
ignores = sorted(ignores, key=len, reverse=True)
|
|
511
|
+
# list of all modules, sorted by module name
|
|
512
|
+
modules = sorted(self.domain.data['modules'].items(),
|
|
513
|
+
key=lambda x: x[0].lower())
|
|
514
|
+
# sort out collapsible modules
|
|
515
|
+
prev_modname = ''
|
|
516
|
+
num_toplevels = 0
|
|
517
|
+
for modname, (docname, node_id, synopsis, platforms, deprecated) in modules:
|
|
518
|
+
if docnames and docname not in docnames:
|
|
519
|
+
continue
|
|
520
|
+
|
|
521
|
+
for ignore in ignores:
|
|
522
|
+
if modname.startswith(ignore):
|
|
523
|
+
modname = modname[len(ignore):]
|
|
524
|
+
stripped = ignore
|
|
525
|
+
break
|
|
526
|
+
else:
|
|
527
|
+
stripped = ''
|
|
528
|
+
|
|
529
|
+
# we stripped the whole module name?
|
|
530
|
+
if not modname:
|
|
531
|
+
modname, stripped = stripped, ''
|
|
532
|
+
|
|
533
|
+
entries = content.setdefault(modname[0].lower(), [])
|
|
534
|
+
|
|
535
|
+
package = modname.split('.')[0]
|
|
536
|
+
if package != modname:
|
|
537
|
+
# it's a submodule
|
|
538
|
+
if prev_modname == package:
|
|
539
|
+
# first submodule - make parent a group head
|
|
540
|
+
if entries:
|
|
541
|
+
last = entries[-1]
|
|
542
|
+
entries[-1] = IndexEntry(last[0], 1, last[2], last[3],
|
|
543
|
+
last[4], last[5], last[6])
|
|
544
|
+
elif not prev_modname.startswith(package):
|
|
545
|
+
# submodule without parent in list, add dummy entry
|
|
546
|
+
entries.append(IndexEntry(stripped + package, 1, '', '', '', '', ''))
|
|
547
|
+
subtype = 2
|
|
548
|
+
else:
|
|
549
|
+
num_toplevels += 1
|
|
550
|
+
subtype = 0
|
|
551
|
+
|
|
552
|
+
qualifier = _('Deprecated') if deprecated else ''
|
|
553
|
+
entries.append(IndexEntry(stripped + modname, subtype, docname,
|
|
554
|
+
node_id, platforms, qualifier, synopsis))
|
|
555
|
+
prev_modname = modname
|
|
556
|
+
|
|
557
|
+
# apply heuristics when to collapse modindex at page load:
|
|
558
|
+
# only collapse if number of toplevel modules is larger than
|
|
559
|
+
# number of submodules
|
|
560
|
+
collapse = len(modules) - num_toplevels < num_toplevels
|
|
561
|
+
|
|
562
|
+
# sort by first letter
|
|
563
|
+
sorted_content = sorted(content.items())
|
|
564
|
+
|
|
565
|
+
return sorted_content, collapse
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
class PythonDomain(Domain):
|
|
569
|
+
"""Python language domain."""
|
|
570
|
+
|
|
571
|
+
name = 'py'
|
|
572
|
+
label = 'Python'
|
|
573
|
+
object_types: dict[str, ObjType] = {
|
|
574
|
+
'function': ObjType(_('function'), 'func', 'obj'),
|
|
575
|
+
'data': ObjType(_('data'), 'data', 'obj'),
|
|
576
|
+
'class': ObjType(_('class'), 'class', 'exc', 'obj'),
|
|
577
|
+
'exception': ObjType(_('exception'), 'exc', 'class', 'obj'),
|
|
578
|
+
'method': ObjType(_('method'), 'meth', 'obj'),
|
|
579
|
+
'classmethod': ObjType(_('class method'), 'meth', 'obj'),
|
|
580
|
+
'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
|
|
581
|
+
'attribute': ObjType(_('attribute'), 'attr', 'obj'),
|
|
582
|
+
'property': ObjType(_('property'), 'attr', '_prop', 'obj'),
|
|
583
|
+
'module': ObjType(_('module'), 'mod', 'obj'),
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
directives = {
|
|
587
|
+
'function': PyFunction,
|
|
588
|
+
'data': PyVariable,
|
|
589
|
+
'class': PyClasslike,
|
|
590
|
+
'exception': PyClasslike,
|
|
591
|
+
'method': PyMethod,
|
|
592
|
+
'classmethod': PyClassMethod,
|
|
593
|
+
'staticmethod': PyStaticMethod,
|
|
594
|
+
'attribute': PyAttribute,
|
|
595
|
+
'property': PyProperty,
|
|
596
|
+
'module': PyModule,
|
|
597
|
+
'currentmodule': PyCurrentModule,
|
|
598
|
+
'decorator': PyDecoratorFunction,
|
|
599
|
+
'decoratormethod': PyDecoratorMethod,
|
|
600
|
+
}
|
|
601
|
+
roles = {
|
|
602
|
+
'data': PyXRefRole(),
|
|
603
|
+
'exc': PyXRefRole(),
|
|
604
|
+
'func': PyXRefRole(fix_parens=True),
|
|
605
|
+
'class': PyXRefRole(),
|
|
606
|
+
'const': PyXRefRole(),
|
|
607
|
+
'attr': PyXRefRole(),
|
|
608
|
+
'meth': PyXRefRole(fix_parens=True),
|
|
609
|
+
'mod': PyXRefRole(),
|
|
610
|
+
'obj': PyXRefRole(),
|
|
611
|
+
}
|
|
612
|
+
initial_data: dict[str, dict[str, tuple[Any]]] = {
|
|
613
|
+
'objects': {}, # fullname -> docname, objtype
|
|
614
|
+
'modules': {}, # modname -> docname, synopsis, platform, deprecated
|
|
615
|
+
}
|
|
616
|
+
indices = [
|
|
617
|
+
PythonModuleIndex,
|
|
618
|
+
]
|
|
619
|
+
|
|
620
|
+
@property
|
|
621
|
+
def objects(self) -> dict[str, ObjectEntry]:
|
|
622
|
+
return self.data.setdefault('objects', {}) # fullname -> ObjectEntry
|
|
623
|
+
|
|
624
|
+
def note_object(self, name: str, objtype: str, node_id: str,
|
|
625
|
+
aliased: bool = False, location: Any = None) -> None:
|
|
626
|
+
"""Note a python object for cross reference.
|
|
627
|
+
|
|
628
|
+
.. versionadded:: 2.1
|
|
629
|
+
"""
|
|
630
|
+
if name in self.objects:
|
|
631
|
+
other = self.objects[name]
|
|
632
|
+
if other.aliased and aliased is False:
|
|
633
|
+
# The original definition found. Override it!
|
|
634
|
+
pass
|
|
635
|
+
elif other.aliased is False and aliased:
|
|
636
|
+
# The original definition is already registered.
|
|
637
|
+
return
|
|
638
|
+
else:
|
|
639
|
+
# duplicated
|
|
640
|
+
logger.warning(__('duplicate object description of %s, '
|
|
641
|
+
'other instance in %s, use :no-index: for one of them'),
|
|
642
|
+
name, other.docname, location=location)
|
|
643
|
+
self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype, aliased)
|
|
644
|
+
|
|
645
|
+
@property
|
|
646
|
+
def modules(self) -> dict[str, ModuleEntry]:
|
|
647
|
+
return self.data.setdefault('modules', {}) # modname -> ModuleEntry
|
|
648
|
+
|
|
649
|
+
def note_module(self, name: str, node_id: str, synopsis: str,
|
|
650
|
+
platform: str, deprecated: bool) -> None:
|
|
651
|
+
"""Note a python module for cross reference.
|
|
652
|
+
|
|
653
|
+
.. versionadded:: 2.1
|
|
654
|
+
"""
|
|
655
|
+
self.modules[name] = ModuleEntry(self.env.docname, node_id,
|
|
656
|
+
synopsis, platform, deprecated)
|
|
657
|
+
|
|
658
|
+
def clear_doc(self, docname: str) -> None:
|
|
659
|
+
for fullname, obj in list(self.objects.items()):
|
|
660
|
+
if obj.docname == docname:
|
|
661
|
+
del self.objects[fullname]
|
|
662
|
+
for modname, mod in list(self.modules.items()):
|
|
663
|
+
if mod.docname == docname:
|
|
664
|
+
del self.modules[modname]
|
|
665
|
+
|
|
666
|
+
def merge_domaindata(self, docnames: list[str], otherdata: dict[str, Any]) -> None:
|
|
667
|
+
# XXX check duplicates?
|
|
668
|
+
for fullname, obj in otherdata['objects'].items():
|
|
669
|
+
if obj.docname in docnames:
|
|
670
|
+
self.objects[fullname] = obj
|
|
671
|
+
for modname, mod in otherdata['modules'].items():
|
|
672
|
+
if mod.docname in docnames:
|
|
673
|
+
self.modules[modname] = mod
|
|
674
|
+
|
|
675
|
+
def find_obj(self, env: BuildEnvironment, modname: str, classname: str,
|
|
676
|
+
name: str, type: str | None, searchmode: int = 0,
|
|
677
|
+
) -> list[tuple[str, ObjectEntry]]:
|
|
678
|
+
"""Find a Python object for "name", perhaps using the given module
|
|
679
|
+
and/or classname. Returns a list of (name, object entry) tuples.
|
|
680
|
+
"""
|
|
681
|
+
# skip parens
|
|
682
|
+
if name[-2:] == '()':
|
|
683
|
+
name = name[:-2]
|
|
684
|
+
|
|
685
|
+
if not name:
|
|
686
|
+
return []
|
|
687
|
+
|
|
688
|
+
matches: list[tuple[str, ObjectEntry]] = []
|
|
689
|
+
|
|
690
|
+
newname = None
|
|
691
|
+
if searchmode == 1:
|
|
692
|
+
if type is None:
|
|
693
|
+
objtypes: list[str] | None = list(self.object_types)
|
|
694
|
+
else:
|
|
695
|
+
objtypes = self.objtypes_for_role(type)
|
|
696
|
+
if objtypes is not None:
|
|
697
|
+
if modname and classname:
|
|
698
|
+
fullname = modname + '.' + classname + '.' + name
|
|
699
|
+
if fullname in self.objects and self.objects[fullname].objtype in objtypes:
|
|
700
|
+
newname = fullname
|
|
701
|
+
if not newname:
|
|
702
|
+
if modname and modname + '.' + name in self.objects and \
|
|
703
|
+
self.objects[modname + '.' + name].objtype in objtypes:
|
|
704
|
+
newname = modname + '.' + name
|
|
705
|
+
elif name in self.objects and self.objects[name].objtype in objtypes:
|
|
706
|
+
newname = name
|
|
707
|
+
else:
|
|
708
|
+
# "fuzzy" searching mode
|
|
709
|
+
searchname = '.' + name
|
|
710
|
+
matches = [(oname, self.objects[oname]) for oname in self.objects
|
|
711
|
+
if oname.endswith(searchname) and
|
|
712
|
+
self.objects[oname].objtype in objtypes]
|
|
713
|
+
else:
|
|
714
|
+
# NOTE: searching for exact match, object type is not considered
|
|
715
|
+
if name in self.objects:
|
|
716
|
+
newname = name
|
|
717
|
+
elif type == 'mod':
|
|
718
|
+
# only exact matches allowed for modules
|
|
719
|
+
return []
|
|
720
|
+
elif classname and classname + '.' + name in self.objects:
|
|
721
|
+
newname = classname + '.' + name
|
|
722
|
+
elif modname and modname + '.' + name in self.objects:
|
|
723
|
+
newname = modname + '.' + name
|
|
724
|
+
elif modname and classname and \
|
|
725
|
+
modname + '.' + classname + '.' + name in self.objects:
|
|
726
|
+
newname = modname + '.' + classname + '.' + name
|
|
727
|
+
if newname is not None:
|
|
728
|
+
matches.append((newname, self.objects[newname]))
|
|
729
|
+
return matches
|
|
730
|
+
|
|
731
|
+
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
732
|
+
type: str, target: str, node: pending_xref, contnode: Element,
|
|
733
|
+
) -> Element | None:
|
|
734
|
+
modname = node.get('py:module')
|
|
735
|
+
clsname = node.get('py:class')
|
|
736
|
+
searchmode = 1 if node.hasattr('refspecific') else 0
|
|
737
|
+
matches = self.find_obj(env, modname, clsname, target,
|
|
738
|
+
type, searchmode)
|
|
739
|
+
|
|
740
|
+
if not matches and type == 'attr':
|
|
741
|
+
# fallback to meth (for property; Sphinx 2.4.x)
|
|
742
|
+
# this ensures that `:attr:` role continues to refer to the old property entry
|
|
743
|
+
# that defined by ``method`` directive in old reST files.
|
|
744
|
+
matches = self.find_obj(env, modname, clsname, target, 'meth', searchmode)
|
|
745
|
+
if not matches and type == 'meth':
|
|
746
|
+
# fallback to attr (for property)
|
|
747
|
+
# this ensures that `:meth:` in the old reST files can refer to the property
|
|
748
|
+
# entry that defined by ``property`` directive.
|
|
749
|
+
#
|
|
750
|
+
# Note: _prop is a secret role only for internal look-up.
|
|
751
|
+
matches = self.find_obj(env, modname, clsname, target, '_prop', searchmode)
|
|
752
|
+
|
|
753
|
+
if not matches:
|
|
754
|
+
return None
|
|
755
|
+
elif len(matches) > 1:
|
|
756
|
+
canonicals = [m for m in matches if not m[1].aliased]
|
|
757
|
+
if len(canonicals) == 1:
|
|
758
|
+
matches = canonicals
|
|
759
|
+
else:
|
|
760
|
+
logger.warning(__('more than one target found for cross-reference %r: %s'),
|
|
761
|
+
target, ', '.join(match[0] for match in matches),
|
|
762
|
+
type='ref', subtype='python', location=node)
|
|
763
|
+
name, obj = matches[0]
|
|
764
|
+
|
|
765
|
+
if obj[2] == 'module':
|
|
766
|
+
return self._make_module_refnode(builder, fromdocname, name, contnode)
|
|
767
|
+
else:
|
|
768
|
+
# determine the content of the reference by conditions
|
|
769
|
+
content = find_pending_xref_condition(node, 'resolved')
|
|
770
|
+
if content:
|
|
771
|
+
children = content.children
|
|
772
|
+
else:
|
|
773
|
+
# if not found, use contnode
|
|
774
|
+
children = [contnode]
|
|
775
|
+
|
|
776
|
+
return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)
|
|
777
|
+
|
|
778
|
+
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
779
|
+
target: str, node: pending_xref, contnode: Element,
|
|
780
|
+
) -> list[tuple[str, Element]]:
|
|
781
|
+
modname = node.get('py:module')
|
|
782
|
+
clsname = node.get('py:class')
|
|
783
|
+
results: list[tuple[str, Element]] = []
|
|
784
|
+
|
|
785
|
+
# always search in "refspecific" mode with the :any: role
|
|
786
|
+
matches = self.find_obj(env, modname, clsname, target, None, 1)
|
|
787
|
+
multiple_matches = len(matches) > 1
|
|
788
|
+
|
|
789
|
+
for name, obj in matches:
|
|
790
|
+
|
|
791
|
+
if multiple_matches and obj.aliased:
|
|
792
|
+
# Skip duplicated matches
|
|
793
|
+
continue
|
|
794
|
+
|
|
795
|
+
if obj[2] == 'module':
|
|
796
|
+
results.append(('py:mod',
|
|
797
|
+
self._make_module_refnode(builder, fromdocname,
|
|
798
|
+
name, contnode)))
|
|
799
|
+
else:
|
|
800
|
+
# determine the content of the reference by conditions
|
|
801
|
+
content = find_pending_xref_condition(node, 'resolved')
|
|
802
|
+
if content:
|
|
803
|
+
children = content.children
|
|
804
|
+
else:
|
|
805
|
+
# if not found, use contnode
|
|
806
|
+
children = [contnode]
|
|
807
|
+
|
|
808
|
+
role = 'py:' + self.role_for_objtype(obj[2]) # type: ignore[operator]
|
|
809
|
+
results.append((role, make_refnode(builder, fromdocname, obj[0], obj[1],
|
|
810
|
+
children, name)))
|
|
811
|
+
return results
|
|
812
|
+
|
|
813
|
+
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
|
|
814
|
+
contnode: Node) -> Element:
|
|
815
|
+
# get additional info for modules
|
|
816
|
+
module = self.modules[name]
|
|
817
|
+
title = name
|
|
818
|
+
if module.synopsis:
|
|
819
|
+
title += ': ' + module.synopsis
|
|
820
|
+
if module.deprecated:
|
|
821
|
+
title += _(' (deprecated)')
|
|
822
|
+
if module.platform:
|
|
823
|
+
title += ' (' + module.platform + ')'
|
|
824
|
+
return make_refnode(builder, fromdocname, module.docname, module.node_id,
|
|
825
|
+
contnode, title)
|
|
826
|
+
|
|
827
|
+
def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
|
|
828
|
+
for modname, mod in self.modules.items():
|
|
829
|
+
yield (modname, modname, 'module', mod.docname, mod.node_id, 0)
|
|
830
|
+
for refname, obj in self.objects.items():
|
|
831
|
+
if obj.objtype != 'module': # modules are already handled
|
|
832
|
+
if obj.aliased:
|
|
833
|
+
# aliased names are not full-text searchable.
|
|
834
|
+
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, -1)
|
|
835
|
+
else:
|
|
836
|
+
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
|
|
837
|
+
|
|
838
|
+
def get_full_qualified_name(self, node: Element) -> str | None:
|
|
839
|
+
modname = node.get('py:module')
|
|
840
|
+
clsname = node.get('py:class')
|
|
841
|
+
target = node.get('reftarget')
|
|
842
|
+
if target is None:
|
|
843
|
+
return None
|
|
844
|
+
else:
|
|
845
|
+
return '.'.join(filter(None, [modname, clsname, target]))
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def builtin_resolver(app: Sphinx, env: BuildEnvironment,
|
|
849
|
+
node: pending_xref, contnode: Element) -> Element | None:
|
|
850
|
+
"""Do not emit nitpicky warnings for built-in types."""
|
|
851
|
+
def istyping(s: str) -> bool:
|
|
852
|
+
if s.startswith('typing.'):
|
|
853
|
+
s = s.split('.', 1)[1]
|
|
854
|
+
|
|
855
|
+
return s in typing.__all__
|
|
856
|
+
|
|
857
|
+
if node.get('refdomain') != 'py':
|
|
858
|
+
return None
|
|
859
|
+
elif node.get('reftype') in ('class', 'obj') and node.get('reftarget') == 'None':
|
|
860
|
+
return contnode
|
|
861
|
+
elif node.get('reftype') in ('class', 'obj', 'exc'):
|
|
862
|
+
reftarget = node.get('reftarget')
|
|
863
|
+
if inspect.isclass(getattr(builtins, reftarget, None)):
|
|
864
|
+
# built-in class
|
|
865
|
+
return contnode
|
|
866
|
+
if istyping(reftarget):
|
|
867
|
+
# typing class
|
|
868
|
+
return contnode
|
|
869
|
+
|
|
870
|
+
return None
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
def setup(app: Sphinx) -> ExtensionMetadata:
|
|
874
|
+
app.setup_extension('sphinx.directives')
|
|
875
|
+
|
|
876
|
+
app.add_domain(PythonDomain)
|
|
877
|
+
app.add_config_value('python_use_unqualified_type_names', False, 'env')
|
|
878
|
+
app.add_config_value(
|
|
879
|
+
'python_maximum_signature_line_length', None, 'env', {int, type(None)},
|
|
880
|
+
)
|
|
881
|
+
app.add_config_value('python_display_short_literal_types', False, 'env')
|
|
882
|
+
app.connect('object-description-transform', filter_meta_fields)
|
|
883
|
+
app.connect('missing-reference', builtin_resolver, priority=900)
|
|
884
|
+
|
|
885
|
+
return {
|
|
886
|
+
'version': 'builtin',
|
|
887
|
+
'env_version': 4,
|
|
888
|
+
'parallel_read_safe': True,
|
|
889
|
+
'parallel_write_safe': True,
|
|
890
|
+
}
|