Sphinx 7.3.7__py3-none-any.whl → 7.4.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 +5 -6
- sphinx/_cli/__init__.py +296 -0
- sphinx/_cli/util/__init__.py +0 -0
- sphinx/_cli/util/colour.py +103 -0
- sphinx/_cli/util/errors.py +165 -0
- sphinx/application.py +78 -43
- sphinx/builders/__init__.py +59 -15
- sphinx/builders/_epub_base.py +11 -5
- sphinx/builders/changes.py +2 -2
- sphinx/builders/epub3.py +2 -2
- sphinx/builders/gettext.py +10 -10
- sphinx/builders/html/__init__.py +56 -54
- sphinx/builders/latex/__init__.py +5 -5
- sphinx/builders/latex/constants.py +5 -0
- sphinx/builders/linkcheck.py +73 -38
- sphinx/builders/texinfo.py +1 -1
- sphinx/cmd/build.py +1 -1
- sphinx/cmd/quickstart.py +11 -11
- sphinx/config.py +57 -38
- sphinx/directives/__init__.py +7 -9
- sphinx/directives/code.py +12 -15
- sphinx/directives/other.py +12 -15
- sphinx/directives/patches.py +26 -0
- sphinx/domains/__init__.py +1 -1
- sphinx/domains/c/__init__.py +5 -5
- sphinx/domains/c/_ast.py +436 -12
- sphinx/domains/c/_symbol.py +89 -134
- sphinx/domains/changeset.py +3 -4
- sphinx/domains/cpp/__init__.py +5 -6
- sphinx/domains/cpp/_ast.py +822 -25
- sphinx/domains/cpp/_symbol.py +3 -0
- sphinx/domains/javascript.py +3 -6
- sphinx/domains/math.py +3 -2
- sphinx/domains/python/__init__.py +44 -6
- sphinx/domains/python/_object.py +7 -5
- sphinx/domains/rst.py +2 -2
- sphinx/domains/std/__init__.py +95 -14
- sphinx/environment/__init__.py +35 -15
- sphinx/environment/adapters/indexentries.py +71 -24
- sphinx/environment/adapters/toctree.py +1 -1
- sphinx/environment/collectors/__init__.py +18 -4
- sphinx/environment/collectors/asset.py +4 -4
- sphinx/environment/collectors/toctree.py +27 -14
- sphinx/events.py +7 -6
- sphinx/ext/apidoc.py +377 -170
- sphinx/ext/autodoc/__init__.py +13 -13
- sphinx/ext/autodoc/directive.py +10 -13
- sphinx/ext/autodoc/mock.py +10 -7
- sphinx/ext/autodoc/preserve_defaults.py +1 -1
- sphinx/ext/autodoc/typehints.py +2 -2
- sphinx/ext/autosummary/__init__.py +15 -9
- sphinx/ext/autosummary/generate.py +270 -154
- sphinx/ext/coverage.py +108 -18
- sphinx/ext/duration.py +10 -3
- sphinx/ext/extlinks.py +3 -2
- sphinx/ext/graphviz.py +3 -3
- sphinx/ext/ifconfig.py +1 -2
- sphinx/ext/imgconverter.py +1 -0
- sphinx/ext/imgmath.py +7 -6
- sphinx/ext/inheritance_diagram.py +3 -3
- sphinx/ext/intersphinx/__init__.py +81 -0
- sphinx/ext/intersphinx/__main__.py +10 -0
- sphinx/ext/intersphinx/_cli.py +44 -0
- sphinx/ext/intersphinx/_load.py +253 -0
- sphinx/ext/{intersphinx.py → intersphinx/_resolve.py} +17 -368
- sphinx/ext/intersphinx/_shared.py +53 -0
- sphinx/ext/mathjax.py +1 -1
- sphinx/ext/todo.py +2 -2
- sphinx/io.py +2 -6
- sphinx/locale/__init__.py +1 -5
- sphinx/locale/ar/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +678 -471
- sphinx/locale/bg/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +684 -476
- sphinx/locale/bn/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +679 -472
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +681 -474
- sphinx/locale/cak/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +678 -471
- sphinx/locale/cs/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +679 -472
- sphinx/locale/cy/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +679 -472
- sphinx/locale/da/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +679 -472
- sphinx/locale/de/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +679 -472
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +678 -471
- sphinx/locale/el/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/eo/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/es/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/et/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/eu/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/fa/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/fi/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +700 -493
- 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 +725 -518
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +701 -494
- 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 +700 -493
- sphinx/locale/hi/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/hr/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/hu/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/id/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/is/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/it/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +708 -500
- sphinx/locale/ja/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ka/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/ko/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/lt/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/lv/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/mk/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ne/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/nl/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/pt/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +705 -498
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ro/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +890 -680
- sphinx/locale/si/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/sk/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/sl/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/sphinx.pot +702 -494
- 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 +704 -497
- sphinx/locale/sr/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +700 -493
- 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.js +1 -1
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +1016 -808
- sphinx/locale/te/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/tr/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/ur/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/vi/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +701 -494
- sphinx/locale/yue/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +700 -493
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +704 -496
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +700 -493
- 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 +729 -522
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +700 -493
- sphinx/roles.py +1 -1
- sphinx/search/__init__.py +17 -9
- sphinx/templates/quickstart/{root_doc.rst_t → root_doc.rst.jinja} +7 -10
- sphinx/testing/fixtures.py +22 -20
- sphinx/testing/path.py +6 -2
- sphinx/testing/util.py +8 -13
- sphinx/texinputs/sphinx.sty +449 -332
- sphinx/texinputs/sphinxlatexadmonitions.sty +209 -66
- sphinx/texinputs/sphinxlatexliterals.sty +9 -16
- sphinx/texinputs/sphinxlatexstyletext.sty +4 -38
- sphinx/texinputs/sphinxlatextables.sty +6 -14
- sphinx/texinputs/sphinxpackageboxes.sty +15 -42
- sphinx/texinputs/sphinxpackagefootnote.sty +4 -3
- sphinx/themes/agogo/layout.html +3 -3
- sphinx/themes/basic/genindex-single.html +2 -1
- sphinx/themes/basic/layout.html +3 -6
- sphinx/themes/basic/static/searchtools.js +4 -3
- sphinx/themes/haiku/layout.html +4 -4
- sphinx/themes/pyramid/layout.html +1 -1
- sphinx/themes/scrolls/layout.html +2 -2
- sphinx/theming.py +3 -3
- sphinx/transforms/__init__.py +34 -20
- sphinx/transforms/i18n.py +8 -7
- sphinx/transforms/post_transforms/__init__.py +1 -1
- sphinx/transforms/post_transforms/images.py +7 -10
- sphinx/util/_pathlib.py +2 -2
- sphinx/util/cfamily.py +52 -30
- sphinx/util/console.py +1 -1
- sphinx/util/display.py +16 -11
- sphinx/util/docutils.py +88 -40
- sphinx/util/fileutil.py +15 -3
- sphinx/util/images.py +1 -0
- sphinx/util/inspect.py +66 -22
- sphinx/util/inventory.py +15 -0
- sphinx/util/logging.py +14 -21
- sphinx/util/math.py +3 -1
- sphinx/util/nodes.py +9 -12
- sphinx/util/osutil.py +5 -5
- sphinx/util/parsing.py +93 -0
- sphinx/util/tags.py +71 -47
- sphinx/util/typing.py +265 -143
- sphinx/versioning.py +17 -17
- sphinx/writers/html5.py +26 -19
- sphinx/writers/latex.py +60 -30
- sphinx/writers/manpage.py +4 -3
- sphinx/writers/texinfo.py +19 -14
- {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/METADATA +21 -20
- sphinx-7.4.1.dist-info/RECORD +591 -0
- sphinx-7.3.7.dist-info/RECORD +0 -581
- /sphinx/templates/apidoc/{module.rst_t → module.rst.jinja} +0 -0
- /sphinx/templates/apidoc/{package.rst_t → package.rst.jinja} +0 -0
- /sphinx/templates/apidoc/{toc.rst_t → toc.rst.jinja} +0 -0
- /sphinx/templates/epub3/{content.opf_t → content.opf.jinja} +0 -0
- /sphinx/templates/epub3/{nav.xhtml_t → nav.xhtml.jinja} +0 -0
- /sphinx/templates/epub3/{toc.ncx_t → toc.ncx.jinja} +0 -0
- /sphinx/templates/gettext/{message.pot_t → message.pot.jinja} +0 -0
- /sphinx/templates/imgmath/{preview.tex_t → preview.tex.jinja} +0 -0
- /sphinx/templates/imgmath/{template.tex_t → template.tex.jinja} +0 -0
- /sphinx/templates/latex/{latex.tex_t → latex.tex.jinja} +0 -0
- /sphinx/templates/latex/{longtable.tex_t → longtable.tex.jinja} +0 -0
- /sphinx/templates/latex/{sphinxmessages.sty_t → sphinxmessages.sty.jinja} +0 -0
- /sphinx/templates/latex/{tabular.tex_t → tabular.tex.jinja} +0 -0
- /sphinx/templates/latex/{tabulary.tex_t → tabulary.tex.jinja} +0 -0
- /sphinx/templates/quickstart/{Makefile_t → Makefile.jinja} +0 -0
- /sphinx/templates/quickstart/{Makefile.new_t → Makefile.new.jinja} +0 -0
- /sphinx/templates/quickstart/{conf.py_t → conf.py.jinja} +0 -0
- /sphinx/templates/quickstart/{make.bat_t → make.bat.jinja} +0 -0
- /sphinx/templates/quickstart/{make.bat.new_t → make.bat.new.jinja} +0 -0
- /sphinx/texinputs/{Makefile_t → Makefile.jinja} +0 -0
- /sphinx/texinputs/{latexmkjarc_t → latexmkjarc.jinja} +0 -0
- /sphinx/texinputs/{latexmkrc_t → latexmkrc.jinja} +0 -0
- /sphinx/texinputs/{make.bat_t → make.bat.jinja} +0 -0
- /sphinx/texinputs_win/{Makefile_t → Makefile.jinja} +0 -0
- /sphinx/themes/agogo/static/{agogo.css_t → agogo.css.jinja} +0 -0
- /sphinx/themes/basic/static/{basic.css_t → basic.css.jinja} +0 -0
- /sphinx/themes/basic/static/{documentation_options.js_t → documentation_options.js.jinja} +0 -0
- /sphinx/themes/basic/static/{language_data.js_t → language_data.js.jinja} +0 -0
- /sphinx/themes/bizstyle/static/{bizstyle.css_t → bizstyle.css.jinja} +0 -0
- /sphinx/themes/bizstyle/static/{bizstyle.js_t → bizstyle.js.jinja} +0 -0
- /sphinx/themes/classic/static/{classic.css_t → classic.css.jinja} +0 -0
- /sphinx/themes/classic/static/{sidebar.js_t → sidebar.js.jinja} +0 -0
- /sphinx/themes/epub/static/{epub.css_t → epub.css.jinja} +0 -0
- /sphinx/themes/haiku/static/{haiku.css_t → haiku.css.jinja} +0 -0
- /sphinx/themes/nature/static/{nature.css_t → nature.css.jinja} +0 -0
- /sphinx/themes/nonav/static/{nonav.css_t → nonav.css.jinja} +0 -0
- /sphinx/themes/pyramid/static/{epub.css_t → epub.css.jinja} +0 -0
- /sphinx/themes/pyramid/static/{pyramid.css_t → pyramid.css.jinja} +0 -0
- /sphinx/themes/scrolls/static/{scrolls.css_t → scrolls.css.jinja} +0 -0
- /sphinx/themes/sphinxdoc/static/{sphinxdoc.css_t → sphinxdoc.css.jinja} +0 -0
- /sphinx/themes/traditional/static/{traditional.css_t → traditional.css.jinja} +0 -0
- {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/LICENSE.rst +0 -0
- {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/WHEEL +0 -0
- {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/entry_points.txt +0 -0
sphinx/util/typing.py
CHANGED
|
@@ -8,23 +8,45 @@ import typing
|
|
|
8
8
|
from collections.abc import Sequence
|
|
9
9
|
from contextvars import Context, ContextVar, Token
|
|
10
10
|
from struct import Struct
|
|
11
|
-
from typing import
|
|
11
|
+
from typing import (
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
Annotated,
|
|
14
|
+
Any,
|
|
15
|
+
Callable,
|
|
16
|
+
ForwardRef,
|
|
17
|
+
TypedDict,
|
|
18
|
+
TypeVar,
|
|
19
|
+
Union,
|
|
20
|
+
)
|
|
12
21
|
|
|
13
22
|
from docutils import nodes
|
|
14
23
|
from docutils.parsers.rst.states import Inliner
|
|
15
24
|
|
|
16
25
|
if TYPE_CHECKING:
|
|
17
|
-
import
|
|
26
|
+
from collections.abc import Mapping
|
|
27
|
+
from typing import Final, Literal, Protocol
|
|
28
|
+
|
|
29
|
+
from typing_extensions import TypeAlias, TypeIs
|
|
18
30
|
|
|
19
31
|
from sphinx.application import Sphinx
|
|
20
32
|
|
|
33
|
+
_RestifyMode: TypeAlias = Literal[
|
|
34
|
+
'fully-qualified-except-typing',
|
|
35
|
+
'smart',
|
|
36
|
+
]
|
|
37
|
+
_StringifyMode: TypeAlias = Literal[
|
|
38
|
+
'fully-qualified-except-typing',
|
|
39
|
+
'fully-qualified',
|
|
40
|
+
'smart',
|
|
41
|
+
]
|
|
42
|
+
|
|
21
43
|
if sys.version_info >= (3, 10):
|
|
22
44
|
from types import UnionType
|
|
23
45
|
else:
|
|
24
46
|
UnionType = None
|
|
25
47
|
|
|
26
48
|
# classes that have an incorrect .__module__ attribute
|
|
27
|
-
_INVALID_BUILTIN_CLASSES = {
|
|
49
|
+
_INVALID_BUILTIN_CLASSES: Final[Mapping[object, str]] = {
|
|
28
50
|
Context: 'contextvars.Context', # Context.__module__ == '_contextvars'
|
|
29
51
|
ContextVar: 'contextvars.ContextVar', # ContextVar.__module__ == '_contextvars'
|
|
30
52
|
Token: 'contextvars.Token', # Token.__module__ == '_contextvars'
|
|
@@ -71,8 +93,25 @@ NoneType = type(None)
|
|
|
71
93
|
PathMatcher = Callable[[str], bool]
|
|
72
94
|
|
|
73
95
|
# common role functions
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
if TYPE_CHECKING:
|
|
97
|
+
class RoleFunction(Protocol):
|
|
98
|
+
def __call__(
|
|
99
|
+
self,
|
|
100
|
+
name: str,
|
|
101
|
+
rawtext: str,
|
|
102
|
+
text: str,
|
|
103
|
+
lineno: int,
|
|
104
|
+
inliner: Inliner,
|
|
105
|
+
/,
|
|
106
|
+
options: dict[str, Any] | None = None,
|
|
107
|
+
content: Sequence[str] = (),
|
|
108
|
+
) -> tuple[list[nodes.Node], list[nodes.system_message]]:
|
|
109
|
+
...
|
|
110
|
+
else:
|
|
111
|
+
RoleFunction = Callable[
|
|
112
|
+
[str, str, str, int, Inliner, dict[str, Any], Sequence[str]],
|
|
113
|
+
tuple[list[nodes.Node], list[nodes.system_message]],
|
|
114
|
+
]
|
|
76
115
|
|
|
77
116
|
# A option spec for directive
|
|
78
117
|
OptionSpec = dict[str, Callable[[str], Any]]
|
|
@@ -115,7 +154,9 @@ if TYPE_CHECKING:
|
|
|
115
154
|
|
|
116
155
|
|
|
117
156
|
def get_type_hints(
|
|
118
|
-
obj: Any,
|
|
157
|
+
obj: Any,
|
|
158
|
+
globalns: dict[str, Any] | None = None,
|
|
159
|
+
localns: dict[str, Any] | None = None,
|
|
119
160
|
) -> dict[str, Any]:
|
|
120
161
|
"""Return a dictionary containing type hints for a function, method, module or class
|
|
121
162
|
object.
|
|
@@ -147,8 +188,40 @@ def is_system_TypeVar(typ: Any) -> bool:
|
|
|
147
188
|
return modname == 'typing' and isinstance(typ, TypeVar)
|
|
148
189
|
|
|
149
190
|
|
|
150
|
-
def
|
|
151
|
-
"""
|
|
191
|
+
def _is_annotated_form(obj: Any) -> TypeIs[Annotated[Any, ...]]:
|
|
192
|
+
"""Check if *obj* is an annotated type."""
|
|
193
|
+
return typing.get_origin(obj) is Annotated or str(obj).startswith('typing.Annotated')
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _is_unpack_form(obj: Any) -> bool:
|
|
197
|
+
"""Check if the object is :class:`typing.Unpack` or equivalent."""
|
|
198
|
+
if sys.version_info >= (3, 11):
|
|
199
|
+
from typing import Unpack
|
|
200
|
+
|
|
201
|
+
# typing_extensions.Unpack != typing.Unpack for 3.11, but we assume
|
|
202
|
+
# that typing_extensions.Unpack should not be used in that case
|
|
203
|
+
return typing.get_origin(obj) is Unpack
|
|
204
|
+
|
|
205
|
+
# 3.9 and 3.10 require typing_extensions.Unpack
|
|
206
|
+
origin = typing.get_origin(obj)
|
|
207
|
+
return (
|
|
208
|
+
getattr(origin, '__module__', None) == 'typing_extensions'
|
|
209
|
+
and _typing_internal_name(origin) == 'Unpack'
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _typing_internal_name(obj: Any) -> str | None:
|
|
214
|
+
if sys.version_info[:2] >= (3, 10):
|
|
215
|
+
try:
|
|
216
|
+
return obj.__name__
|
|
217
|
+
except AttributeError:
|
|
218
|
+
# e.g. ParamSpecArgs, ParamSpecKwargs
|
|
219
|
+
return ''
|
|
220
|
+
return getattr(obj, '_name', None)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> str:
|
|
224
|
+
"""Convert a type-like object to a reST reference.
|
|
152
225
|
|
|
153
226
|
:param mode: Specify a method how annotations will be stringified.
|
|
154
227
|
|
|
@@ -161,31 +234,53 @@ def restify(cls: type | None, mode: str = 'fully-qualified-except-typing') -> st
|
|
|
161
234
|
from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
|
|
162
235
|
from sphinx.util import inspect # lazy loading
|
|
163
236
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
237
|
+
valid_modes = {'fully-qualified-except-typing', 'smart'}
|
|
238
|
+
if mode not in valid_modes:
|
|
239
|
+
valid = ', '.join(map(repr, sorted(valid_modes)))
|
|
240
|
+
msg = f'mode must be one of {valid}; got {mode!r}'
|
|
241
|
+
raise ValueError(msg)
|
|
242
|
+
|
|
243
|
+
# things that are not types
|
|
244
|
+
if cls is None or cls == NoneType:
|
|
245
|
+
return ':py:obj:`None`'
|
|
246
|
+
if cls is Ellipsis:
|
|
247
|
+
return '...'
|
|
248
|
+
if isinstance(cls, str):
|
|
249
|
+
return cls
|
|
250
|
+
|
|
251
|
+
cls_module_is_typing = getattr(cls, '__module__', '') == 'typing'
|
|
252
|
+
|
|
253
|
+
# If the mode is 'smart', we always use '~'.
|
|
254
|
+
# If the mode is 'fully-qualified-except-typing',
|
|
255
|
+
# we use '~' only for the objects in the ``typing`` module.
|
|
256
|
+
module_prefix = '~' if mode == 'smart' or cls_module_is_typing else ''
|
|
168
257
|
|
|
169
258
|
try:
|
|
170
|
-
if cls
|
|
171
|
-
return ':py:
|
|
172
|
-
elif cls is Ellipsis:
|
|
173
|
-
return '...'
|
|
174
|
-
elif isinstance(cls, str):
|
|
175
|
-
return cls
|
|
176
|
-
elif ismockmodule(cls):
|
|
177
|
-
return f':py:class:`{modprefix}{cls.__name__}`'
|
|
259
|
+
if ismockmodule(cls):
|
|
260
|
+
return f':py:class:`{module_prefix}{cls.__name__}`'
|
|
178
261
|
elif ismock(cls):
|
|
179
|
-
return f':py:class:`{
|
|
262
|
+
return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
180
263
|
elif is_invalid_builtin_class(cls):
|
|
181
|
-
|
|
264
|
+
# The above predicate never raises TypeError but should not be
|
|
265
|
+
# evaluated before determining whether *cls* is a mocked object
|
|
266
|
+
# or not; instead of two try-except blocks, we keep it here.
|
|
267
|
+
return f':py:class:`{module_prefix}{_INVALID_BUILTIN_CLASSES[cls]}`'
|
|
268
|
+
elif _is_annotated_form(cls):
|
|
269
|
+
args = restify(cls.__args__[0], mode)
|
|
270
|
+
meta = ', '.join(map(repr, cls.__metadata__))
|
|
271
|
+
if sys.version_info[:2] <= (3, 11):
|
|
272
|
+
# Hardcoded to fix errors on Python 3.11 and earlier.
|
|
273
|
+
return fr':py:class:`~typing.Annotated`\ [{args}, {meta}]'
|
|
274
|
+
return (f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
275
|
+
fr'\ [{args}, {meta}]')
|
|
182
276
|
elif inspect.isNewType(cls):
|
|
183
277
|
if sys.version_info[:2] >= (3, 10):
|
|
184
278
|
# newtypes have correct module info since Python 3.10+
|
|
185
|
-
return f':py:class:`{
|
|
186
|
-
|
|
187
|
-
return f':py:class:`{cls.__name__}`'
|
|
279
|
+
return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
280
|
+
return f':py:class:`{cls.__name__}`'
|
|
188
281
|
elif UnionType and isinstance(cls, UnionType):
|
|
282
|
+
# Union types (PEP 585) retain their definition order when they
|
|
283
|
+
# are printed natively and ``None``-like types are kept as is.
|
|
189
284
|
return ' | '.join(restify(a, mode) for a in cls.__args__)
|
|
190
285
|
elif cls.__module__ in ('__builtin__', 'builtins'):
|
|
191
286
|
if hasattr(cls, '__args__'):
|
|
@@ -194,73 +289,85 @@ def restify(cls: type | None, mode: str = 'fully-qualified-except-typing') -> st
|
|
|
194
289
|
|
|
195
290
|
concatenated_args = ', '.join(restify(arg, mode) for arg in cls.__args__)
|
|
196
291
|
return fr':py:class:`{cls.__name__}`\ [{concatenated_args}]'
|
|
197
|
-
|
|
198
|
-
return f':py:class:`{cls.__name__}`'
|
|
292
|
+
return f':py:class:`{cls.__name__}`'
|
|
199
293
|
elif (inspect.isgenericalias(cls)
|
|
200
|
-
and
|
|
201
|
-
and cls.__origin__ is Union):
|
|
202
|
-
|
|
294
|
+
and cls_module_is_typing
|
|
295
|
+
and cls.__origin__ is Union):
|
|
296
|
+
# *cls* is defined in ``typing``, and thus ``__args__`` must exist
|
|
297
|
+
return ' | '.join(restify(a, mode) for a in cls.__args__)
|
|
203
298
|
elif inspect.isgenericalias(cls):
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
299
|
+
# A generic alias always has an __origin__, but it is difficult to
|
|
300
|
+
# use a type guard on inspect.isgenericalias()
|
|
301
|
+
# (ideally, we would use ``TypeIs`` introduced in Python 3.13).
|
|
302
|
+
cls_name = _typing_internal_name(cls)
|
|
303
|
+
|
|
304
|
+
if isinstance(cls.__origin__, typing._SpecialForm):
|
|
305
|
+
# ClassVar; Concatenate; Final; Literal; Unpack; TypeGuard; TypeIs
|
|
306
|
+
# Required/NotRequired
|
|
307
|
+
text = restify(cls.__origin__, mode)
|
|
308
|
+
elif cls_name:
|
|
309
|
+
text = f':py:class:`{module_prefix}{cls.__module__}.{cls_name}`'
|
|
212
310
|
else:
|
|
213
|
-
text = restify(cls.__origin__, mode)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if not
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
for a in
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
311
|
+
text = restify(cls.__origin__, mode)
|
|
312
|
+
|
|
313
|
+
__args__ = getattr(cls, '__args__', ())
|
|
314
|
+
if not __args__:
|
|
315
|
+
return text
|
|
316
|
+
if all(map(is_system_TypeVar, __args__)):
|
|
317
|
+
# Don't print the arguments; they're all system defined type variables.
|
|
318
|
+
return text
|
|
319
|
+
|
|
320
|
+
# Callable has special formatting
|
|
321
|
+
if (
|
|
322
|
+
(cls_module_is_typing and _typing_internal_name(cls) == 'Callable')
|
|
323
|
+
or (cls.__module__ == 'collections.abc' and cls.__name__ == 'Callable')
|
|
324
|
+
):
|
|
325
|
+
args = ', '.join(restify(a, mode) for a in __args__[:-1])
|
|
326
|
+
returns = restify(__args__[-1], mode)
|
|
327
|
+
return fr'{text}\ [[{args}], {returns}]'
|
|
328
|
+
|
|
329
|
+
if cls_module_is_typing and _typing_internal_name(cls.__origin__) == 'Literal':
|
|
330
|
+
args = ', '.join(_format_literal_arg_restify(a, mode=mode)
|
|
331
|
+
for a in cls.__args__)
|
|
332
|
+
return fr'{text}\ [{args}]'
|
|
333
|
+
|
|
334
|
+
# generic representation of the parameters
|
|
335
|
+
args = ', '.join(restify(a, mode) for a in __args__)
|
|
336
|
+
return fr'{text}\ [{args}]'
|
|
238
337
|
elif isinstance(cls, typing._SpecialForm):
|
|
239
|
-
|
|
338
|
+
cls_name = _typing_internal_name(cls)
|
|
339
|
+
return f':py:obj:`~{cls.__module__}.{cls_name}`'
|
|
240
340
|
elif sys.version_info[:2] >= (3, 11) and cls is typing.Any:
|
|
241
341
|
# handle bpo-46998
|
|
242
342
|
return f':py:obj:`~{cls.__module__}.{cls.__name__}`'
|
|
243
343
|
elif hasattr(cls, '__qualname__'):
|
|
244
|
-
|
|
245
|
-
return f':py:class:`~{cls.__module__}.{cls.__qualname__}`'
|
|
246
|
-
else:
|
|
247
|
-
return f':py:class:`{modprefix}{cls.__module__}.{cls.__qualname__}`'
|
|
344
|
+
return f':py:class:`{module_prefix}{cls.__module__}.{cls.__qualname__}`'
|
|
248
345
|
elif isinstance(cls, ForwardRef):
|
|
249
346
|
return f':py:class:`{cls.__forward_arg__}`'
|
|
250
347
|
else:
|
|
251
|
-
# not a class (ex. TypeVar)
|
|
252
|
-
|
|
253
|
-
return f':py:obj:`~{cls.__module__}.{cls.__name__}`'
|
|
254
|
-
else:
|
|
255
|
-
return f':py:obj:`{modprefix}{cls.__module__}.{cls.__name__}`'
|
|
348
|
+
# not a class (ex. TypeVar) but should have a __name__
|
|
349
|
+
return f':py:obj:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
256
350
|
except (AttributeError, TypeError):
|
|
257
351
|
return inspect.object_description(cls)
|
|
258
352
|
|
|
259
353
|
|
|
354
|
+
def _format_literal_arg_restify(arg: Any, /, *, mode: str) -> str:
|
|
355
|
+
from sphinx.util.inspect import isenumattribute # lazy loading
|
|
356
|
+
|
|
357
|
+
if isenumattribute(arg):
|
|
358
|
+
enum_cls = arg.__class__
|
|
359
|
+
if mode == 'smart' or enum_cls.__module__ == 'typing':
|
|
360
|
+
# MyEnum.member
|
|
361
|
+
return f':py:attr:`~{enum_cls.__module__}.{enum_cls.__qualname__}.{arg.name}`'
|
|
362
|
+
# module.MyEnum.member
|
|
363
|
+
return f':py:attr:`{enum_cls.__module__}.{enum_cls.__qualname__}.{arg.name}`'
|
|
364
|
+
return repr(arg)
|
|
365
|
+
|
|
366
|
+
|
|
260
367
|
def stringify_annotation(
|
|
261
368
|
annotation: Any,
|
|
262
369
|
/,
|
|
263
|
-
mode:
|
|
370
|
+
mode: _StringifyMode = 'fully-qualified-except-typing',
|
|
264
371
|
) -> str:
|
|
265
372
|
"""Stringify type annotation object.
|
|
266
373
|
|
|
@@ -278,69 +385,76 @@ def stringify_annotation(
|
|
|
278
385
|
from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
|
|
279
386
|
from sphinx.util.inspect import isNewType # lazy loading
|
|
280
387
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
388
|
+
valid_modes = {'fully-qualified-except-typing', 'fully-qualified', 'smart'}
|
|
389
|
+
if mode not in valid_modes:
|
|
390
|
+
valid = ', '.join(map(repr, sorted(valid_modes)))
|
|
391
|
+
msg = f'mode must be one of {valid}; got {mode!r}'
|
|
284
392
|
raise ValueError(msg)
|
|
285
393
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
annotation_qualname = getattr(annotation, '__qualname__', '')
|
|
292
|
-
annotation_module = getattr(annotation, '__module__', '')
|
|
293
|
-
annotation_name = getattr(annotation, '__name__', '')
|
|
294
|
-
annotation_module_is_typing = annotation_module == 'typing'
|
|
295
|
-
|
|
394
|
+
# things that are not types
|
|
395
|
+
if annotation is None or annotation == NoneType:
|
|
396
|
+
return 'None'
|
|
397
|
+
if annotation is Ellipsis:
|
|
398
|
+
return '...'
|
|
296
399
|
if isinstance(annotation, str):
|
|
297
400
|
if annotation.startswith("'") and annotation.endswith("'"):
|
|
298
|
-
#
|
|
401
|
+
# Might be a double Forward-ref'ed type. Go unquoting.
|
|
299
402
|
return annotation[1:-1]
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
403
|
+
return annotation
|
|
404
|
+
if not annotation:
|
|
405
|
+
return repr(annotation)
|
|
406
|
+
|
|
407
|
+
module_prefix = '~' if mode == 'smart' else ''
|
|
408
|
+
|
|
409
|
+
# The values below must be strings if the objects are well-formed.
|
|
410
|
+
annotation_qualname: str = getattr(annotation, '__qualname__', '')
|
|
411
|
+
annotation_module: str = getattr(annotation, '__module__', '')
|
|
412
|
+
annotation_name: str = getattr(annotation, '__name__', '')
|
|
413
|
+
annotation_module_is_typing = annotation_module == 'typing'
|
|
414
|
+
|
|
415
|
+
# Extract the annotation's base type by considering formattable cases
|
|
416
|
+
if isinstance(annotation, TypeVar) and not _is_unpack_form(annotation):
|
|
417
|
+
# typing_extensions.Unpack is incorrectly determined as a TypeVar
|
|
303
418
|
if annotation_module_is_typing and mode in {'fully-qualified-except-typing', 'smart'}:
|
|
304
419
|
return annotation_name
|
|
305
|
-
|
|
306
|
-
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
420
|
+
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
307
421
|
elif isNewType(annotation):
|
|
308
422
|
if sys.version_info[:2] >= (3, 10):
|
|
309
423
|
# newtypes have correct module info since Python 3.10+
|
|
310
424
|
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
311
|
-
|
|
312
|
-
return annotation_name
|
|
313
|
-
elif not annotation:
|
|
314
|
-
return repr(annotation)
|
|
315
|
-
elif annotation is NoneType:
|
|
316
|
-
return 'None'
|
|
425
|
+
return annotation_name
|
|
317
426
|
elif ismockmodule(annotation):
|
|
318
427
|
return module_prefix + annotation_name
|
|
319
428
|
elif ismock(annotation):
|
|
320
429
|
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
321
430
|
elif is_invalid_builtin_class(annotation):
|
|
322
431
|
return module_prefix + _INVALID_BUILTIN_CLASSES[annotation]
|
|
323
|
-
elif
|
|
432
|
+
elif _is_annotated_form(annotation): # for py39+
|
|
324
433
|
pass
|
|
325
434
|
elif annotation_module == 'builtins' and annotation_qualname:
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return repr(annotation)
|
|
329
|
-
|
|
330
|
-
concatenated_args = ', '.join(stringify_annotation(arg, mode) for arg in args)
|
|
331
|
-
return f'{annotation_qualname}[{concatenated_args}]'
|
|
332
|
-
else:
|
|
435
|
+
args = getattr(annotation, '__args__', None)
|
|
436
|
+
if args is None:
|
|
333
437
|
return annotation_qualname
|
|
334
|
-
|
|
335
|
-
|
|
438
|
+
|
|
439
|
+
# PEP 585 generic
|
|
440
|
+
if not args: # Empty tuple, list, ...
|
|
441
|
+
return repr(annotation)
|
|
442
|
+
|
|
443
|
+
concatenated_args = ', '.join(stringify_annotation(arg, mode) for arg in args)
|
|
444
|
+
return f'{annotation_qualname}[{concatenated_args}]'
|
|
445
|
+
else:
|
|
446
|
+
# add other special cases that can be directly formatted
|
|
447
|
+
pass
|
|
336
448
|
|
|
337
449
|
module_prefix = f'{annotation_module}.'
|
|
338
|
-
annotation_forward_arg = getattr(annotation, '__forward_arg__', None)
|
|
450
|
+
annotation_forward_arg: str | None = getattr(annotation, '__forward_arg__', None)
|
|
339
451
|
if annotation_qualname or (annotation_module_is_typing and not annotation_forward_arg):
|
|
340
452
|
if mode == 'smart':
|
|
341
|
-
module_prefix = '~'
|
|
453
|
+
module_prefix = f'~{module_prefix}'
|
|
342
454
|
if annotation_module_is_typing and mode == 'fully-qualified-except-typing':
|
|
343
455
|
module_prefix = ''
|
|
456
|
+
elif _is_unpack_form(annotation) and annotation_module == 'typing_extensions':
|
|
457
|
+
module_prefix = '~' if mode == 'smart' else ''
|
|
344
458
|
else:
|
|
345
459
|
module_prefix = ''
|
|
346
460
|
|
|
@@ -349,12 +463,13 @@ def stringify_annotation(
|
|
|
349
463
|
# handle ForwardRefs
|
|
350
464
|
qualname = annotation_forward_arg
|
|
351
465
|
else:
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
qualname = _name
|
|
466
|
+
if internal_name := _typing_internal_name(annotation):
|
|
467
|
+
qualname = internal_name
|
|
355
468
|
elif annotation_qualname:
|
|
356
469
|
qualname = annotation_qualname
|
|
357
470
|
else:
|
|
471
|
+
# in this case, we know that the annotation is a member
|
|
472
|
+
# of ``typing`` and all of them define ``__origin__``
|
|
358
473
|
qualname = stringify_annotation(
|
|
359
474
|
annotation.__origin__, 'fully-qualified-except-typing',
|
|
360
475
|
).replace('typing.', '') # ex. Union
|
|
@@ -370,36 +485,38 @@ def stringify_annotation(
|
|
|
370
485
|
# only make them appear twice
|
|
371
486
|
return repr(annotation)
|
|
372
487
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
488
|
+
# Process the generic arguments (if any).
|
|
489
|
+
# They must be a list or a tuple, otherwise they are considered 'broken'.
|
|
490
|
+
annotation_args = getattr(annotation, '__args__', ())
|
|
491
|
+
if annotation_args and isinstance(annotation_args, (list, tuple)):
|
|
492
|
+
if (
|
|
493
|
+
qualname in {'Union', 'types.UnionType'}
|
|
494
|
+
and all(getattr(a, '__origin__', ...) is typing.Literal for a in annotation_args)
|
|
495
|
+
):
|
|
496
|
+
# special case to flatten a Union of Literals into a literal
|
|
497
|
+
flattened_args = typing.Literal[annotation_args].__args__ # type: ignore[attr-defined]
|
|
498
|
+
args = ', '.join(_format_literal_arg_stringify(a, mode=mode)
|
|
499
|
+
for a in flattened_args)
|
|
500
|
+
return f'{module_prefix}Literal[{args}]'
|
|
501
|
+
if qualname in {'Optional', 'Union', 'types.UnionType'}:
|
|
379
502
|
return ' | '.join(stringify_annotation(a, mode) for a in annotation_args)
|
|
380
503
|
elif qualname == 'Callable':
|
|
381
504
|
args = ', '.join(stringify_annotation(a, mode) for a in annotation_args[:-1])
|
|
382
505
|
returns = stringify_annotation(annotation_args[-1], mode)
|
|
383
506
|
return f'{module_prefix}Callable[[{args}], {returns}]'
|
|
384
507
|
elif qualname == 'Literal':
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
def format_literal_arg(arg: Any) -> str:
|
|
388
|
-
if isenumattribute(arg):
|
|
389
|
-
enumcls = arg.__class__
|
|
390
|
-
|
|
391
|
-
if mode == 'smart':
|
|
392
|
-
# MyEnum.member
|
|
393
|
-
return f'{enumcls.__qualname__}.{arg.name}'
|
|
394
|
-
|
|
395
|
-
# module.MyEnum.member
|
|
396
|
-
return f'{enumcls.__module__}.{enumcls.__qualname__}.{arg.name}'
|
|
397
|
-
return repr(arg)
|
|
398
|
-
|
|
399
|
-
args = ', '.join(map(format_literal_arg, annotation_args))
|
|
508
|
+
args = ', '.join(_format_literal_arg_stringify(a, mode=mode)
|
|
509
|
+
for a in annotation_args)
|
|
400
510
|
return f'{module_prefix}Literal[{args}]'
|
|
401
|
-
elif
|
|
402
|
-
|
|
511
|
+
elif _is_annotated_form(annotation): # for py39+
|
|
512
|
+
args = stringify_annotation(annotation_args[0], mode)
|
|
513
|
+
meta = ', '.join(map(repr, annotation.__metadata__))
|
|
514
|
+
if sys.version_info[:2] <= (3, 11):
|
|
515
|
+
if mode == 'fully-qualified-except-typing':
|
|
516
|
+
return f'Annotated[{args}, {meta}]'
|
|
517
|
+
module_prefix = module_prefix.replace('builtins', 'typing')
|
|
518
|
+
return f'{module_prefix}Annotated[{args}, {meta}]'
|
|
519
|
+
return f'{module_prefix}Annotated[{args}, {meta}]'
|
|
403
520
|
elif all(is_system_TypeVar(a) for a in annotation_args):
|
|
404
521
|
# Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
|
|
405
522
|
return module_prefix + qualname
|
|
@@ -410,12 +527,17 @@ def stringify_annotation(
|
|
|
410
527
|
return module_prefix + qualname
|
|
411
528
|
|
|
412
529
|
|
|
413
|
-
def
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
530
|
+
def _format_literal_arg_stringify(arg: Any, /, *, mode: str) -> str:
|
|
531
|
+
from sphinx.util.inspect import isenumattribute # lazy loading
|
|
532
|
+
|
|
533
|
+
if isenumattribute(arg):
|
|
534
|
+
enum_cls = arg.__class__
|
|
535
|
+
if mode == 'smart' or enum_cls.__module__ == 'typing':
|
|
536
|
+
# MyEnum.member
|
|
537
|
+
return f'{enum_cls.__qualname__}.{arg.name}'
|
|
538
|
+
# module.MyEnum.member
|
|
539
|
+
return f'{enum_cls.__module__}.{enum_cls.__qualname__}.{arg.name}'
|
|
540
|
+
return repr(arg)
|
|
419
541
|
|
|
420
542
|
|
|
421
543
|
# deprecated name -> (object to return, canonical path or empty string, removal version)
|
sphinx/versioning.py
CHANGED
|
@@ -12,7 +12,7 @@ from uuid import uuid4
|
|
|
12
12
|
from sphinx.transforms import SphinxTransform
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
-
from collections.abc import Iterator
|
|
15
|
+
from collections.abc import Callable, Iterator
|
|
16
16
|
|
|
17
17
|
from docutils.nodes import Node
|
|
18
18
|
|
|
@@ -30,7 +30,7 @@ except ImportError:
|
|
|
30
30
|
VERSIONING_RATIO = 65
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def add_uids(doctree: Node, condition:
|
|
33
|
+
def add_uids(doctree: Node, condition: Callable[[Node], bool]) -> Iterator[Node]:
|
|
34
34
|
"""Add a unique id to every node in the `doctree` which matches the
|
|
35
35
|
condition and yield the nodes.
|
|
36
36
|
|
|
@@ -41,11 +41,11 @@ def add_uids(doctree: Node, condition: Any) -> Iterator[Node]:
|
|
|
41
41
|
A callable which returns either ``True`` or ``False`` for a given node.
|
|
42
42
|
"""
|
|
43
43
|
for node in doctree.findall(condition):
|
|
44
|
-
node.uid = uuid4().hex
|
|
44
|
+
node.uid = uuid4().hex # type: ignore[attr-defined]
|
|
45
45
|
yield node
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
def merge_doctrees(old: Node, new: Node, condition:
|
|
48
|
+
def merge_doctrees(old: Node, new: Node, condition: Callable[[Node], bool]) -> Iterator[Node]:
|
|
49
49
|
"""Merge the `old` doctree with the `new` one while looking at nodes
|
|
50
50
|
matching the `condition`.
|
|
51
51
|
|
|
@@ -68,13 +68,13 @@ def merge_doctrees(old: Node, new: Node, condition: Any) -> Iterator[Node]:
|
|
|
68
68
|
continue
|
|
69
69
|
if not getattr(old_node, 'uid', None):
|
|
70
70
|
# maybe config.gettext_uuid has been changed.
|
|
71
|
-
old_node.uid = uuid4().hex
|
|
71
|
+
old_node.uid = uuid4().hex # type: ignore[union-attr]
|
|
72
72
|
if new_node is None:
|
|
73
73
|
old_nodes.append(old_node)
|
|
74
74
|
continue
|
|
75
|
-
ratio = get_ratio(old_node.rawsource, new_node.rawsource)
|
|
75
|
+
ratio = get_ratio(old_node.rawsource, new_node.rawsource) # type: ignore[union-attr]
|
|
76
76
|
if ratio == 0:
|
|
77
|
-
new_node.uid = old_node.uid
|
|
77
|
+
new_node.uid = old_node.uid # type: ignore[union-attr]
|
|
78
78
|
seen.add(new_node)
|
|
79
79
|
else:
|
|
80
80
|
ratios[old_node, new_node] = ratio
|
|
@@ -85,30 +85,29 @@ def merge_doctrees(old: Node, new: Node, condition: Any) -> Iterator[Node]:
|
|
|
85
85
|
for old_node, new_node in product(old_nodes, new_nodes):
|
|
86
86
|
if new_node in seen or (old_node, new_node) in ratios:
|
|
87
87
|
continue
|
|
88
|
-
ratio = get_ratio(old_node.rawsource, new_node.rawsource)
|
|
88
|
+
ratio = get_ratio(old_node.rawsource, new_node.rawsource) # type: ignore[union-attr]
|
|
89
89
|
if ratio == 0:
|
|
90
|
-
new_node.uid = old_node.uid
|
|
90
|
+
new_node.uid = old_node.uid # type: ignore[union-attr]
|
|
91
91
|
seen.add(new_node)
|
|
92
92
|
else:
|
|
93
93
|
ratios[old_node, new_node] = ratio
|
|
94
94
|
# choose the old node with the best ratio for each new node and set the uid
|
|
95
95
|
# as long as the ratio is under a certain value, in which case we consider
|
|
96
96
|
# them not changed but different
|
|
97
|
-
|
|
98
|
-
for (old_node, new_node), ratio in ratios:
|
|
97
|
+
for (old_node, new_node), ratio in sorted(ratios.items(), key=itemgetter(1)):
|
|
99
98
|
if new_node in seen:
|
|
100
99
|
continue
|
|
101
100
|
else:
|
|
102
101
|
seen.add(new_node)
|
|
103
102
|
if ratio < VERSIONING_RATIO:
|
|
104
|
-
new_node.uid = old_node.uid
|
|
103
|
+
new_node.uid = old_node.uid # type: ignore[union-attr]
|
|
105
104
|
else:
|
|
106
|
-
new_node.uid = uuid4().hex
|
|
105
|
+
new_node.uid = uuid4().hex # type: ignore[union-attr]
|
|
107
106
|
yield new_node
|
|
108
107
|
# create new uuids for any new node we left out earlier, this happens
|
|
109
108
|
# if one or more nodes are simply added.
|
|
110
109
|
for new_node in set(new_nodes) - seen:
|
|
111
|
-
new_node.uid = uuid4().hex
|
|
110
|
+
new_node.uid = uuid4().hex # type: ignore[union-attr]
|
|
112
111
|
yield new_node
|
|
113
112
|
|
|
114
113
|
|
|
@@ -153,7 +152,8 @@ class UIDTransform(SphinxTransform):
|
|
|
153
152
|
def apply(self, **kwargs: Any) -> None:
|
|
154
153
|
env = self.env
|
|
155
154
|
old_doctree = None
|
|
156
|
-
|
|
155
|
+
versioning_condition = env.versioning_condition
|
|
156
|
+
if not versioning_condition:
|
|
157
157
|
return
|
|
158
158
|
|
|
159
159
|
if env.versioning_compare:
|
|
@@ -167,9 +167,9 @@ class UIDTransform(SphinxTransform):
|
|
|
167
167
|
|
|
168
168
|
# add uids for versioning
|
|
169
169
|
if not env.versioning_compare or old_doctree is None:
|
|
170
|
-
list(add_uids(self.document,
|
|
170
|
+
list(add_uids(self.document, versioning_condition))
|
|
171
171
|
else:
|
|
172
|
-
list(merge_doctrees(old_doctree, self.document,
|
|
172
|
+
list(merge_doctrees(old_doctree, self.document, versioning_condition))
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
def setup(app: Sphinx) -> ExtensionMetadata:
|