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/domains/python.py
DELETED
|
@@ -1,1769 +0,0 @@
|
|
|
1
|
-
"""The Python domain."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import ast
|
|
6
|
-
import builtins
|
|
7
|
-
import contextlib
|
|
8
|
-
import inspect
|
|
9
|
-
import re
|
|
10
|
-
import token
|
|
11
|
-
import typing
|
|
12
|
-
from inspect import Parameter
|
|
13
|
-
from typing import TYPE_CHECKING, Any, NamedTuple, cast
|
|
14
|
-
|
|
15
|
-
from docutils import nodes
|
|
16
|
-
from docutils.parsers.rst import directives
|
|
17
|
-
|
|
18
|
-
from sphinx import addnodes
|
|
19
|
-
from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
|
|
20
|
-
from sphinx.directives import ObjectDescription
|
|
21
|
-
from sphinx.domains import Domain, Index, IndexEntry, ObjType
|
|
22
|
-
from sphinx.locale import _, __
|
|
23
|
-
from sphinx.pycode.parser import Token, TokenProcessor
|
|
24
|
-
from sphinx.roles import XRefRole
|
|
25
|
-
from sphinx.util import logging
|
|
26
|
-
from sphinx.util.docfields import Field, GroupedField, TypedField
|
|
27
|
-
from sphinx.util.docutils import SphinxDirective
|
|
28
|
-
from sphinx.util.inspect import signature_from_str
|
|
29
|
-
from sphinx.util.nodes import (
|
|
30
|
-
find_pending_xref_condition,
|
|
31
|
-
make_id,
|
|
32
|
-
make_refnode,
|
|
33
|
-
nested_parse_with_titles,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
if TYPE_CHECKING:
|
|
37
|
-
from collections.abc import Iterable, Iterator
|
|
38
|
-
|
|
39
|
-
from docutils.nodes import Element, Node
|
|
40
|
-
from docutils.parsers.rst.states import Inliner
|
|
41
|
-
|
|
42
|
-
from sphinx.application import Sphinx
|
|
43
|
-
from sphinx.builders import Builder
|
|
44
|
-
from sphinx.environment import BuildEnvironment
|
|
45
|
-
from sphinx.util.typing import OptionSpec, TextlikeNode
|
|
46
|
-
|
|
47
|
-
logger = logging.getLogger(__name__)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# REs for Python signatures
|
|
51
|
-
py_sig_re = re.compile(
|
|
52
|
-
r'''^ ([\w.]*\.)? # class name(s)
|
|
53
|
-
(\w+) \s* # thing name
|
|
54
|
-
(?: \[\s*(.*)\s*])? # optional: type parameters list
|
|
55
|
-
(?: \(\s*(.*)\s*\) # optional: arguments
|
|
56
|
-
(?:\s* -> \s* (.*))? # return annotation
|
|
57
|
-
)? $ # and nothing more
|
|
58
|
-
''', re.VERBOSE)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
pairindextypes = {
|
|
62
|
-
'module': 'module',
|
|
63
|
-
'keyword': 'keyword',
|
|
64
|
-
'operator': 'operator',
|
|
65
|
-
'object': 'object',
|
|
66
|
-
'exception': 'exception',
|
|
67
|
-
'statement': 'statement',
|
|
68
|
-
'builtin': 'built-in function',
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class ObjectEntry(NamedTuple):
|
|
73
|
-
docname: str
|
|
74
|
-
node_id: str
|
|
75
|
-
objtype: str
|
|
76
|
-
aliased: bool
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class ModuleEntry(NamedTuple):
|
|
80
|
-
docname: str
|
|
81
|
-
node_id: str
|
|
82
|
-
synopsis: str
|
|
83
|
-
platform: str
|
|
84
|
-
deprecated: bool
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def parse_reftarget(reftarget: str, suppress_prefix: bool = False,
|
|
88
|
-
) -> tuple[str, str, str, bool]:
|
|
89
|
-
"""Parse a type string and return (reftype, reftarget, title, refspecific flag)"""
|
|
90
|
-
refspecific = False
|
|
91
|
-
if reftarget.startswith('.'):
|
|
92
|
-
reftarget = reftarget[1:]
|
|
93
|
-
title = reftarget
|
|
94
|
-
refspecific = True
|
|
95
|
-
elif reftarget.startswith('~'):
|
|
96
|
-
reftarget = reftarget[1:]
|
|
97
|
-
title = reftarget.split('.')[-1]
|
|
98
|
-
elif suppress_prefix:
|
|
99
|
-
title = reftarget.split('.')[-1]
|
|
100
|
-
elif reftarget.startswith('typing.'):
|
|
101
|
-
title = reftarget[7:]
|
|
102
|
-
else:
|
|
103
|
-
title = reftarget
|
|
104
|
-
|
|
105
|
-
if reftarget == 'None' or reftarget.startswith('typing.'):
|
|
106
|
-
# typing module provides non-class types. Obj reference is good to refer them.
|
|
107
|
-
reftype = 'obj'
|
|
108
|
-
else:
|
|
109
|
-
reftype = 'class'
|
|
110
|
-
|
|
111
|
-
return reftype, reftarget, title, refspecific
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def type_to_xref(target: str, env: BuildEnvironment, *,
|
|
115
|
-
suppress_prefix: bool = False) -> addnodes.pending_xref:
|
|
116
|
-
"""Convert a type string to a cross reference node."""
|
|
117
|
-
if env:
|
|
118
|
-
kwargs = {'py:module': env.ref_context.get('py:module'),
|
|
119
|
-
'py:class': env.ref_context.get('py:class')}
|
|
120
|
-
else:
|
|
121
|
-
kwargs = {}
|
|
122
|
-
|
|
123
|
-
reftype, target, title, refspecific = parse_reftarget(target, suppress_prefix)
|
|
124
|
-
|
|
125
|
-
if env.config.python_use_unqualified_type_names:
|
|
126
|
-
# Note: It would be better to use qualname to describe the object to support support
|
|
127
|
-
# nested classes. But python domain can't access the real python object because this
|
|
128
|
-
# module should work not-dynamically.
|
|
129
|
-
shortname = title.split('.')[-1]
|
|
130
|
-
contnodes: list[Node] = [pending_xref_condition('', shortname, condition='resolved'),
|
|
131
|
-
pending_xref_condition('', title, condition='*')]
|
|
132
|
-
else:
|
|
133
|
-
contnodes = [nodes.Text(title)]
|
|
134
|
-
|
|
135
|
-
return pending_xref('', *contnodes,
|
|
136
|
-
refdomain='py', reftype=reftype, reftarget=target,
|
|
137
|
-
refspecific=refspecific, **kwargs)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
|
|
141
|
-
"""Parse type annotation."""
|
|
142
|
-
short_literals = env.config.python_display_short_literal_types
|
|
143
|
-
|
|
144
|
-
def unparse(node: ast.AST) -> list[Node]:
|
|
145
|
-
if isinstance(node, ast.Attribute):
|
|
146
|
-
return [nodes.Text(f"{unparse(node.value)[0]}.{node.attr}")]
|
|
147
|
-
if isinstance(node, ast.BinOp):
|
|
148
|
-
result: list[Node] = unparse(node.left)
|
|
149
|
-
result.extend(unparse(node.op))
|
|
150
|
-
result.extend(unparse(node.right))
|
|
151
|
-
return result
|
|
152
|
-
if isinstance(node, ast.BitOr):
|
|
153
|
-
return [addnodes.desc_sig_space(),
|
|
154
|
-
addnodes.desc_sig_punctuation('', '|'),
|
|
155
|
-
addnodes.desc_sig_space()]
|
|
156
|
-
if isinstance(node, ast.Constant):
|
|
157
|
-
if node.value is Ellipsis:
|
|
158
|
-
return [addnodes.desc_sig_punctuation('', "...")]
|
|
159
|
-
if isinstance(node.value, bool):
|
|
160
|
-
return [addnodes.desc_sig_keyword('', repr(node.value))]
|
|
161
|
-
if isinstance(node.value, int):
|
|
162
|
-
return [addnodes.desc_sig_literal_number('', repr(node.value))]
|
|
163
|
-
if isinstance(node.value, str):
|
|
164
|
-
return [addnodes.desc_sig_literal_string('', repr(node.value))]
|
|
165
|
-
else:
|
|
166
|
-
# handles None, which is further handled by type_to_xref later
|
|
167
|
-
# and fallback for other types that should be converted
|
|
168
|
-
return [nodes.Text(repr(node.value))]
|
|
169
|
-
if isinstance(node, ast.Expr):
|
|
170
|
-
return unparse(node.value)
|
|
171
|
-
if isinstance(node, ast.Invert):
|
|
172
|
-
return [addnodes.desc_sig_punctuation('', '~')]
|
|
173
|
-
if isinstance(node, ast.List):
|
|
174
|
-
result = [addnodes.desc_sig_punctuation('', '[')]
|
|
175
|
-
if node.elts:
|
|
176
|
-
# check if there are elements in node.elts to only pop the
|
|
177
|
-
# last element of result if the for-loop was run at least
|
|
178
|
-
# once
|
|
179
|
-
for elem in node.elts:
|
|
180
|
-
result.extend(unparse(elem))
|
|
181
|
-
result.append(addnodes.desc_sig_punctuation('', ','))
|
|
182
|
-
result.append(addnodes.desc_sig_space())
|
|
183
|
-
result.pop()
|
|
184
|
-
result.pop()
|
|
185
|
-
result.append(addnodes.desc_sig_punctuation('', ']'))
|
|
186
|
-
return result
|
|
187
|
-
if isinstance(node, ast.Module):
|
|
188
|
-
return sum((unparse(e) for e in node.body), [])
|
|
189
|
-
if isinstance(node, ast.Name):
|
|
190
|
-
return [nodes.Text(node.id)]
|
|
191
|
-
if isinstance(node, ast.Subscript):
|
|
192
|
-
if getattr(node.value, 'id', '') in {'Optional', 'Union'}:
|
|
193
|
-
return _unparse_pep_604_annotation(node)
|
|
194
|
-
if short_literals and getattr(node.value, 'id', '') == 'Literal':
|
|
195
|
-
return _unparse_pep_604_annotation(node)
|
|
196
|
-
result = unparse(node.value)
|
|
197
|
-
result.append(addnodes.desc_sig_punctuation('', '['))
|
|
198
|
-
result.extend(unparse(node.slice))
|
|
199
|
-
result.append(addnodes.desc_sig_punctuation('', ']'))
|
|
200
|
-
|
|
201
|
-
# Wrap the Text nodes inside brackets by literal node if the subscript is a Literal
|
|
202
|
-
if result[0] in ('Literal', 'typing.Literal'):
|
|
203
|
-
for i, subnode in enumerate(result[1:], start=1):
|
|
204
|
-
if isinstance(subnode, nodes.Text):
|
|
205
|
-
result[i] = nodes.literal('', '', subnode)
|
|
206
|
-
return result
|
|
207
|
-
if isinstance(node, ast.UnaryOp):
|
|
208
|
-
return unparse(node.op) + unparse(node.operand)
|
|
209
|
-
if isinstance(node, ast.Tuple):
|
|
210
|
-
if node.elts:
|
|
211
|
-
result = []
|
|
212
|
-
for elem in node.elts:
|
|
213
|
-
result.extend(unparse(elem))
|
|
214
|
-
result.append(addnodes.desc_sig_punctuation('', ','))
|
|
215
|
-
result.append(addnodes.desc_sig_space())
|
|
216
|
-
result.pop()
|
|
217
|
-
result.pop()
|
|
218
|
-
else:
|
|
219
|
-
result = [addnodes.desc_sig_punctuation('', '('),
|
|
220
|
-
addnodes.desc_sig_punctuation('', ')')]
|
|
221
|
-
|
|
222
|
-
return result
|
|
223
|
-
raise SyntaxError # unsupported syntax
|
|
224
|
-
|
|
225
|
-
def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
|
|
226
|
-
subscript = node.slice
|
|
227
|
-
|
|
228
|
-
flattened: list[Node] = []
|
|
229
|
-
if isinstance(subscript, ast.Tuple):
|
|
230
|
-
flattened.extend(unparse(subscript.elts[0]))
|
|
231
|
-
for elt in subscript.elts[1:]:
|
|
232
|
-
flattened.extend(unparse(ast.BitOr()))
|
|
233
|
-
flattened.extend(unparse(elt))
|
|
234
|
-
else:
|
|
235
|
-
# e.g. a Union[] inside an Optional[]
|
|
236
|
-
flattened.extend(unparse(subscript))
|
|
237
|
-
|
|
238
|
-
if getattr(node.value, 'id', '') == 'Optional':
|
|
239
|
-
flattened.extend(unparse(ast.BitOr()))
|
|
240
|
-
flattened.append(nodes.Text('None'))
|
|
241
|
-
|
|
242
|
-
return flattened
|
|
243
|
-
|
|
244
|
-
try:
|
|
245
|
-
tree = ast.parse(annotation, type_comments=True)
|
|
246
|
-
result: list[Node] = []
|
|
247
|
-
for node in unparse(tree):
|
|
248
|
-
if isinstance(node, nodes.literal):
|
|
249
|
-
result.append(node[0])
|
|
250
|
-
elif isinstance(node, nodes.Text) and node.strip():
|
|
251
|
-
if (result and isinstance(result[-1], addnodes.desc_sig_punctuation) and
|
|
252
|
-
result[-1].astext() == '~'):
|
|
253
|
-
result.pop()
|
|
254
|
-
result.append(type_to_xref(str(node), env, suppress_prefix=True))
|
|
255
|
-
else:
|
|
256
|
-
result.append(type_to_xref(str(node), env))
|
|
257
|
-
else:
|
|
258
|
-
result.append(node)
|
|
259
|
-
return result
|
|
260
|
-
except SyntaxError:
|
|
261
|
-
return [type_to_xref(annotation, env)]
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
class _TypeParameterListParser(TokenProcessor):
|
|
265
|
-
def __init__(self, sig: str) -> None:
|
|
266
|
-
signature = sig.replace('\n', '').strip()
|
|
267
|
-
super().__init__([signature])
|
|
268
|
-
# Each item is a tuple (name, kind, default, annotation) mimicking
|
|
269
|
-
# ``inspect.Parameter`` to allow default values on VAR_POSITIONAL
|
|
270
|
-
# or VAR_KEYWORD parameters.
|
|
271
|
-
self.type_params: list[tuple[str, int, Any, Any]] = []
|
|
272
|
-
|
|
273
|
-
def fetch_type_param_spec(self) -> list[Token]:
|
|
274
|
-
tokens = []
|
|
275
|
-
while current := self.fetch_token():
|
|
276
|
-
tokens.append(current)
|
|
277
|
-
for ldelim, rdelim in ('(', ')'), ('{', '}'), ('[', ']'):
|
|
278
|
-
if current == [token.OP, ldelim]:
|
|
279
|
-
tokens += self.fetch_until([token.OP, rdelim])
|
|
280
|
-
break
|
|
281
|
-
else:
|
|
282
|
-
if current == token.INDENT:
|
|
283
|
-
tokens += self.fetch_until(token.DEDENT)
|
|
284
|
-
elif current.match(
|
|
285
|
-
[token.OP, ':'], [token.OP, '='], [token.OP, ',']):
|
|
286
|
-
tokens.pop()
|
|
287
|
-
break
|
|
288
|
-
return tokens
|
|
289
|
-
|
|
290
|
-
def parse(self) -> None:
|
|
291
|
-
while current := self.fetch_token():
|
|
292
|
-
if current == token.NAME:
|
|
293
|
-
tp_name = current.value.strip()
|
|
294
|
-
if self.previous and self.previous.match([token.OP, '*'], [token.OP, '**']):
|
|
295
|
-
if self.previous == [token.OP, '*']:
|
|
296
|
-
tp_kind = Parameter.VAR_POSITIONAL
|
|
297
|
-
else:
|
|
298
|
-
tp_kind = Parameter.VAR_KEYWORD # type: ignore[assignment]
|
|
299
|
-
else:
|
|
300
|
-
tp_kind = Parameter.POSITIONAL_OR_KEYWORD # type: ignore[assignment]
|
|
301
|
-
|
|
302
|
-
tp_ann: Any = Parameter.empty
|
|
303
|
-
tp_default: Any = Parameter.empty
|
|
304
|
-
|
|
305
|
-
current = self.fetch_token()
|
|
306
|
-
if current and current.match([token.OP, ':'], [token.OP, '=']):
|
|
307
|
-
if current == [token.OP, ':']:
|
|
308
|
-
tokens = self.fetch_type_param_spec()
|
|
309
|
-
tp_ann = self._build_identifier(tokens)
|
|
310
|
-
|
|
311
|
-
if self.current and self.current == [token.OP, '=']:
|
|
312
|
-
tokens = self.fetch_type_param_spec()
|
|
313
|
-
tp_default = self._build_identifier(tokens)
|
|
314
|
-
|
|
315
|
-
if tp_kind != Parameter.POSITIONAL_OR_KEYWORD and tp_ann != Parameter.empty:
|
|
316
|
-
msg = ('type parameter bound or constraint is not allowed '
|
|
317
|
-
f'for {tp_kind.description} parameters')
|
|
318
|
-
raise SyntaxError(msg)
|
|
319
|
-
|
|
320
|
-
type_param = (tp_name, tp_kind, tp_default, tp_ann)
|
|
321
|
-
self.type_params.append(type_param)
|
|
322
|
-
|
|
323
|
-
def _build_identifier(self, tokens: list[Token]) -> str:
|
|
324
|
-
from itertools import chain, tee
|
|
325
|
-
|
|
326
|
-
def pairwise(iterable):
|
|
327
|
-
a, b = tee(iterable)
|
|
328
|
-
next(b, None)
|
|
329
|
-
return zip(a, b)
|
|
330
|
-
|
|
331
|
-
def triplewise(iterable):
|
|
332
|
-
for (a, _z), (b, c) in pairwise(pairwise(iterable)):
|
|
333
|
-
yield a, b, c
|
|
334
|
-
|
|
335
|
-
idents: list[str] = []
|
|
336
|
-
tokens: Iterable[Token] = iter(tokens) # type: ignore[no-redef]
|
|
337
|
-
# do not format opening brackets
|
|
338
|
-
for tok in tokens:
|
|
339
|
-
if not tok.match([token.OP, '('], [token.OP, '['], [token.OP, '{']):
|
|
340
|
-
# check if the first non-delimiter character is an unpack operator
|
|
341
|
-
is_unpack_operator = tok.match([token.OP, '*'], [token.OP, ['**']])
|
|
342
|
-
idents.append(self._pformat_token(tok, native=is_unpack_operator))
|
|
343
|
-
break
|
|
344
|
-
idents.append(tok.value)
|
|
345
|
-
|
|
346
|
-
# check the remaining tokens
|
|
347
|
-
stop = Token(token.ENDMARKER, '', (-1, -1), (-1, -1), '<sentinel>')
|
|
348
|
-
is_unpack_operator = False
|
|
349
|
-
for tok, op, after in triplewise(chain(tokens, [stop, stop])):
|
|
350
|
-
ident = self._pformat_token(tok, native=is_unpack_operator)
|
|
351
|
-
idents.append(ident)
|
|
352
|
-
# determine if the next token is an unpack operator depending
|
|
353
|
-
# on the left and right hand side of the operator symbol
|
|
354
|
-
is_unpack_operator = (
|
|
355
|
-
op.match([token.OP, '*'], [token.OP, '**']) and not (
|
|
356
|
-
tok.match(token.NAME, token.NUMBER, token.STRING,
|
|
357
|
-
[token.OP, ')'], [token.OP, ']'], [token.OP, '}'])
|
|
358
|
-
and after.match(token.NAME, token.NUMBER, token.STRING,
|
|
359
|
-
[token.OP, '('], [token.OP, '['], [token.OP, '{'])
|
|
360
|
-
)
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
return ''.join(idents).strip()
|
|
364
|
-
|
|
365
|
-
def _pformat_token(self, tok: Token, native: bool = False) -> str:
|
|
366
|
-
if native:
|
|
367
|
-
return tok.value
|
|
368
|
-
|
|
369
|
-
if tok.match(token.NEWLINE, token.ENDMARKER):
|
|
370
|
-
return ''
|
|
371
|
-
|
|
372
|
-
if tok.match([token.OP, ':'], [token.OP, ','], [token.OP, '#']):
|
|
373
|
-
return f'{tok.value} '
|
|
374
|
-
|
|
375
|
-
# Arithmetic operators are allowed because PEP 695 specifies the
|
|
376
|
-
# default type parameter to be *any* expression (so "T1 << T2" is
|
|
377
|
-
# allowed if it makes sense). The caller is responsible to ensure
|
|
378
|
-
# that a multiplication operator ("*") is not to be confused with
|
|
379
|
-
# an unpack operator (which will not be surrounded by spaces).
|
|
380
|
-
#
|
|
381
|
-
# The operators are ordered according to how likely they are to
|
|
382
|
-
# be used and for (possible) future implementations (e.g., "&" for
|
|
383
|
-
# an intersection type).
|
|
384
|
-
if tok.match(
|
|
385
|
-
# Most likely operators to appear
|
|
386
|
-
[token.OP, '='], [token.OP, '|'],
|
|
387
|
-
# Type composition (future compatibility)
|
|
388
|
-
[token.OP, '&'], [token.OP, '^'], [token.OP, '<'], [token.OP, '>'],
|
|
389
|
-
# Unlikely type composition
|
|
390
|
-
[token.OP, '+'], [token.OP, '-'], [token.OP, '*'], [token.OP, '**'],
|
|
391
|
-
# Unlikely operators but included for completeness
|
|
392
|
-
[token.OP, '@'], [token.OP, '/'], [token.OP, '//'], [token.OP, '%'],
|
|
393
|
-
[token.OP, '<<'], [token.OP, '>>'], [token.OP, '>>>'],
|
|
394
|
-
[token.OP, '<='], [token.OP, '>='], [token.OP, '=='], [token.OP, '!='],
|
|
395
|
-
):
|
|
396
|
-
return f' {tok.value} '
|
|
397
|
-
|
|
398
|
-
return tok.value
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
def _parse_type_list(
|
|
402
|
-
tp_list: str, env: BuildEnvironment,
|
|
403
|
-
multi_line_parameter_list: bool = False,
|
|
404
|
-
) -> addnodes.desc_type_parameter_list:
|
|
405
|
-
"""Parse a list of type parameters according to PEP 695."""
|
|
406
|
-
type_params = addnodes.desc_type_parameter_list(tp_list)
|
|
407
|
-
type_params['multi_line_parameter_list'] = multi_line_parameter_list
|
|
408
|
-
# formal parameter names are interpreted as type parameter names and
|
|
409
|
-
# type annotations are interpreted as type parameter bound or constraints
|
|
410
|
-
parser = _TypeParameterListParser(tp_list)
|
|
411
|
-
parser.parse()
|
|
412
|
-
for (tp_name, tp_kind, tp_default, tp_ann) in parser.type_params:
|
|
413
|
-
# no positional-only or keyword-only allowed in a type parameters list
|
|
414
|
-
if tp_kind in {Parameter.POSITIONAL_ONLY, Parameter.KEYWORD_ONLY}:
|
|
415
|
-
msg = ('positional-only or keyword-only parameters '
|
|
416
|
-
'are prohibited in type parameter lists')
|
|
417
|
-
raise SyntaxError(msg)
|
|
418
|
-
|
|
419
|
-
node = addnodes.desc_type_parameter()
|
|
420
|
-
if tp_kind == Parameter.VAR_POSITIONAL:
|
|
421
|
-
node += addnodes.desc_sig_operator('', '*')
|
|
422
|
-
elif tp_kind == Parameter.VAR_KEYWORD:
|
|
423
|
-
node += addnodes.desc_sig_operator('', '**')
|
|
424
|
-
node += addnodes.desc_sig_name('', tp_name)
|
|
425
|
-
|
|
426
|
-
if tp_ann is not Parameter.empty:
|
|
427
|
-
annotation = _parse_annotation(tp_ann, env)
|
|
428
|
-
if not annotation:
|
|
429
|
-
continue
|
|
430
|
-
|
|
431
|
-
node += addnodes.desc_sig_punctuation('', ':')
|
|
432
|
-
node += addnodes.desc_sig_space()
|
|
433
|
-
|
|
434
|
-
type_ann_expr = addnodes.desc_sig_name('', '',
|
|
435
|
-
*annotation) # type: ignore[arg-type]
|
|
436
|
-
# a type bound is ``T: U`` whereas type constraints
|
|
437
|
-
# must be enclosed with parentheses. ``T: (U, V)``
|
|
438
|
-
if tp_ann.startswith('(') and tp_ann.endswith(')'):
|
|
439
|
-
type_ann_text = type_ann_expr.astext()
|
|
440
|
-
if type_ann_text.startswith('(') and type_ann_text.endswith(')'):
|
|
441
|
-
node += type_ann_expr
|
|
442
|
-
else:
|
|
443
|
-
# surrounding braces are lost when using _parse_annotation()
|
|
444
|
-
node += addnodes.desc_sig_punctuation('', '(')
|
|
445
|
-
node += type_ann_expr # type constraint
|
|
446
|
-
node += addnodes.desc_sig_punctuation('', ')')
|
|
447
|
-
else:
|
|
448
|
-
node += type_ann_expr # type bound
|
|
449
|
-
|
|
450
|
-
if tp_default is not Parameter.empty:
|
|
451
|
-
# Always surround '=' with spaces, even if there is no annotation
|
|
452
|
-
node += addnodes.desc_sig_space()
|
|
453
|
-
node += addnodes.desc_sig_operator('', '=')
|
|
454
|
-
node += addnodes.desc_sig_space()
|
|
455
|
-
node += nodes.inline('', tp_default,
|
|
456
|
-
classes=['default_value'],
|
|
457
|
-
support_smartquotes=False)
|
|
458
|
-
|
|
459
|
-
type_params += node
|
|
460
|
-
return type_params
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
def _parse_arglist(
|
|
464
|
-
arglist: str, env: BuildEnvironment, multi_line_parameter_list: bool = False,
|
|
465
|
-
) -> addnodes.desc_parameterlist:
|
|
466
|
-
"""Parse a list of arguments using AST parser"""
|
|
467
|
-
params = addnodes.desc_parameterlist(arglist)
|
|
468
|
-
params['multi_line_parameter_list'] = multi_line_parameter_list
|
|
469
|
-
sig = signature_from_str('(%s)' % arglist)
|
|
470
|
-
last_kind = None
|
|
471
|
-
for param in sig.parameters.values():
|
|
472
|
-
if param.kind != param.POSITIONAL_ONLY and last_kind == param.POSITIONAL_ONLY:
|
|
473
|
-
# PEP-570: Separator for Positional Only Parameter: /
|
|
474
|
-
params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
|
|
475
|
-
if param.kind == param.KEYWORD_ONLY and last_kind in (param.POSITIONAL_OR_KEYWORD,
|
|
476
|
-
param.POSITIONAL_ONLY,
|
|
477
|
-
None):
|
|
478
|
-
# PEP-3102: Separator for Keyword Only Parameter: *
|
|
479
|
-
params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '*'))
|
|
480
|
-
|
|
481
|
-
node = addnodes.desc_parameter()
|
|
482
|
-
if param.kind == param.VAR_POSITIONAL:
|
|
483
|
-
node += addnodes.desc_sig_operator('', '*')
|
|
484
|
-
node += addnodes.desc_sig_name('', param.name)
|
|
485
|
-
elif param.kind == param.VAR_KEYWORD:
|
|
486
|
-
node += addnodes.desc_sig_operator('', '**')
|
|
487
|
-
node += addnodes.desc_sig_name('', param.name)
|
|
488
|
-
else:
|
|
489
|
-
node += addnodes.desc_sig_name('', param.name)
|
|
490
|
-
|
|
491
|
-
if param.annotation is not param.empty:
|
|
492
|
-
children = _parse_annotation(param.annotation, env)
|
|
493
|
-
node += addnodes.desc_sig_punctuation('', ':')
|
|
494
|
-
node += addnodes.desc_sig_space()
|
|
495
|
-
node += addnodes.desc_sig_name('', '', *children) # type: ignore[arg-type]
|
|
496
|
-
if param.default is not param.empty:
|
|
497
|
-
if param.annotation is not param.empty:
|
|
498
|
-
node += addnodes.desc_sig_space()
|
|
499
|
-
node += addnodes.desc_sig_operator('', '=')
|
|
500
|
-
node += addnodes.desc_sig_space()
|
|
501
|
-
else:
|
|
502
|
-
node += addnodes.desc_sig_operator('', '=')
|
|
503
|
-
node += nodes.inline('', param.default, classes=['default_value'],
|
|
504
|
-
support_smartquotes=False)
|
|
505
|
-
|
|
506
|
-
params += node
|
|
507
|
-
last_kind = param.kind
|
|
508
|
-
|
|
509
|
-
if last_kind == Parameter.POSITIONAL_ONLY:
|
|
510
|
-
# PEP-570: Separator for Positional Only Parameter: /
|
|
511
|
-
params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
|
|
512
|
-
|
|
513
|
-
return params
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
def _pseudo_parse_arglist(
|
|
517
|
-
signode: desc_signature, arglist: str, multi_line_parameter_list: bool = False,
|
|
518
|
-
) -> None:
|
|
519
|
-
""""Parse" a list of arguments separated by commas.
|
|
520
|
-
|
|
521
|
-
Arguments can have "optional" annotations given by enclosing them in
|
|
522
|
-
brackets. Currently, this will split at any comma, even if it's inside a
|
|
523
|
-
string literal (e.g. default argument value).
|
|
524
|
-
"""
|
|
525
|
-
paramlist = addnodes.desc_parameterlist()
|
|
526
|
-
paramlist['multi_line_parameter_list'] = multi_line_parameter_list
|
|
527
|
-
stack: list[Element] = [paramlist]
|
|
528
|
-
try:
|
|
529
|
-
for argument in arglist.split(','):
|
|
530
|
-
argument = argument.strip()
|
|
531
|
-
ends_open = ends_close = 0
|
|
532
|
-
while argument.startswith('['):
|
|
533
|
-
stack.append(addnodes.desc_optional())
|
|
534
|
-
stack[-2] += stack[-1]
|
|
535
|
-
argument = argument[1:].strip()
|
|
536
|
-
while argument.startswith(']'):
|
|
537
|
-
stack.pop()
|
|
538
|
-
argument = argument[1:].strip()
|
|
539
|
-
while argument.endswith(']') and not argument.endswith('[]'):
|
|
540
|
-
ends_close += 1
|
|
541
|
-
argument = argument[:-1].strip()
|
|
542
|
-
while argument.endswith('['):
|
|
543
|
-
ends_open += 1
|
|
544
|
-
argument = argument[:-1].strip()
|
|
545
|
-
if argument:
|
|
546
|
-
stack[-1] += addnodes.desc_parameter(
|
|
547
|
-
'', '', addnodes.desc_sig_name(argument, argument))
|
|
548
|
-
while ends_open:
|
|
549
|
-
stack.append(addnodes.desc_optional())
|
|
550
|
-
stack[-2] += stack[-1]
|
|
551
|
-
ends_open -= 1
|
|
552
|
-
while ends_close:
|
|
553
|
-
stack.pop()
|
|
554
|
-
ends_close -= 1
|
|
555
|
-
if len(stack) != 1:
|
|
556
|
-
raise IndexError
|
|
557
|
-
except IndexError:
|
|
558
|
-
# if there are too few or too many elements on the stack, just give up
|
|
559
|
-
# and treat the whole argument list as one argument, discarding the
|
|
560
|
-
# already partially populated paramlist node
|
|
561
|
-
paramlist = addnodes.desc_parameterlist()
|
|
562
|
-
paramlist += addnodes.desc_parameter(arglist, arglist)
|
|
563
|
-
signode += paramlist
|
|
564
|
-
else:
|
|
565
|
-
signode += paramlist
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
# This override allows our inline type specifiers to behave like :class: link
|
|
569
|
-
# when it comes to handling "." and "~" prefixes.
|
|
570
|
-
class PyXrefMixin:
|
|
571
|
-
def make_xref(
|
|
572
|
-
self,
|
|
573
|
-
rolename: str,
|
|
574
|
-
domain: str,
|
|
575
|
-
target: str,
|
|
576
|
-
innernode: type[TextlikeNode] = nodes.emphasis,
|
|
577
|
-
contnode: Node | None = None,
|
|
578
|
-
env: BuildEnvironment | None = None,
|
|
579
|
-
inliner: Inliner | None = None,
|
|
580
|
-
location: Node | None = None,
|
|
581
|
-
) -> Node:
|
|
582
|
-
# we use inliner=None to make sure we get the old behaviour with a single
|
|
583
|
-
# pending_xref node
|
|
584
|
-
result = super().make_xref(rolename, domain, target, # type: ignore[misc]
|
|
585
|
-
innernode, contnode,
|
|
586
|
-
env, inliner=None, location=None)
|
|
587
|
-
if isinstance(result, pending_xref):
|
|
588
|
-
assert env is not None
|
|
589
|
-
result['refspecific'] = True
|
|
590
|
-
result['py:module'] = env.ref_context.get('py:module')
|
|
591
|
-
result['py:class'] = env.ref_context.get('py:class')
|
|
592
|
-
|
|
593
|
-
reftype, reftarget, reftitle, _ = parse_reftarget(target)
|
|
594
|
-
if reftarget != reftitle:
|
|
595
|
-
result['reftype'] = reftype
|
|
596
|
-
result['reftarget'] = reftarget
|
|
597
|
-
|
|
598
|
-
result.clear()
|
|
599
|
-
result += innernode(reftitle, reftitle)
|
|
600
|
-
elif env.config.python_use_unqualified_type_names:
|
|
601
|
-
children = result.children
|
|
602
|
-
result.clear()
|
|
603
|
-
|
|
604
|
-
shortname = target.split('.')[-1]
|
|
605
|
-
textnode = innernode('', shortname)
|
|
606
|
-
contnodes = [pending_xref_condition('', '', textnode, condition='resolved'),
|
|
607
|
-
pending_xref_condition('', '', *children, condition='*')]
|
|
608
|
-
result.extend(contnodes)
|
|
609
|
-
|
|
610
|
-
return result
|
|
611
|
-
|
|
612
|
-
def make_xrefs(
|
|
613
|
-
self,
|
|
614
|
-
rolename: str,
|
|
615
|
-
domain: str,
|
|
616
|
-
target: str,
|
|
617
|
-
innernode: type[TextlikeNode] = nodes.emphasis,
|
|
618
|
-
contnode: Node | None = None,
|
|
619
|
-
env: BuildEnvironment | None = None,
|
|
620
|
-
inliner: Inliner | None = None,
|
|
621
|
-
location: Node | None = None,
|
|
622
|
-
) -> list[Node]:
|
|
623
|
-
delims = r'(\s*[\[\]\(\),](?:\s*o[rf]\s)?\s*|\s+o[rf]\s+|\s*\|\s*|\.\.\.)'
|
|
624
|
-
delims_re = re.compile(delims)
|
|
625
|
-
sub_targets = re.split(delims, target)
|
|
626
|
-
|
|
627
|
-
split_contnode = bool(contnode and contnode.astext() == target)
|
|
628
|
-
|
|
629
|
-
in_literal = False
|
|
630
|
-
results = []
|
|
631
|
-
for sub_target in filter(None, sub_targets):
|
|
632
|
-
if split_contnode:
|
|
633
|
-
contnode = nodes.Text(sub_target)
|
|
634
|
-
|
|
635
|
-
if in_literal or delims_re.match(sub_target):
|
|
636
|
-
results.append(contnode or innernode(sub_target, sub_target))
|
|
637
|
-
else:
|
|
638
|
-
results.append(self.make_xref(rolename, domain, sub_target,
|
|
639
|
-
innernode, contnode, env, inliner, location))
|
|
640
|
-
|
|
641
|
-
if sub_target in ('Literal', 'typing.Literal', '~typing.Literal'):
|
|
642
|
-
in_literal = True
|
|
643
|
-
|
|
644
|
-
return results
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
class PyField(PyXrefMixin, Field):
|
|
648
|
-
pass
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
class PyGroupedField(PyXrefMixin, GroupedField):
|
|
652
|
-
pass
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
class PyTypedField(PyXrefMixin, TypedField):
|
|
656
|
-
pass
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
class PyObject(ObjectDescription[tuple[str, str]]):
|
|
660
|
-
"""
|
|
661
|
-
Description of a general Python object.
|
|
662
|
-
|
|
663
|
-
:cvar allow_nesting: Class is an object that allows for nested namespaces
|
|
664
|
-
:vartype allow_nesting: bool
|
|
665
|
-
"""
|
|
666
|
-
option_spec: OptionSpec = {
|
|
667
|
-
'no-index': directives.flag,
|
|
668
|
-
'no-index-entry': directives.flag,
|
|
669
|
-
'no-contents-entry': directives.flag,
|
|
670
|
-
'no-typesetting': directives.flag,
|
|
671
|
-
'noindex': directives.flag,
|
|
672
|
-
'noindexentry': directives.flag,
|
|
673
|
-
'nocontentsentry': directives.flag,
|
|
674
|
-
'single-line-parameter-list': directives.flag,
|
|
675
|
-
'single-line-type-parameter-list': directives.flag,
|
|
676
|
-
'module': directives.unchanged,
|
|
677
|
-
'canonical': directives.unchanged,
|
|
678
|
-
'annotation': directives.unchanged,
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
doc_field_types = [
|
|
682
|
-
PyTypedField('parameter', label=_('Parameters'),
|
|
683
|
-
names=('param', 'parameter', 'arg', 'argument',
|
|
684
|
-
'keyword', 'kwarg', 'kwparam'),
|
|
685
|
-
typerolename='class', typenames=('paramtype', 'type'),
|
|
686
|
-
can_collapse=True),
|
|
687
|
-
PyTypedField('variable', label=_('Variables'),
|
|
688
|
-
names=('var', 'ivar', 'cvar'),
|
|
689
|
-
typerolename='class', typenames=('vartype',),
|
|
690
|
-
can_collapse=True),
|
|
691
|
-
PyGroupedField('exceptions', label=_('Raises'), rolename='exc',
|
|
692
|
-
names=('raises', 'raise', 'exception', 'except'),
|
|
693
|
-
can_collapse=True),
|
|
694
|
-
Field('returnvalue', label=_('Returns'), has_arg=False,
|
|
695
|
-
names=('returns', 'return')),
|
|
696
|
-
PyField('returntype', label=_('Return type'), has_arg=False,
|
|
697
|
-
names=('rtype',), bodyrolename='class'),
|
|
698
|
-
]
|
|
699
|
-
|
|
700
|
-
allow_nesting = False
|
|
701
|
-
|
|
702
|
-
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
703
|
-
"""May return a prefix to put before the object name in the
|
|
704
|
-
signature.
|
|
705
|
-
"""
|
|
706
|
-
return []
|
|
707
|
-
|
|
708
|
-
def needs_arglist(self) -> bool:
|
|
709
|
-
"""May return true if an empty argument list is to be generated even if
|
|
710
|
-
the document contains none.
|
|
711
|
-
"""
|
|
712
|
-
return False
|
|
713
|
-
|
|
714
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
715
|
-
"""Transform a Python signature into RST nodes.
|
|
716
|
-
|
|
717
|
-
Return (fully qualified name of the thing, classname if any).
|
|
718
|
-
|
|
719
|
-
If inside a class, the current class name is handled intelligently:
|
|
720
|
-
* it is stripped from the displayed name if present
|
|
721
|
-
* it is added to the full name (return value) if not present
|
|
722
|
-
"""
|
|
723
|
-
m = py_sig_re.match(sig)
|
|
724
|
-
if m is None:
|
|
725
|
-
raise ValueError
|
|
726
|
-
prefix, name, tp_list, arglist, retann = m.groups()
|
|
727
|
-
|
|
728
|
-
# determine module and class name (if applicable), as well as full name
|
|
729
|
-
modname = self.options.get('module', self.env.ref_context.get('py:module'))
|
|
730
|
-
classname = self.env.ref_context.get('py:class')
|
|
731
|
-
if classname:
|
|
732
|
-
add_module = False
|
|
733
|
-
if prefix and (prefix == classname or
|
|
734
|
-
prefix.startswith(classname + ".")):
|
|
735
|
-
fullname = prefix + name
|
|
736
|
-
# class name is given again in the signature
|
|
737
|
-
prefix = prefix[len(classname):].lstrip('.')
|
|
738
|
-
elif prefix:
|
|
739
|
-
# class name is given in the signature, but different
|
|
740
|
-
# (shouldn't happen)
|
|
741
|
-
fullname = classname + '.' + prefix + name
|
|
742
|
-
else:
|
|
743
|
-
# class name is not given in the signature
|
|
744
|
-
fullname = classname + '.' + name
|
|
745
|
-
else:
|
|
746
|
-
add_module = True
|
|
747
|
-
if prefix:
|
|
748
|
-
classname = prefix.rstrip('.')
|
|
749
|
-
fullname = prefix + name
|
|
750
|
-
else:
|
|
751
|
-
classname = ''
|
|
752
|
-
fullname = name
|
|
753
|
-
|
|
754
|
-
signode['module'] = modname
|
|
755
|
-
signode['class'] = classname
|
|
756
|
-
signode['fullname'] = fullname
|
|
757
|
-
|
|
758
|
-
max_len = (self.env.config.python_maximum_signature_line_length
|
|
759
|
-
or self.env.config.maximum_signature_line_length
|
|
760
|
-
or 0)
|
|
761
|
-
|
|
762
|
-
# determine if the function arguments (without its type parameters)
|
|
763
|
-
# should be formatted on a multiline or not by removing the width of
|
|
764
|
-
# the type parameters list (if any)
|
|
765
|
-
sig_len = len(sig)
|
|
766
|
-
tp_list_span = m.span(3)
|
|
767
|
-
multi_line_parameter_list = (
|
|
768
|
-
'single-line-parameter-list' not in self.options
|
|
769
|
-
and (sig_len - (tp_list_span[1] - tp_list_span[0])) > max_len > 0
|
|
770
|
-
)
|
|
771
|
-
|
|
772
|
-
# determine whether the type parameter list must be wrapped or not
|
|
773
|
-
arglist_span = m.span(4)
|
|
774
|
-
multi_line_type_parameter_list = (
|
|
775
|
-
'single-line-type-parameter-list' not in self.options
|
|
776
|
-
and (sig_len - (arglist_span[1] - arglist_span[0])) > max_len > 0
|
|
777
|
-
)
|
|
778
|
-
|
|
779
|
-
sig_prefix = self.get_signature_prefix(sig)
|
|
780
|
-
if sig_prefix:
|
|
781
|
-
if type(sig_prefix) is str:
|
|
782
|
-
msg = ("Python directive method get_signature_prefix()"
|
|
783
|
-
" must return a list of nodes."
|
|
784
|
-
f" Return value was '{sig_prefix}'.")
|
|
785
|
-
raise TypeError(msg)
|
|
786
|
-
signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
|
|
787
|
-
|
|
788
|
-
if prefix:
|
|
789
|
-
signode += addnodes.desc_addname(prefix, prefix)
|
|
790
|
-
elif modname and add_module and self.env.config.add_module_names:
|
|
791
|
-
nodetext = modname + '.'
|
|
792
|
-
signode += addnodes.desc_addname(nodetext, nodetext)
|
|
793
|
-
|
|
794
|
-
signode += addnodes.desc_name(name, name)
|
|
795
|
-
|
|
796
|
-
if tp_list:
|
|
797
|
-
try:
|
|
798
|
-
signode += _parse_type_list(tp_list, self.env, multi_line_type_parameter_list)
|
|
799
|
-
except Exception as exc:
|
|
800
|
-
logger.warning("could not parse tp_list (%r): %s", tp_list, exc,
|
|
801
|
-
location=signode)
|
|
802
|
-
|
|
803
|
-
if arglist:
|
|
804
|
-
try:
|
|
805
|
-
signode += _parse_arglist(arglist, self.env, multi_line_parameter_list)
|
|
806
|
-
except SyntaxError:
|
|
807
|
-
# fallback to parse arglist original parser
|
|
808
|
-
# (this may happen if the argument list is incorrectly used
|
|
809
|
-
# as a list of bases when documenting a class)
|
|
810
|
-
# it supports to represent optional arguments (ex. "func(foo [, bar])")
|
|
811
|
-
_pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
|
|
812
|
-
except (NotImplementedError, ValueError) as exc:
|
|
813
|
-
# duplicated parameter names raise ValueError and not a SyntaxError
|
|
814
|
-
logger.warning("could not parse arglist (%r): %s", arglist, exc,
|
|
815
|
-
location=signode)
|
|
816
|
-
_pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
|
|
817
|
-
else:
|
|
818
|
-
if self.needs_arglist():
|
|
819
|
-
# for callables, add an empty parameter list
|
|
820
|
-
signode += addnodes.desc_parameterlist()
|
|
821
|
-
|
|
822
|
-
if retann:
|
|
823
|
-
children = _parse_annotation(retann, self.env)
|
|
824
|
-
signode += addnodes.desc_returns(retann, '', *children)
|
|
825
|
-
|
|
826
|
-
anno = self.options.get('annotation')
|
|
827
|
-
if anno:
|
|
828
|
-
signode += addnodes.desc_annotation(' ' + anno, '',
|
|
829
|
-
addnodes.desc_sig_space(),
|
|
830
|
-
nodes.Text(anno))
|
|
831
|
-
|
|
832
|
-
return fullname, prefix
|
|
833
|
-
|
|
834
|
-
def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
|
|
835
|
-
if 'fullname' not in sig_node:
|
|
836
|
-
return ()
|
|
837
|
-
modname = sig_node.get('module')
|
|
838
|
-
fullname = sig_node['fullname']
|
|
839
|
-
|
|
840
|
-
if modname:
|
|
841
|
-
return (modname, *fullname.split('.'))
|
|
842
|
-
else:
|
|
843
|
-
return tuple(fullname.split('.'))
|
|
844
|
-
|
|
845
|
-
def get_index_text(self, modname: str, name: tuple[str, str]) -> str:
|
|
846
|
-
"""Return the text for the index entry of the object."""
|
|
847
|
-
msg = 'must be implemented in subclasses'
|
|
848
|
-
raise NotImplementedError(msg)
|
|
849
|
-
|
|
850
|
-
def add_target_and_index(self, name_cls: tuple[str, str], sig: str,
|
|
851
|
-
signode: desc_signature) -> None:
|
|
852
|
-
modname = self.options.get('module', self.env.ref_context.get('py:module'))
|
|
853
|
-
fullname = (modname + '.' if modname else '') + name_cls[0]
|
|
854
|
-
node_id = make_id(self.env, self.state.document, '', fullname)
|
|
855
|
-
signode['ids'].append(node_id)
|
|
856
|
-
self.state.document.note_explicit_target(signode)
|
|
857
|
-
|
|
858
|
-
domain = cast(PythonDomain, self.env.get_domain('py'))
|
|
859
|
-
domain.note_object(fullname, self.objtype, node_id, location=signode)
|
|
860
|
-
|
|
861
|
-
canonical_name = self.options.get('canonical')
|
|
862
|
-
if canonical_name:
|
|
863
|
-
domain.note_object(canonical_name, self.objtype, node_id, aliased=True,
|
|
864
|
-
location=signode)
|
|
865
|
-
|
|
866
|
-
if 'no-index-entry' not in self.options:
|
|
867
|
-
indextext = self.get_index_text(modname, name_cls)
|
|
868
|
-
if indextext:
|
|
869
|
-
self.indexnode['entries'].append(('single', indextext, node_id, '', None))
|
|
870
|
-
|
|
871
|
-
def before_content(self) -> None:
|
|
872
|
-
"""Handle object nesting before content
|
|
873
|
-
|
|
874
|
-
:py:class:`PyObject` represents Python language constructs. For
|
|
875
|
-
constructs that are nestable, such as a Python classes, this method will
|
|
876
|
-
build up a stack of the nesting hierarchy so that it can be later
|
|
877
|
-
de-nested correctly, in :py:meth:`after_content`.
|
|
878
|
-
|
|
879
|
-
For constructs that aren't nestable, the stack is bypassed, and instead
|
|
880
|
-
only the most recent object is tracked. This object prefix name will be
|
|
881
|
-
removed with :py:meth:`after_content`.
|
|
882
|
-
"""
|
|
883
|
-
prefix = None
|
|
884
|
-
if self.names:
|
|
885
|
-
# fullname and name_prefix come from the `handle_signature` method.
|
|
886
|
-
# fullname represents the full object name that is constructed using
|
|
887
|
-
# object nesting and explicit prefixes. `name_prefix` is the
|
|
888
|
-
# explicit prefix given in a signature
|
|
889
|
-
(fullname, name_prefix) = self.names[-1]
|
|
890
|
-
if self.allow_nesting:
|
|
891
|
-
prefix = fullname
|
|
892
|
-
elif name_prefix:
|
|
893
|
-
prefix = name_prefix.strip('.')
|
|
894
|
-
if prefix:
|
|
895
|
-
self.env.ref_context['py:class'] = prefix
|
|
896
|
-
if self.allow_nesting:
|
|
897
|
-
classes = self.env.ref_context.setdefault('py:classes', [])
|
|
898
|
-
classes.append(prefix)
|
|
899
|
-
if 'module' in self.options:
|
|
900
|
-
modules = self.env.ref_context.setdefault('py:modules', [])
|
|
901
|
-
modules.append(self.env.ref_context.get('py:module'))
|
|
902
|
-
self.env.ref_context['py:module'] = self.options['module']
|
|
903
|
-
|
|
904
|
-
def after_content(self) -> None:
|
|
905
|
-
"""Handle object de-nesting after content
|
|
906
|
-
|
|
907
|
-
If this class is a nestable object, removing the last nested class prefix
|
|
908
|
-
ends further nesting in the object.
|
|
909
|
-
|
|
910
|
-
If this class is not a nestable object, the list of classes should not
|
|
911
|
-
be altered as we didn't affect the nesting levels in
|
|
912
|
-
:py:meth:`before_content`.
|
|
913
|
-
"""
|
|
914
|
-
classes = self.env.ref_context.setdefault('py:classes', [])
|
|
915
|
-
if self.allow_nesting:
|
|
916
|
-
with contextlib.suppress(IndexError):
|
|
917
|
-
classes.pop()
|
|
918
|
-
|
|
919
|
-
self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0
|
|
920
|
-
else None)
|
|
921
|
-
if 'module' in self.options:
|
|
922
|
-
modules = self.env.ref_context.setdefault('py:modules', [])
|
|
923
|
-
if modules:
|
|
924
|
-
self.env.ref_context['py:module'] = modules.pop()
|
|
925
|
-
else:
|
|
926
|
-
self.env.ref_context.pop('py:module')
|
|
927
|
-
|
|
928
|
-
def _toc_entry_name(self, sig_node: desc_signature) -> str:
|
|
929
|
-
if not sig_node.get('_toc_parts'):
|
|
930
|
-
return ''
|
|
931
|
-
|
|
932
|
-
config = self.env.app.config
|
|
933
|
-
objtype = sig_node.parent.get('objtype')
|
|
934
|
-
if config.add_function_parentheses and objtype in {'function', 'method'}:
|
|
935
|
-
parens = '()'
|
|
936
|
-
else:
|
|
937
|
-
parens = ''
|
|
938
|
-
*parents, name = sig_node['_toc_parts']
|
|
939
|
-
if config.toc_object_entries_show_parents == 'domain':
|
|
940
|
-
return sig_node.get('fullname', name) + parens
|
|
941
|
-
if config.toc_object_entries_show_parents == 'hide':
|
|
942
|
-
return name + parens
|
|
943
|
-
if config.toc_object_entries_show_parents == 'all':
|
|
944
|
-
return '.'.join(parents + [name + parens])
|
|
945
|
-
return ''
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
class PyFunction(PyObject):
|
|
949
|
-
"""Description of a function."""
|
|
950
|
-
|
|
951
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
952
|
-
option_spec.update({
|
|
953
|
-
'async': directives.flag,
|
|
954
|
-
})
|
|
955
|
-
|
|
956
|
-
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
957
|
-
if 'async' in self.options:
|
|
958
|
-
return [addnodes.desc_sig_keyword('', 'async'),
|
|
959
|
-
addnodes.desc_sig_space()]
|
|
960
|
-
else:
|
|
961
|
-
return []
|
|
962
|
-
|
|
963
|
-
def needs_arglist(self) -> bool:
|
|
964
|
-
return True
|
|
965
|
-
|
|
966
|
-
def add_target_and_index(self, name_cls: tuple[str, str], sig: str,
|
|
967
|
-
signode: desc_signature) -> None:
|
|
968
|
-
super().add_target_and_index(name_cls, sig, signode)
|
|
969
|
-
if 'no-index-entry' not in self.options:
|
|
970
|
-
modname = self.options.get('module', self.env.ref_context.get('py:module'))
|
|
971
|
-
node_id = signode['ids'][0]
|
|
972
|
-
|
|
973
|
-
name, cls = name_cls
|
|
974
|
-
if modname:
|
|
975
|
-
text = _('%s() (in module %s)') % (name, modname)
|
|
976
|
-
self.indexnode['entries'].append(('single', text, node_id, '', None))
|
|
977
|
-
else:
|
|
978
|
-
text = f'built-in function; {name}()'
|
|
979
|
-
self.indexnode['entries'].append(('pair', text, node_id, '', None))
|
|
980
|
-
|
|
981
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
982
|
-
# add index in own add_target_and_index() instead.
|
|
983
|
-
return ''
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
class PyDecoratorFunction(PyFunction):
|
|
987
|
-
"""Description of a decorator."""
|
|
988
|
-
|
|
989
|
-
def run(self) -> list[Node]:
|
|
990
|
-
# a decorator function is a function after all
|
|
991
|
-
self.name = 'py:function'
|
|
992
|
-
return super().run()
|
|
993
|
-
|
|
994
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
995
|
-
ret = super().handle_signature(sig, signode)
|
|
996
|
-
signode.insert(0, addnodes.desc_addname('@', '@'))
|
|
997
|
-
return ret
|
|
998
|
-
|
|
999
|
-
def needs_arglist(self) -> bool:
|
|
1000
|
-
return False
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
class PyVariable(PyObject):
|
|
1004
|
-
"""Description of a variable."""
|
|
1005
|
-
|
|
1006
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1007
|
-
option_spec.update({
|
|
1008
|
-
'type': directives.unchanged,
|
|
1009
|
-
'value': directives.unchanged,
|
|
1010
|
-
})
|
|
1011
|
-
|
|
1012
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
1013
|
-
fullname, prefix = super().handle_signature(sig, signode)
|
|
1014
|
-
|
|
1015
|
-
typ = self.options.get('type')
|
|
1016
|
-
if typ:
|
|
1017
|
-
annotations = _parse_annotation(typ, self.env)
|
|
1018
|
-
signode += addnodes.desc_annotation(typ, '',
|
|
1019
|
-
addnodes.desc_sig_punctuation('', ':'),
|
|
1020
|
-
addnodes.desc_sig_space(), *annotations)
|
|
1021
|
-
|
|
1022
|
-
value = self.options.get('value')
|
|
1023
|
-
if value:
|
|
1024
|
-
signode += addnodes.desc_annotation(value, '',
|
|
1025
|
-
addnodes.desc_sig_space(),
|
|
1026
|
-
addnodes.desc_sig_punctuation('', '='),
|
|
1027
|
-
addnodes.desc_sig_space(),
|
|
1028
|
-
nodes.Text(value))
|
|
1029
|
-
|
|
1030
|
-
return fullname, prefix
|
|
1031
|
-
|
|
1032
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
1033
|
-
name, cls = name_cls
|
|
1034
|
-
if modname:
|
|
1035
|
-
return _('%s (in module %s)') % (name, modname)
|
|
1036
|
-
else:
|
|
1037
|
-
return _('%s (built-in variable)') % name
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
class PyClasslike(PyObject):
|
|
1041
|
-
"""
|
|
1042
|
-
Description of a class-like object (classes, interfaces, exceptions).
|
|
1043
|
-
"""
|
|
1044
|
-
|
|
1045
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1046
|
-
option_spec.update({
|
|
1047
|
-
'final': directives.flag,
|
|
1048
|
-
})
|
|
1049
|
-
|
|
1050
|
-
allow_nesting = True
|
|
1051
|
-
|
|
1052
|
-
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
1053
|
-
if 'final' in self.options:
|
|
1054
|
-
return [nodes.Text('final'), addnodes.desc_sig_space(),
|
|
1055
|
-
nodes.Text(self.objtype), addnodes.desc_sig_space()]
|
|
1056
|
-
else:
|
|
1057
|
-
return [nodes.Text(self.objtype), addnodes.desc_sig_space()]
|
|
1058
|
-
|
|
1059
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
1060
|
-
if self.objtype == 'class':
|
|
1061
|
-
if not modname:
|
|
1062
|
-
return _('%s (built-in class)') % name_cls[0]
|
|
1063
|
-
return _('%s (class in %s)') % (name_cls[0], modname)
|
|
1064
|
-
elif self.objtype == 'exception':
|
|
1065
|
-
return name_cls[0]
|
|
1066
|
-
else:
|
|
1067
|
-
return ''
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
class PyMethod(PyObject):
|
|
1071
|
-
"""Description of a method."""
|
|
1072
|
-
|
|
1073
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1074
|
-
option_spec.update({
|
|
1075
|
-
'abstractmethod': directives.flag,
|
|
1076
|
-
'async': directives.flag,
|
|
1077
|
-
'classmethod': directives.flag,
|
|
1078
|
-
'final': directives.flag,
|
|
1079
|
-
'staticmethod': directives.flag,
|
|
1080
|
-
})
|
|
1081
|
-
|
|
1082
|
-
def needs_arglist(self) -> bool:
|
|
1083
|
-
return True
|
|
1084
|
-
|
|
1085
|
-
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
1086
|
-
prefix: list[nodes.Node] = []
|
|
1087
|
-
if 'final' in self.options:
|
|
1088
|
-
prefix.append(nodes.Text('final'))
|
|
1089
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1090
|
-
if 'abstractmethod' in self.options:
|
|
1091
|
-
prefix.append(nodes.Text('abstract'))
|
|
1092
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1093
|
-
if 'async' in self.options:
|
|
1094
|
-
prefix.append(nodes.Text('async'))
|
|
1095
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1096
|
-
if 'classmethod' in self.options:
|
|
1097
|
-
prefix.append(nodes.Text('classmethod'))
|
|
1098
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1099
|
-
if 'staticmethod' in self.options:
|
|
1100
|
-
prefix.append(nodes.Text('static'))
|
|
1101
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1102
|
-
return prefix
|
|
1103
|
-
|
|
1104
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
1105
|
-
name, cls = name_cls
|
|
1106
|
-
try:
|
|
1107
|
-
clsname, methname = name.rsplit('.', 1)
|
|
1108
|
-
if modname and self.env.config.add_module_names:
|
|
1109
|
-
clsname = '.'.join([modname, clsname])
|
|
1110
|
-
except ValueError:
|
|
1111
|
-
if modname:
|
|
1112
|
-
return _('%s() (in module %s)') % (name, modname)
|
|
1113
|
-
else:
|
|
1114
|
-
return '%s()' % name
|
|
1115
|
-
|
|
1116
|
-
if 'classmethod' in self.options:
|
|
1117
|
-
return _('%s() (%s class method)') % (methname, clsname)
|
|
1118
|
-
elif 'staticmethod' in self.options:
|
|
1119
|
-
return _('%s() (%s static method)') % (methname, clsname)
|
|
1120
|
-
else:
|
|
1121
|
-
return _('%s() (%s method)') % (methname, clsname)
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
class PyClassMethod(PyMethod):
|
|
1125
|
-
"""Description of a classmethod."""
|
|
1126
|
-
|
|
1127
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1128
|
-
|
|
1129
|
-
def run(self) -> list[Node]:
|
|
1130
|
-
self.name = 'py:method'
|
|
1131
|
-
self.options['classmethod'] = True
|
|
1132
|
-
|
|
1133
|
-
return super().run()
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
class PyStaticMethod(PyMethod):
|
|
1137
|
-
"""Description of a staticmethod."""
|
|
1138
|
-
|
|
1139
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1140
|
-
|
|
1141
|
-
def run(self) -> list[Node]:
|
|
1142
|
-
self.name = 'py:method'
|
|
1143
|
-
self.options['staticmethod'] = True
|
|
1144
|
-
|
|
1145
|
-
return super().run()
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
class PyDecoratorMethod(PyMethod):
|
|
1149
|
-
"""Description of a decoratormethod."""
|
|
1150
|
-
|
|
1151
|
-
def run(self) -> list[Node]:
|
|
1152
|
-
self.name = 'py:method'
|
|
1153
|
-
return super().run()
|
|
1154
|
-
|
|
1155
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
1156
|
-
ret = super().handle_signature(sig, signode)
|
|
1157
|
-
signode.insert(0, addnodes.desc_addname('@', '@'))
|
|
1158
|
-
return ret
|
|
1159
|
-
|
|
1160
|
-
def needs_arglist(self) -> bool:
|
|
1161
|
-
return False
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
class PyAttribute(PyObject):
|
|
1165
|
-
"""Description of an attribute."""
|
|
1166
|
-
|
|
1167
|
-
option_spec: OptionSpec = PyObject.option_spec.copy()
|
|
1168
|
-
option_spec.update({
|
|
1169
|
-
'type': directives.unchanged,
|
|
1170
|
-
'value': directives.unchanged,
|
|
1171
|
-
})
|
|
1172
|
-
|
|
1173
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
1174
|
-
fullname, prefix = super().handle_signature(sig, signode)
|
|
1175
|
-
|
|
1176
|
-
typ = self.options.get('type')
|
|
1177
|
-
if typ:
|
|
1178
|
-
annotations = _parse_annotation(typ, self.env)
|
|
1179
|
-
signode += addnodes.desc_annotation(typ, '',
|
|
1180
|
-
addnodes.desc_sig_punctuation('', ':'),
|
|
1181
|
-
addnodes.desc_sig_space(),
|
|
1182
|
-
*annotations)
|
|
1183
|
-
|
|
1184
|
-
value = self.options.get('value')
|
|
1185
|
-
if value:
|
|
1186
|
-
signode += addnodes.desc_annotation(value, '',
|
|
1187
|
-
addnodes.desc_sig_space(),
|
|
1188
|
-
addnodes.desc_sig_punctuation('', '='),
|
|
1189
|
-
addnodes.desc_sig_space(),
|
|
1190
|
-
nodes.Text(value))
|
|
1191
|
-
|
|
1192
|
-
return fullname, prefix
|
|
1193
|
-
|
|
1194
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
1195
|
-
name, cls = name_cls
|
|
1196
|
-
try:
|
|
1197
|
-
clsname, attrname = name.rsplit('.', 1)
|
|
1198
|
-
if modname and self.env.config.add_module_names:
|
|
1199
|
-
clsname = '.'.join([modname, clsname])
|
|
1200
|
-
except ValueError:
|
|
1201
|
-
if modname:
|
|
1202
|
-
return _('%s (in module %s)') % (name, modname)
|
|
1203
|
-
else:
|
|
1204
|
-
return name
|
|
1205
|
-
|
|
1206
|
-
return _('%s (%s attribute)') % (attrname, clsname)
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
class PyProperty(PyObject):
|
|
1210
|
-
"""Description of an attribute."""
|
|
1211
|
-
|
|
1212
|
-
option_spec = PyObject.option_spec.copy()
|
|
1213
|
-
option_spec.update({
|
|
1214
|
-
'abstractmethod': directives.flag,
|
|
1215
|
-
'classmethod': directives.flag,
|
|
1216
|
-
'type': directives.unchanged,
|
|
1217
|
-
})
|
|
1218
|
-
|
|
1219
|
-
def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
|
|
1220
|
-
fullname, prefix = super().handle_signature(sig, signode)
|
|
1221
|
-
|
|
1222
|
-
typ = self.options.get('type')
|
|
1223
|
-
if typ:
|
|
1224
|
-
annotations = _parse_annotation(typ, self.env)
|
|
1225
|
-
signode += addnodes.desc_annotation(typ, '',
|
|
1226
|
-
addnodes.desc_sig_punctuation('', ':'),
|
|
1227
|
-
addnodes.desc_sig_space(),
|
|
1228
|
-
*annotations)
|
|
1229
|
-
|
|
1230
|
-
return fullname, prefix
|
|
1231
|
-
|
|
1232
|
-
def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
|
|
1233
|
-
prefix: list[nodes.Node] = []
|
|
1234
|
-
if 'abstractmethod' in self.options:
|
|
1235
|
-
prefix.append(nodes.Text('abstract'))
|
|
1236
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1237
|
-
if 'classmethod' in self.options:
|
|
1238
|
-
prefix.append(nodes.Text('class'))
|
|
1239
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1240
|
-
|
|
1241
|
-
prefix.append(nodes.Text('property'))
|
|
1242
|
-
prefix.append(addnodes.desc_sig_space())
|
|
1243
|
-
return prefix
|
|
1244
|
-
|
|
1245
|
-
def get_index_text(self, modname: str, name_cls: tuple[str, str]) -> str:
|
|
1246
|
-
name, cls = name_cls
|
|
1247
|
-
try:
|
|
1248
|
-
clsname, attrname = name.rsplit('.', 1)
|
|
1249
|
-
if modname and self.env.config.add_module_names:
|
|
1250
|
-
clsname = '.'.join([modname, clsname])
|
|
1251
|
-
except ValueError:
|
|
1252
|
-
if modname:
|
|
1253
|
-
return _('%s (in module %s)') % (name, modname)
|
|
1254
|
-
else:
|
|
1255
|
-
return name
|
|
1256
|
-
|
|
1257
|
-
return _('%s (%s property)') % (attrname, clsname)
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
class PyModule(SphinxDirective):
|
|
1261
|
-
"""
|
|
1262
|
-
Directive to mark description of a new module.
|
|
1263
|
-
"""
|
|
1264
|
-
|
|
1265
|
-
has_content = True
|
|
1266
|
-
required_arguments = 1
|
|
1267
|
-
optional_arguments = 0
|
|
1268
|
-
final_argument_whitespace = False
|
|
1269
|
-
option_spec: OptionSpec = {
|
|
1270
|
-
'platform': lambda x: x,
|
|
1271
|
-
'synopsis': lambda x: x,
|
|
1272
|
-
'no-index': directives.flag,
|
|
1273
|
-
'no-contents-entry': directives.flag,
|
|
1274
|
-
'no-typesetting': directives.flag,
|
|
1275
|
-
'noindex': directives.flag,
|
|
1276
|
-
'nocontentsentry': directives.flag,
|
|
1277
|
-
'deprecated': directives.flag,
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
def run(self) -> list[Node]:
|
|
1281
|
-
domain = cast(PythonDomain, self.env.get_domain('py'))
|
|
1282
|
-
|
|
1283
|
-
modname = self.arguments[0].strip()
|
|
1284
|
-
no_index = 'no-index' in self.options or 'noindex' in self.options
|
|
1285
|
-
self.env.ref_context['py:module'] = modname
|
|
1286
|
-
|
|
1287
|
-
content_node: Element = nodes.section()
|
|
1288
|
-
# necessary so that the child nodes get the right source/line set
|
|
1289
|
-
content_node.document = self.state.document
|
|
1290
|
-
nested_parse_with_titles(self.state, self.content, content_node, self.content_offset)
|
|
1291
|
-
|
|
1292
|
-
ret: list[Node] = []
|
|
1293
|
-
if not no_index:
|
|
1294
|
-
# note module to the domain
|
|
1295
|
-
node_id = make_id(self.env, self.state.document, 'module', modname)
|
|
1296
|
-
target = nodes.target('', '', ids=[node_id], ismod=True)
|
|
1297
|
-
self.set_source_info(target)
|
|
1298
|
-
self.state.document.note_explicit_target(target)
|
|
1299
|
-
|
|
1300
|
-
domain.note_module(modname,
|
|
1301
|
-
node_id,
|
|
1302
|
-
self.options.get('synopsis', ''),
|
|
1303
|
-
self.options.get('platform', ''),
|
|
1304
|
-
'deprecated' in self.options)
|
|
1305
|
-
domain.note_object(modname, 'module', node_id, location=target)
|
|
1306
|
-
|
|
1307
|
-
# the platform and synopsis aren't printed; in fact, they are only
|
|
1308
|
-
# used in the modindex currently
|
|
1309
|
-
indextext = f'module; {modname}'
|
|
1310
|
-
inode = addnodes.index(entries=[('pair', indextext, node_id, '', None)])
|
|
1311
|
-
# The node order is: index node first, then target node.
|
|
1312
|
-
ret.append(inode)
|
|
1313
|
-
ret.append(target)
|
|
1314
|
-
ret.extend(content_node.children)
|
|
1315
|
-
return ret
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
class PyCurrentModule(SphinxDirective):
|
|
1319
|
-
"""
|
|
1320
|
-
This directive is just to tell Sphinx that we're documenting
|
|
1321
|
-
stuff in module foo, but links to module foo won't lead here.
|
|
1322
|
-
"""
|
|
1323
|
-
|
|
1324
|
-
has_content = False
|
|
1325
|
-
required_arguments = 1
|
|
1326
|
-
optional_arguments = 0
|
|
1327
|
-
final_argument_whitespace = False
|
|
1328
|
-
option_spec: OptionSpec = {}
|
|
1329
|
-
|
|
1330
|
-
def run(self) -> list[Node]:
|
|
1331
|
-
modname = self.arguments[0].strip()
|
|
1332
|
-
if modname == 'None':
|
|
1333
|
-
self.env.ref_context.pop('py:module', None)
|
|
1334
|
-
else:
|
|
1335
|
-
self.env.ref_context['py:module'] = modname
|
|
1336
|
-
return []
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
class PyXRefRole(XRefRole):
|
|
1340
|
-
def process_link(self, env: BuildEnvironment, refnode: Element,
|
|
1341
|
-
has_explicit_title: bool, title: str, target: str) -> tuple[str, str]:
|
|
1342
|
-
refnode['py:module'] = env.ref_context.get('py:module')
|
|
1343
|
-
refnode['py:class'] = env.ref_context.get('py:class')
|
|
1344
|
-
if not has_explicit_title:
|
|
1345
|
-
title = title.lstrip('.') # only has a meaning for the target
|
|
1346
|
-
target = target.lstrip('~') # only has a meaning for the title
|
|
1347
|
-
# if the first character is a tilde, don't display the module/class
|
|
1348
|
-
# parts of the contents
|
|
1349
|
-
if title[0:1] == '~':
|
|
1350
|
-
title = title[1:]
|
|
1351
|
-
dot = title.rfind('.')
|
|
1352
|
-
if dot != -1:
|
|
1353
|
-
title = title[dot + 1:]
|
|
1354
|
-
# if the first character is a dot, search more specific namespaces first
|
|
1355
|
-
# else search builtins first
|
|
1356
|
-
if target[0:1] == '.':
|
|
1357
|
-
target = target[1:]
|
|
1358
|
-
refnode['refspecific'] = True
|
|
1359
|
-
return title, target
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
def filter_meta_fields(app: Sphinx, domain: str, objtype: str, content: Element) -> None:
|
|
1363
|
-
"""Filter ``:meta:`` field from its docstring."""
|
|
1364
|
-
if domain != 'py':
|
|
1365
|
-
return
|
|
1366
|
-
|
|
1367
|
-
for node in content:
|
|
1368
|
-
if isinstance(node, nodes.field_list):
|
|
1369
|
-
fields = cast(list[nodes.field], node)
|
|
1370
|
-
# removing list items while iterating the list needs reversed()
|
|
1371
|
-
for field in reversed(fields):
|
|
1372
|
-
field_name = cast(nodes.field_body, field[0]).astext().strip()
|
|
1373
|
-
if field_name == 'meta' or field_name.startswith('meta '):
|
|
1374
|
-
node.remove(field)
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
class PythonModuleIndex(Index):
|
|
1378
|
-
"""
|
|
1379
|
-
Index subclass to provide the Python module index.
|
|
1380
|
-
"""
|
|
1381
|
-
|
|
1382
|
-
name = 'modindex'
|
|
1383
|
-
localname = _('Python Module Index')
|
|
1384
|
-
shortname = _('modules')
|
|
1385
|
-
|
|
1386
|
-
def generate(self, docnames: Iterable[str] | None = None,
|
|
1387
|
-
) -> tuple[list[tuple[str, list[IndexEntry]]], bool]:
|
|
1388
|
-
content: dict[str, list[IndexEntry]] = {}
|
|
1389
|
-
# list of prefixes to ignore
|
|
1390
|
-
ignores: list[str] = self.domain.env.config['modindex_common_prefix']
|
|
1391
|
-
ignores = sorted(ignores, key=len, reverse=True)
|
|
1392
|
-
# list of all modules, sorted by module name
|
|
1393
|
-
modules = sorted(self.domain.data['modules'].items(),
|
|
1394
|
-
key=lambda x: x[0].lower())
|
|
1395
|
-
# sort out collapsible modules
|
|
1396
|
-
prev_modname = ''
|
|
1397
|
-
num_toplevels = 0
|
|
1398
|
-
for modname, (docname, node_id, synopsis, platforms, deprecated) in modules:
|
|
1399
|
-
if docnames and docname not in docnames:
|
|
1400
|
-
continue
|
|
1401
|
-
|
|
1402
|
-
for ignore in ignores:
|
|
1403
|
-
if modname.startswith(ignore):
|
|
1404
|
-
modname = modname[len(ignore):]
|
|
1405
|
-
stripped = ignore
|
|
1406
|
-
break
|
|
1407
|
-
else:
|
|
1408
|
-
stripped = ''
|
|
1409
|
-
|
|
1410
|
-
# we stripped the whole module name?
|
|
1411
|
-
if not modname:
|
|
1412
|
-
modname, stripped = stripped, ''
|
|
1413
|
-
|
|
1414
|
-
entries = content.setdefault(modname[0].lower(), [])
|
|
1415
|
-
|
|
1416
|
-
package = modname.split('.')[0]
|
|
1417
|
-
if package != modname:
|
|
1418
|
-
# it's a submodule
|
|
1419
|
-
if prev_modname == package:
|
|
1420
|
-
# first submodule - make parent a group head
|
|
1421
|
-
if entries:
|
|
1422
|
-
last = entries[-1]
|
|
1423
|
-
entries[-1] = IndexEntry(last[0], 1, last[2], last[3],
|
|
1424
|
-
last[4], last[5], last[6])
|
|
1425
|
-
elif not prev_modname.startswith(package):
|
|
1426
|
-
# submodule without parent in list, add dummy entry
|
|
1427
|
-
entries.append(IndexEntry(stripped + package, 1, '', '', '', '', ''))
|
|
1428
|
-
subtype = 2
|
|
1429
|
-
else:
|
|
1430
|
-
num_toplevels += 1
|
|
1431
|
-
subtype = 0
|
|
1432
|
-
|
|
1433
|
-
qualifier = _('Deprecated') if deprecated else ''
|
|
1434
|
-
entries.append(IndexEntry(stripped + modname, subtype, docname,
|
|
1435
|
-
node_id, platforms, qualifier, synopsis))
|
|
1436
|
-
prev_modname = modname
|
|
1437
|
-
|
|
1438
|
-
# apply heuristics when to collapse modindex at page load:
|
|
1439
|
-
# only collapse if number of toplevel modules is larger than
|
|
1440
|
-
# number of submodules
|
|
1441
|
-
collapse = len(modules) - num_toplevels < num_toplevels
|
|
1442
|
-
|
|
1443
|
-
# sort by first letter
|
|
1444
|
-
sorted_content = sorted(content.items())
|
|
1445
|
-
|
|
1446
|
-
return sorted_content, collapse
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
class PythonDomain(Domain):
|
|
1450
|
-
"""Python language domain."""
|
|
1451
|
-
name = 'py'
|
|
1452
|
-
label = 'Python'
|
|
1453
|
-
object_types: dict[str, ObjType] = {
|
|
1454
|
-
'function': ObjType(_('function'), 'func', 'obj'),
|
|
1455
|
-
'data': ObjType(_('data'), 'data', 'obj'),
|
|
1456
|
-
'class': ObjType(_('class'), 'class', 'exc', 'obj'),
|
|
1457
|
-
'exception': ObjType(_('exception'), 'exc', 'class', 'obj'),
|
|
1458
|
-
'method': ObjType(_('method'), 'meth', 'obj'),
|
|
1459
|
-
'classmethod': ObjType(_('class method'), 'meth', 'obj'),
|
|
1460
|
-
'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
|
|
1461
|
-
'attribute': ObjType(_('attribute'), 'attr', 'obj'),
|
|
1462
|
-
'property': ObjType(_('property'), 'attr', '_prop', 'obj'),
|
|
1463
|
-
'module': ObjType(_('module'), 'mod', 'obj'),
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
directives = {
|
|
1467
|
-
'function': PyFunction,
|
|
1468
|
-
'data': PyVariable,
|
|
1469
|
-
'class': PyClasslike,
|
|
1470
|
-
'exception': PyClasslike,
|
|
1471
|
-
'method': PyMethod,
|
|
1472
|
-
'classmethod': PyClassMethod,
|
|
1473
|
-
'staticmethod': PyStaticMethod,
|
|
1474
|
-
'attribute': PyAttribute,
|
|
1475
|
-
'property': PyProperty,
|
|
1476
|
-
'module': PyModule,
|
|
1477
|
-
'currentmodule': PyCurrentModule,
|
|
1478
|
-
'decorator': PyDecoratorFunction,
|
|
1479
|
-
'decoratormethod': PyDecoratorMethod,
|
|
1480
|
-
}
|
|
1481
|
-
roles = {
|
|
1482
|
-
'data': PyXRefRole(),
|
|
1483
|
-
'exc': PyXRefRole(),
|
|
1484
|
-
'func': PyXRefRole(fix_parens=True),
|
|
1485
|
-
'class': PyXRefRole(),
|
|
1486
|
-
'const': PyXRefRole(),
|
|
1487
|
-
'attr': PyXRefRole(),
|
|
1488
|
-
'meth': PyXRefRole(fix_parens=True),
|
|
1489
|
-
'mod': PyXRefRole(),
|
|
1490
|
-
'obj': PyXRefRole(),
|
|
1491
|
-
}
|
|
1492
|
-
initial_data: dict[str, dict[str, tuple[Any]]] = {
|
|
1493
|
-
'objects': {}, # fullname -> docname, objtype
|
|
1494
|
-
'modules': {}, # modname -> docname, synopsis, platform, deprecated
|
|
1495
|
-
}
|
|
1496
|
-
indices = [
|
|
1497
|
-
PythonModuleIndex,
|
|
1498
|
-
]
|
|
1499
|
-
|
|
1500
|
-
@property
|
|
1501
|
-
def objects(self) -> dict[str, ObjectEntry]:
|
|
1502
|
-
return self.data.setdefault('objects', {}) # fullname -> ObjectEntry
|
|
1503
|
-
|
|
1504
|
-
def note_object(self, name: str, objtype: str, node_id: str,
|
|
1505
|
-
aliased: bool = False, location: Any = None) -> None:
|
|
1506
|
-
"""Note a python object for cross reference.
|
|
1507
|
-
|
|
1508
|
-
.. versionadded:: 2.1
|
|
1509
|
-
"""
|
|
1510
|
-
if name in self.objects:
|
|
1511
|
-
other = self.objects[name]
|
|
1512
|
-
if other.aliased and aliased is False:
|
|
1513
|
-
# The original definition found. Override it!
|
|
1514
|
-
pass
|
|
1515
|
-
elif other.aliased is False and aliased:
|
|
1516
|
-
# The original definition is already registered.
|
|
1517
|
-
return
|
|
1518
|
-
else:
|
|
1519
|
-
# duplicated
|
|
1520
|
-
logger.warning(__('duplicate object description of %s, '
|
|
1521
|
-
'other instance in %s, use :no-index: for one of them'),
|
|
1522
|
-
name, other.docname, location=location)
|
|
1523
|
-
self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype, aliased)
|
|
1524
|
-
|
|
1525
|
-
@property
|
|
1526
|
-
def modules(self) -> dict[str, ModuleEntry]:
|
|
1527
|
-
return self.data.setdefault('modules', {}) # modname -> ModuleEntry
|
|
1528
|
-
|
|
1529
|
-
def note_module(self, name: str, node_id: str, synopsis: str,
|
|
1530
|
-
platform: str, deprecated: bool) -> None:
|
|
1531
|
-
"""Note a python module for cross reference.
|
|
1532
|
-
|
|
1533
|
-
.. versionadded:: 2.1
|
|
1534
|
-
"""
|
|
1535
|
-
self.modules[name] = ModuleEntry(self.env.docname, node_id,
|
|
1536
|
-
synopsis, platform, deprecated)
|
|
1537
|
-
|
|
1538
|
-
def clear_doc(self, docname: str) -> None:
|
|
1539
|
-
for fullname, obj in list(self.objects.items()):
|
|
1540
|
-
if obj.docname == docname:
|
|
1541
|
-
del self.objects[fullname]
|
|
1542
|
-
for modname, mod in list(self.modules.items()):
|
|
1543
|
-
if mod.docname == docname:
|
|
1544
|
-
del self.modules[modname]
|
|
1545
|
-
|
|
1546
|
-
def merge_domaindata(self, docnames: list[str], otherdata: dict[str, Any]) -> None:
|
|
1547
|
-
# XXX check duplicates?
|
|
1548
|
-
for fullname, obj in otherdata['objects'].items():
|
|
1549
|
-
if obj.docname in docnames:
|
|
1550
|
-
self.objects[fullname] = obj
|
|
1551
|
-
for modname, mod in otherdata['modules'].items():
|
|
1552
|
-
if mod.docname in docnames:
|
|
1553
|
-
self.modules[modname] = mod
|
|
1554
|
-
|
|
1555
|
-
def find_obj(self, env: BuildEnvironment, modname: str, classname: str,
|
|
1556
|
-
name: str, type: str | None, searchmode: int = 0,
|
|
1557
|
-
) -> list[tuple[str, ObjectEntry]]:
|
|
1558
|
-
"""Find a Python object for "name", perhaps using the given module
|
|
1559
|
-
and/or classname. Returns a list of (name, object entry) tuples.
|
|
1560
|
-
"""
|
|
1561
|
-
# skip parens
|
|
1562
|
-
if name[-2:] == '()':
|
|
1563
|
-
name = name[:-2]
|
|
1564
|
-
|
|
1565
|
-
if not name:
|
|
1566
|
-
return []
|
|
1567
|
-
|
|
1568
|
-
matches: list[tuple[str, ObjectEntry]] = []
|
|
1569
|
-
|
|
1570
|
-
newname = None
|
|
1571
|
-
if searchmode == 1:
|
|
1572
|
-
if type is None:
|
|
1573
|
-
objtypes: list[str] | None = list(self.object_types)
|
|
1574
|
-
else:
|
|
1575
|
-
objtypes = self.objtypes_for_role(type)
|
|
1576
|
-
if objtypes is not None:
|
|
1577
|
-
if modname and classname:
|
|
1578
|
-
fullname = modname + '.' + classname + '.' + name
|
|
1579
|
-
if fullname in self.objects and self.objects[fullname].objtype in objtypes:
|
|
1580
|
-
newname = fullname
|
|
1581
|
-
if not newname:
|
|
1582
|
-
if modname and modname + '.' + name in self.objects and \
|
|
1583
|
-
self.objects[modname + '.' + name].objtype in objtypes:
|
|
1584
|
-
newname = modname + '.' + name
|
|
1585
|
-
elif name in self.objects and self.objects[name].objtype in objtypes:
|
|
1586
|
-
newname = name
|
|
1587
|
-
else:
|
|
1588
|
-
# "fuzzy" searching mode
|
|
1589
|
-
searchname = '.' + name
|
|
1590
|
-
matches = [(oname, self.objects[oname]) for oname in self.objects
|
|
1591
|
-
if oname.endswith(searchname) and
|
|
1592
|
-
self.objects[oname].objtype in objtypes]
|
|
1593
|
-
else:
|
|
1594
|
-
# NOTE: searching for exact match, object type is not considered
|
|
1595
|
-
if name in self.objects:
|
|
1596
|
-
newname = name
|
|
1597
|
-
elif type == 'mod':
|
|
1598
|
-
# only exact matches allowed for modules
|
|
1599
|
-
return []
|
|
1600
|
-
elif classname and classname + '.' + name in self.objects:
|
|
1601
|
-
newname = classname + '.' + name
|
|
1602
|
-
elif modname and modname + '.' + name in self.objects:
|
|
1603
|
-
newname = modname + '.' + name
|
|
1604
|
-
elif modname and classname and \
|
|
1605
|
-
modname + '.' + classname + '.' + name in self.objects:
|
|
1606
|
-
newname = modname + '.' + classname + '.' + name
|
|
1607
|
-
if newname is not None:
|
|
1608
|
-
matches.append((newname, self.objects[newname]))
|
|
1609
|
-
return matches
|
|
1610
|
-
|
|
1611
|
-
def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
1612
|
-
type: str, target: str, node: pending_xref, contnode: Element,
|
|
1613
|
-
) -> Element | None:
|
|
1614
|
-
modname = node.get('py:module')
|
|
1615
|
-
clsname = node.get('py:class')
|
|
1616
|
-
searchmode = 1 if node.hasattr('refspecific') else 0
|
|
1617
|
-
matches = self.find_obj(env, modname, clsname, target,
|
|
1618
|
-
type, searchmode)
|
|
1619
|
-
|
|
1620
|
-
if not matches and type == 'attr':
|
|
1621
|
-
# fallback to meth (for property; Sphinx 2.4.x)
|
|
1622
|
-
# this ensures that `:attr:` role continues to refer to the old property entry
|
|
1623
|
-
# that defined by ``method`` directive in old reST files.
|
|
1624
|
-
matches = self.find_obj(env, modname, clsname, target, 'meth', searchmode)
|
|
1625
|
-
if not matches and type == 'meth':
|
|
1626
|
-
# fallback to attr (for property)
|
|
1627
|
-
# this ensures that `:meth:` in the old reST files can refer to the property
|
|
1628
|
-
# entry that defined by ``property`` directive.
|
|
1629
|
-
#
|
|
1630
|
-
# Note: _prop is a secret role only for internal look-up.
|
|
1631
|
-
matches = self.find_obj(env, modname, clsname, target, '_prop', searchmode)
|
|
1632
|
-
|
|
1633
|
-
if not matches:
|
|
1634
|
-
return None
|
|
1635
|
-
elif len(matches) > 1:
|
|
1636
|
-
canonicals = [m for m in matches if not m[1].aliased]
|
|
1637
|
-
if len(canonicals) == 1:
|
|
1638
|
-
matches = canonicals
|
|
1639
|
-
else:
|
|
1640
|
-
logger.warning(__('more than one target found for cross-reference %r: %s'),
|
|
1641
|
-
target, ', '.join(match[0] for match in matches),
|
|
1642
|
-
type='ref', subtype='python', location=node)
|
|
1643
|
-
name, obj = matches[0]
|
|
1644
|
-
|
|
1645
|
-
if obj[2] == 'module':
|
|
1646
|
-
return self._make_module_refnode(builder, fromdocname, name, contnode)
|
|
1647
|
-
else:
|
|
1648
|
-
# determine the content of the reference by conditions
|
|
1649
|
-
content = find_pending_xref_condition(node, 'resolved')
|
|
1650
|
-
if content:
|
|
1651
|
-
children = content.children
|
|
1652
|
-
else:
|
|
1653
|
-
# if not found, use contnode
|
|
1654
|
-
children = [contnode]
|
|
1655
|
-
|
|
1656
|
-
return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)
|
|
1657
|
-
|
|
1658
|
-
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
|
1659
|
-
target: str, node: pending_xref, contnode: Element,
|
|
1660
|
-
) -> list[tuple[str, Element]]:
|
|
1661
|
-
modname = node.get('py:module')
|
|
1662
|
-
clsname = node.get('py:class')
|
|
1663
|
-
results: list[tuple[str, Element]] = []
|
|
1664
|
-
|
|
1665
|
-
# always search in "refspecific" mode with the :any: role
|
|
1666
|
-
matches = self.find_obj(env, modname, clsname, target, None, 1)
|
|
1667
|
-
multiple_matches = len(matches) > 1
|
|
1668
|
-
|
|
1669
|
-
for name, obj in matches:
|
|
1670
|
-
|
|
1671
|
-
if multiple_matches and obj.aliased:
|
|
1672
|
-
# Skip duplicated matches
|
|
1673
|
-
continue
|
|
1674
|
-
|
|
1675
|
-
if obj[2] == 'module':
|
|
1676
|
-
results.append(('py:mod',
|
|
1677
|
-
self._make_module_refnode(builder, fromdocname,
|
|
1678
|
-
name, contnode)))
|
|
1679
|
-
else:
|
|
1680
|
-
# determine the content of the reference by conditions
|
|
1681
|
-
content = find_pending_xref_condition(node, 'resolved')
|
|
1682
|
-
if content:
|
|
1683
|
-
children = content.children
|
|
1684
|
-
else:
|
|
1685
|
-
# if not found, use contnode
|
|
1686
|
-
children = [contnode]
|
|
1687
|
-
|
|
1688
|
-
role = 'py:' + self.role_for_objtype(obj[2]) # type: ignore[operator]
|
|
1689
|
-
results.append((role, make_refnode(builder, fromdocname, obj[0], obj[1],
|
|
1690
|
-
children, name)))
|
|
1691
|
-
return results
|
|
1692
|
-
|
|
1693
|
-
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
|
|
1694
|
-
contnode: Node) -> Element:
|
|
1695
|
-
# get additional info for modules
|
|
1696
|
-
module = self.modules[name]
|
|
1697
|
-
title = name
|
|
1698
|
-
if module.synopsis:
|
|
1699
|
-
title += ': ' + module.synopsis
|
|
1700
|
-
if module.deprecated:
|
|
1701
|
-
title += _(' (deprecated)')
|
|
1702
|
-
if module.platform:
|
|
1703
|
-
title += ' (' + module.platform + ')'
|
|
1704
|
-
return make_refnode(builder, fromdocname, module.docname, module.node_id,
|
|
1705
|
-
contnode, title)
|
|
1706
|
-
|
|
1707
|
-
def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
|
|
1708
|
-
for modname, mod in self.modules.items():
|
|
1709
|
-
yield (modname, modname, 'module', mod.docname, mod.node_id, 0)
|
|
1710
|
-
for refname, obj in self.objects.items():
|
|
1711
|
-
if obj.objtype != 'module': # modules are already handled
|
|
1712
|
-
if obj.aliased:
|
|
1713
|
-
# aliased names are not full-text searchable.
|
|
1714
|
-
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, -1)
|
|
1715
|
-
else:
|
|
1716
|
-
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
|
|
1717
|
-
|
|
1718
|
-
def get_full_qualified_name(self, node: Element) -> str | None:
|
|
1719
|
-
modname = node.get('py:module')
|
|
1720
|
-
clsname = node.get('py:class')
|
|
1721
|
-
target = node.get('reftarget')
|
|
1722
|
-
if target is None:
|
|
1723
|
-
return None
|
|
1724
|
-
else:
|
|
1725
|
-
return '.'.join(filter(None, [modname, clsname, target]))
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
def builtin_resolver(app: Sphinx, env: BuildEnvironment,
|
|
1729
|
-
node: pending_xref, contnode: Element) -> Element | None:
|
|
1730
|
-
"""Do not emit nitpicky warnings for built-in types."""
|
|
1731
|
-
def istyping(s: str) -> bool:
|
|
1732
|
-
if s.startswith('typing.'):
|
|
1733
|
-
s = s.split('.', 1)[1]
|
|
1734
|
-
|
|
1735
|
-
return s in typing.__all__
|
|
1736
|
-
|
|
1737
|
-
if node.get('refdomain') != 'py':
|
|
1738
|
-
return None
|
|
1739
|
-
elif node.get('reftype') in ('class', 'obj') and node.get('reftarget') == 'None':
|
|
1740
|
-
return contnode
|
|
1741
|
-
elif node.get('reftype') in ('class', 'obj', 'exc'):
|
|
1742
|
-
reftarget = node.get('reftarget')
|
|
1743
|
-
if inspect.isclass(getattr(builtins, reftarget, None)):
|
|
1744
|
-
# built-in class
|
|
1745
|
-
return contnode
|
|
1746
|
-
if istyping(reftarget):
|
|
1747
|
-
# typing class
|
|
1748
|
-
return contnode
|
|
1749
|
-
|
|
1750
|
-
return None
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
def setup(app: Sphinx) -> dict[str, Any]:
|
|
1754
|
-
app.setup_extension('sphinx.directives')
|
|
1755
|
-
|
|
1756
|
-
app.add_domain(PythonDomain)
|
|
1757
|
-
app.add_config_value('python_use_unqualified_type_names', False, 'env')
|
|
1758
|
-
app.add_config_value('python_maximum_signature_line_length', None, 'env',
|
|
1759
|
-
types={int, None})
|
|
1760
|
-
app.add_config_value('python_display_short_literal_types', False, 'env')
|
|
1761
|
-
app.connect('object-description-transform', filter_meta_fields)
|
|
1762
|
-
app.connect('missing-reference', builtin_resolver, priority=900)
|
|
1763
|
-
|
|
1764
|
-
return {
|
|
1765
|
-
'version': 'builtin',
|
|
1766
|
-
'env_version': 4,
|
|
1767
|
-
'parallel_read_safe': True,
|
|
1768
|
-
'parallel_write_safe': True,
|
|
1769
|
-
}
|