Sphinx 8.1.2__py3-none-any.whl → 8.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +50 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +134 -61
- sphinx/domains/python/_object.py +155 -68
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +66 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +99 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +281 -142
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
- 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 +2660 -2555
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/sphinx.pot +2069 -1964
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +63 -52
- sphinx/writers/latex.py +83 -67
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +47 -47
- sphinx/writers/text.py +50 -32
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
- sphinx-8.2.0.dist-info/RECORD +606 -0
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- sphinx-8.1.2.dist-info/RECORD +0 -598
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
|
@@ -11,7 +11,7 @@ autosummary directive
|
|
|
11
11
|
The autosummary directive has the form::
|
|
12
12
|
|
|
13
13
|
.. autosummary::
|
|
14
|
-
:
|
|
14
|
+
:signatures: none
|
|
15
15
|
:toctree: generated/
|
|
16
16
|
|
|
17
17
|
module.function_1
|
|
@@ -51,14 +51,13 @@ from __future__ import annotations
|
|
|
51
51
|
import functools
|
|
52
52
|
import inspect
|
|
53
53
|
import operator
|
|
54
|
-
import os
|
|
55
54
|
import posixpath
|
|
56
55
|
import re
|
|
57
56
|
import sys
|
|
58
57
|
from inspect import Parameter
|
|
59
|
-
from
|
|
58
|
+
from pathlib import Path
|
|
60
59
|
from types import ModuleType
|
|
61
|
-
from typing import TYPE_CHECKING,
|
|
60
|
+
from typing import TYPE_CHECKING, cast
|
|
62
61
|
|
|
63
62
|
from docutils import nodes
|
|
64
63
|
from docutils.parsers.rst import directives
|
|
@@ -70,7 +69,7 @@ from sphinx import addnodes
|
|
|
70
69
|
from sphinx.config import Config
|
|
71
70
|
from sphinx.environment import BuildEnvironment
|
|
72
71
|
from sphinx.errors import PycodeError
|
|
73
|
-
from sphinx.ext.autodoc import INSTANCEATTR,
|
|
72
|
+
from sphinx.ext.autodoc import INSTANCEATTR, Options
|
|
74
73
|
from sphinx.ext.autodoc.directive import DocumenterBridge
|
|
75
74
|
from sphinx.ext.autodoc.importer import import_module
|
|
76
75
|
from sphinx.ext.autodoc.mock import mock
|
|
@@ -92,10 +91,12 @@ from sphinx.util.parsing import nested_parse_to_nodes
|
|
|
92
91
|
|
|
93
92
|
if TYPE_CHECKING:
|
|
94
93
|
from collections.abc import Sequence
|
|
94
|
+
from typing import Any, ClassVar
|
|
95
95
|
|
|
96
96
|
from docutils.nodes import Node, system_message
|
|
97
97
|
|
|
98
98
|
from sphinx.application import Sphinx
|
|
99
|
+
from sphinx.ext.autodoc import Documenter
|
|
99
100
|
from sphinx.extension import Extension
|
|
100
101
|
from sphinx.util.typing import ExtensionMetadata, OptionSpec
|
|
101
102
|
from sphinx.writers.html5 import HTML5Translator
|
|
@@ -111,6 +112,7 @@ WELL_KNOWN_ABBREVIATIONS = ('et al.', 'e.g.', 'i.e.')
|
|
|
111
112
|
|
|
112
113
|
# -- autosummary_toc node ------------------------------------------------------
|
|
113
114
|
|
|
115
|
+
|
|
114
116
|
class autosummary_toc(nodes.comment):
|
|
115
117
|
pass
|
|
116
118
|
|
|
@@ -126,23 +128,26 @@ def autosummary_noop(self: nodes.NodeVisitor, node: Node) -> None:
|
|
|
126
128
|
|
|
127
129
|
# -- autosummary_table node ----------------------------------------------------
|
|
128
130
|
|
|
131
|
+
|
|
129
132
|
class autosummary_table(nodes.comment):
|
|
130
133
|
pass
|
|
131
134
|
|
|
132
135
|
|
|
133
|
-
def autosummary_table_visit_html(
|
|
136
|
+
def autosummary_table_visit_html(
|
|
137
|
+
self: HTML5Translator, node: autosummary_table
|
|
138
|
+
) -> None:
|
|
134
139
|
"""Make the first column of the table non-breaking."""
|
|
135
140
|
try:
|
|
136
|
-
table = cast(nodes.table, node[0])
|
|
137
|
-
tgroup = cast(nodes.tgroup, table[0])
|
|
138
|
-
tbody = cast(nodes.tbody, tgroup[-1])
|
|
139
|
-
rows = cast(list[nodes.row], tbody)
|
|
141
|
+
table = cast('nodes.table', node[0])
|
|
142
|
+
tgroup = cast('nodes.tgroup', table[0])
|
|
143
|
+
tbody = cast('nodes.tbody', tgroup[-1])
|
|
144
|
+
rows = cast('list[nodes.row]', tbody)
|
|
140
145
|
for row in rows:
|
|
141
|
-
col1_entry = cast(nodes.entry, row[0])
|
|
142
|
-
par = cast(nodes.paragraph, col1_entry[0])
|
|
146
|
+
col1_entry = cast('nodes.entry', row[0])
|
|
147
|
+
par = cast('nodes.paragraph', col1_entry[0])
|
|
143
148
|
for j, subnode in enumerate(list(par)):
|
|
144
149
|
if isinstance(subnode, nodes.Text):
|
|
145
|
-
new_text = subnode.astext().replace(
|
|
150
|
+
new_text = subnode.astext().replace(' ', '\u00a0')
|
|
146
151
|
par[j] = nodes.Text(new_text)
|
|
147
152
|
except IndexError:
|
|
148
153
|
pass
|
|
@@ -150,14 +155,15 @@ def autosummary_table_visit_html(self: HTML5Translator, node: autosummary_table)
|
|
|
150
155
|
|
|
151
156
|
# -- autodoc integration -------------------------------------------------------
|
|
152
157
|
|
|
158
|
+
|
|
153
159
|
class FakeApplication:
|
|
154
160
|
verbosity = 0
|
|
155
161
|
|
|
156
162
|
def __init__(self) -> None:
|
|
157
|
-
self.doctreedir =
|
|
163
|
+
self.doctreedir = Path()
|
|
158
164
|
self.events = None
|
|
159
165
|
self.extensions: dict[str, Extension] = {}
|
|
160
|
-
self.srcdir =
|
|
166
|
+
self.srcdir = Path()
|
|
161
167
|
self.config = Config()
|
|
162
168
|
self.project = Project('', {})
|
|
163
169
|
self.registry = SphinxComponentRegistry()
|
|
@@ -178,6 +184,19 @@ def get_documenter(app: Sphinx, obj: Any, parent: Any) -> type[Documenter]:
|
|
|
178
184
|
"""Get an autodoc.Documenter class suitable for documenting the given
|
|
179
185
|
object.
|
|
180
186
|
|
|
187
|
+
*obj* is the Python object to be documented, and *parent* is an
|
|
188
|
+
another Python object (e.g. a module or a class) to which *obj*
|
|
189
|
+
belongs to.
|
|
190
|
+
"""
|
|
191
|
+
return _get_documenter(obj, parent, registry=app.registry)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _get_documenter(
|
|
195
|
+
obj: Any, parent: Any, *, registry: SphinxComponentRegistry
|
|
196
|
+
) -> type[Documenter]:
|
|
197
|
+
"""Get an autodoc.Documenter class suitable for documenting the given
|
|
198
|
+
object.
|
|
199
|
+
|
|
181
200
|
*obj* is the Python object to be documented, and *parent* is an
|
|
182
201
|
another Python object (e.g. a module or a class) to which *obj*
|
|
183
202
|
belongs to.
|
|
@@ -190,18 +209,21 @@ def get_documenter(app: Sphinx, obj: Any, parent: Any) -> type[Documenter]:
|
|
|
190
209
|
|
|
191
210
|
# Construct a fake documenter for *parent*
|
|
192
211
|
if parent is not None:
|
|
193
|
-
parent_doc_cls =
|
|
212
|
+
parent_doc_cls = _get_documenter(parent, None, registry=registry)
|
|
194
213
|
else:
|
|
195
214
|
parent_doc_cls = ModuleDocumenter
|
|
196
215
|
|
|
197
216
|
if hasattr(parent, '__name__'):
|
|
198
217
|
parent_doc = parent_doc_cls(FakeDirective(), parent.__name__)
|
|
199
218
|
else:
|
|
200
|
-
parent_doc = parent_doc_cls(FakeDirective(),
|
|
219
|
+
parent_doc = parent_doc_cls(FakeDirective(), '')
|
|
201
220
|
|
|
202
221
|
# Get the correct documenter class for *obj*
|
|
203
|
-
classes = [
|
|
204
|
-
|
|
222
|
+
classes = [
|
|
223
|
+
cls
|
|
224
|
+
for cls in registry.documenters.values()
|
|
225
|
+
if cls.can_document_member(obj, '', False, parent_doc)
|
|
226
|
+
]
|
|
205
227
|
if classes:
|
|
206
228
|
classes.sort(key=lambda cls: cls.priority)
|
|
207
229
|
return classes[-1]
|
|
@@ -211,9 +233,9 @@ def get_documenter(app: Sphinx, obj: Any, parent: Any) -> type[Documenter]:
|
|
|
211
233
|
|
|
212
234
|
# -- .. autosummary:: ----------------------------------------------------------
|
|
213
235
|
|
|
236
|
+
|
|
214
237
|
class Autosummary(SphinxDirective):
|
|
215
|
-
"""
|
|
216
|
-
Pretty table containing short signatures and summaries of functions etc.
|
|
238
|
+
"""Pretty table containing short signatures and summaries of functions etc.
|
|
217
239
|
|
|
218
240
|
autosummary can also optionally generate a hidden toctree:: node.
|
|
219
241
|
"""
|
|
@@ -224,18 +246,24 @@ class Autosummary(SphinxDirective):
|
|
|
224
246
|
has_content = True
|
|
225
247
|
option_spec: ClassVar[OptionSpec] = {
|
|
226
248
|
'caption': directives.unchanged_required,
|
|
249
|
+
'class': directives.class_option,
|
|
227
250
|
'toctree': directives.unchanged,
|
|
228
251
|
'nosignatures': directives.flag,
|
|
229
252
|
'recursive': directives.flag,
|
|
253
|
+
'signatures': directives.unchanged,
|
|
230
254
|
'template': directives.unchanged,
|
|
231
255
|
}
|
|
232
256
|
|
|
233
257
|
def run(self) -> list[Node]:
|
|
234
|
-
self.bridge = DocumenterBridge(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
258
|
+
self.bridge = DocumenterBridge(
|
|
259
|
+
self.env, self.state.document.reporter, Options(), self.lineno, self.state
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
names = [
|
|
263
|
+
x.strip().split()[0]
|
|
264
|
+
for x in self.content
|
|
265
|
+
if x.strip() and re.search(r'^[~a-zA-Z_]', x.strip()[0])
|
|
266
|
+
]
|
|
239
267
|
items = self.get_items(names)
|
|
240
268
|
nodes = self.get_table(items)
|
|
241
269
|
|
|
@@ -252,10 +280,14 @@ class Autosummary(SphinxDirective):
|
|
|
252
280
|
docname = posixpath.normpath(posixpath.join(dirname, docname))
|
|
253
281
|
if docname not in self.env.found_docs:
|
|
254
282
|
if excluded(str(self.env.doc2path(docname, False))):
|
|
255
|
-
msg = __(
|
|
283
|
+
msg = __(
|
|
284
|
+
'autosummary references excluded document %r. Ignored.'
|
|
285
|
+
)
|
|
256
286
|
else:
|
|
257
|
-
msg = __(
|
|
258
|
-
|
|
287
|
+
msg = __(
|
|
288
|
+
'autosummary: stub file not found %r. '
|
|
289
|
+
'Check your autosummary_generate setting.'
|
|
290
|
+
)
|
|
259
291
|
|
|
260
292
|
logger.warning(msg, real_name, location=self.get_location())
|
|
261
293
|
continue
|
|
@@ -273,13 +305,15 @@ class Autosummary(SphinxDirective):
|
|
|
273
305
|
nodes.append(autosummary_toc('', '', tocnode))
|
|
274
306
|
|
|
275
307
|
if 'toctree' not in self.options and 'caption' in self.options:
|
|
276
|
-
logger.warning(
|
|
277
|
-
|
|
308
|
+
logger.warning(
|
|
309
|
+
__('A captioned autosummary requires :toctree: option. ignored.'),
|
|
310
|
+
location=nodes[-1],
|
|
311
|
+
)
|
|
278
312
|
|
|
279
313
|
return nodes
|
|
280
314
|
|
|
281
315
|
def import_by_name(
|
|
282
|
-
self, name: str, prefixes: list[str | None]
|
|
316
|
+
self, name: str, prefixes: list[str | None]
|
|
283
317
|
) -> tuple[str, Any, Any, str]:
|
|
284
318
|
with mock(self.config.autosummary_mock_imports):
|
|
285
319
|
try:
|
|
@@ -296,23 +330,41 @@ class Autosummary(SphinxDirective):
|
|
|
296
330
|
|
|
297
331
|
raise ImportExceptionGroup(exc.args[0], errors) from None
|
|
298
332
|
|
|
299
|
-
def create_documenter(
|
|
300
|
-
|
|
333
|
+
def create_documenter(
|
|
334
|
+
self,
|
|
335
|
+
obj: Any,
|
|
336
|
+
parent: Any,
|
|
337
|
+
full_name: str,
|
|
338
|
+
*,
|
|
339
|
+
registry: SphinxComponentRegistry,
|
|
340
|
+
) -> Documenter:
|
|
301
341
|
"""Get an autodoc.Documenter class suitable for documenting the given
|
|
302
342
|
object.
|
|
303
343
|
|
|
304
|
-
Wraps
|
|
344
|
+
Wraps _get_documenter and is meant as a hook for extensions.
|
|
305
345
|
"""
|
|
306
|
-
doccls =
|
|
346
|
+
doccls = _get_documenter(obj, parent, registry=registry)
|
|
307
347
|
return doccls(self.bridge, full_name)
|
|
308
348
|
|
|
309
|
-
def get_items(self, names: list[str]) -> list[tuple[str, str, str, str]]:
|
|
349
|
+
def get_items(self, names: list[str]) -> list[tuple[str, str | None, str, str]]:
|
|
310
350
|
"""Try to import the given names, and return a list of
|
|
311
351
|
``[(name, signature, summary_string, real_name), ...]``.
|
|
352
|
+
|
|
353
|
+
signature is already formatted and is None if :nosignatures: option was given.
|
|
312
354
|
"""
|
|
313
355
|
prefixes = get_import_prefixes_from_env(self.env)
|
|
314
356
|
|
|
315
|
-
items: list[tuple[str, str, str, str]] = []
|
|
357
|
+
items: list[tuple[str, str | None, str, str]] = []
|
|
358
|
+
|
|
359
|
+
signatures_option = self.options.get('signatures')
|
|
360
|
+
if signatures_option is None:
|
|
361
|
+
signatures_option = 'none' if 'nosignatures' in self.options else 'long'
|
|
362
|
+
if signatures_option not in {'none', 'short', 'long'}:
|
|
363
|
+
msg = (
|
|
364
|
+
'Invalid value for autosummary :signatures: option: '
|
|
365
|
+
f"{signatures_option!r}. Valid values are 'none', 'short', 'long'"
|
|
366
|
+
)
|
|
367
|
+
raise ValueError(msg)
|
|
316
368
|
|
|
317
369
|
max_item_chars = 50
|
|
318
370
|
|
|
@@ -323,11 +375,17 @@ class Autosummary(SphinxDirective):
|
|
|
323
375
|
display_name = name.split('.')[-1]
|
|
324
376
|
|
|
325
377
|
try:
|
|
326
|
-
real_name, obj, parent, modname = self.import_by_name(
|
|
378
|
+
real_name, obj, parent, modname = self.import_by_name(
|
|
379
|
+
name, prefixes=prefixes
|
|
380
|
+
)
|
|
327
381
|
except ImportExceptionGroup as exc:
|
|
328
|
-
errors = list({f
|
|
329
|
-
logger.warning(
|
|
330
|
-
|
|
382
|
+
errors = list({f'* {type(e).__name__}: {e}' for e in exc.exceptions})
|
|
383
|
+
logger.warning(
|
|
384
|
+
__('autosummary: failed to import %s.\nPossible hints:\n%s'),
|
|
385
|
+
name,
|
|
386
|
+
'\n'.join(errors),
|
|
387
|
+
location=self.get_location(),
|
|
388
|
+
)
|
|
331
389
|
continue
|
|
332
390
|
|
|
333
391
|
self.bridge.result = StringList() # initialize for each documenter
|
|
@@ -335,25 +393,34 @@ class Autosummary(SphinxDirective):
|
|
|
335
393
|
if not isinstance(obj, ModuleType):
|
|
336
394
|
# give explicitly separated module name, so that members
|
|
337
395
|
# of inner classes can be documented
|
|
338
|
-
full_name = modname + '::' + full_name[len(modname) + 1:]
|
|
396
|
+
full_name = modname + '::' + full_name[len(modname) + 1 :]
|
|
339
397
|
# NB. using full_name here is important, since Documenters
|
|
340
398
|
# handle module prefixes slightly differently
|
|
341
|
-
documenter = self.create_documenter(
|
|
399
|
+
documenter = self.create_documenter(
|
|
400
|
+
obj, parent, full_name, registry=self.env._registry
|
|
401
|
+
)
|
|
342
402
|
if not documenter.parse_name():
|
|
343
|
-
logger.warning(
|
|
344
|
-
|
|
403
|
+
logger.warning(
|
|
404
|
+
__('failed to parse name %s'),
|
|
405
|
+
real_name,
|
|
406
|
+
location=self.get_location(),
|
|
407
|
+
)
|
|
345
408
|
items.append((display_name, '', '', real_name))
|
|
346
409
|
continue
|
|
347
410
|
if not documenter.import_object():
|
|
348
|
-
logger.warning(
|
|
349
|
-
|
|
411
|
+
logger.warning(
|
|
412
|
+
__('failed to import object %s'),
|
|
413
|
+
real_name,
|
|
414
|
+
location=self.get_location(),
|
|
415
|
+
)
|
|
350
416
|
items.append((display_name, '', '', real_name))
|
|
351
417
|
continue
|
|
352
418
|
|
|
353
419
|
# try to also get a source code analyzer for attribute docs
|
|
354
420
|
try:
|
|
355
421
|
documenter.analyzer = ModuleAnalyzer.for_module(
|
|
356
|
-
documenter.get_real_modname()
|
|
422
|
+
documenter.get_real_modname()
|
|
423
|
+
)
|
|
357
424
|
# parse right now, to get PycodeErrors on parsing (results will
|
|
358
425
|
# be cached anyway)
|
|
359
426
|
documenter.analyzer.find_attr_docs()
|
|
@@ -364,17 +431,22 @@ class Autosummary(SphinxDirective):
|
|
|
364
431
|
|
|
365
432
|
# -- Grab the signature
|
|
366
433
|
|
|
367
|
-
|
|
368
|
-
sig =
|
|
369
|
-
except TypeError:
|
|
370
|
-
# the documenter does not support ``show_annotation`` option
|
|
371
|
-
sig = documenter.format_signature()
|
|
372
|
-
|
|
373
|
-
if not sig:
|
|
374
|
-
sig = ''
|
|
434
|
+
if signatures_option == 'none':
|
|
435
|
+
sig = None
|
|
375
436
|
else:
|
|
376
|
-
|
|
377
|
-
|
|
437
|
+
try:
|
|
438
|
+
sig = documenter.format_signature(show_annotation=False)
|
|
439
|
+
except TypeError:
|
|
440
|
+
# the documenter does not support ``show_annotation`` option
|
|
441
|
+
sig = documenter.format_signature()
|
|
442
|
+
if not sig:
|
|
443
|
+
sig = ''
|
|
444
|
+
elif signatures_option == 'short':
|
|
445
|
+
if sig != '()':
|
|
446
|
+
sig = '(…)'
|
|
447
|
+
else: # signatures_option == 'long'
|
|
448
|
+
max_chars = max(10, max_item_chars - len(display_name))
|
|
449
|
+
sig = mangle_signature(sig, max_chars=max_chars)
|
|
378
450
|
|
|
379
451
|
# -- Grab the summary
|
|
380
452
|
|
|
@@ -388,7 +460,7 @@ class Autosummary(SphinxDirective):
|
|
|
388
460
|
|
|
389
461
|
return items
|
|
390
462
|
|
|
391
|
-
def get_table(self, items: list[tuple[str, str, str, str]]) -> list[Node]:
|
|
463
|
+
def get_table(self, items: list[tuple[str, str | None, str, str]]) -> list[Node]:
|
|
392
464
|
"""Generate a proper list of table nodes for autosummary:: directive.
|
|
393
465
|
|
|
394
466
|
*items* is a list produced by :meth:`get_items`.
|
|
@@ -397,7 +469,9 @@ class Autosummary(SphinxDirective):
|
|
|
397
469
|
table_spec['spec'] = r'\X{1}{2}\X{1}{2}'
|
|
398
470
|
|
|
399
471
|
table = autosummary_table('')
|
|
400
|
-
real_table = nodes.table(
|
|
472
|
+
real_table = nodes.table(
|
|
473
|
+
'', classes=['autosummary', 'longtable', *self.options.get('class', ())]
|
|
474
|
+
)
|
|
401
475
|
table.append(real_table)
|
|
402
476
|
group = nodes.tgroup('', cols=2)
|
|
403
477
|
real_table.append(group)
|
|
@@ -412,8 +486,9 @@ class Autosummary(SphinxDirective):
|
|
|
412
486
|
for text in column_texts:
|
|
413
487
|
vl = StringList([text], f'{source}:{line}:<autosummary>')
|
|
414
488
|
with switch_source_input(self.state, vl):
|
|
415
|
-
col_nodes = nested_parse_to_nodes(
|
|
416
|
-
|
|
489
|
+
col_nodes = nested_parse_to_nodes(
|
|
490
|
+
self.state, vl, allow_section_headings=False
|
|
491
|
+
)
|
|
417
492
|
if col_nodes and isinstance(col_nodes[0], nodes.paragraph):
|
|
418
493
|
node = col_nodes[0]
|
|
419
494
|
else:
|
|
@@ -423,10 +498,11 @@ class Autosummary(SphinxDirective):
|
|
|
423
498
|
|
|
424
499
|
for name, sig, summary, real_name in items:
|
|
425
500
|
qualifier = 'obj'
|
|
426
|
-
if
|
|
427
|
-
col1 = f':py:{qualifier}:`{name} <{real_name}>`\\ {rst.escape(sig)}'
|
|
428
|
-
else:
|
|
501
|
+
if sig is None:
|
|
429
502
|
col1 = f':py:{qualifier}:`{name} <{real_name}>`'
|
|
503
|
+
else:
|
|
504
|
+
col1 = f':py:{qualifier}:`{name} <{real_name}>`\\ {rst.escape(sig)}'
|
|
505
|
+
|
|
430
506
|
col2 = summary
|
|
431
507
|
append_row(col1, col2)
|
|
432
508
|
|
|
@@ -463,31 +539,33 @@ def mangle_signature(sig: str, max_chars: int = 30) -> str:
|
|
|
463
539
|
s = _cleanup_signature(sig)
|
|
464
540
|
|
|
465
541
|
# Strip return type annotation
|
|
466
|
-
s = re.sub(r
|
|
542
|
+
s = re.sub(r'\)\s*->\s.*$', ')', s)
|
|
467
543
|
|
|
468
544
|
# Remove parenthesis
|
|
469
|
-
s = re.sub(r
|
|
545
|
+
s = re.sub(r'^\((.*)\)$', r'\1', s).strip()
|
|
470
546
|
|
|
471
547
|
# Strip literals (which can contain things that confuse the code below)
|
|
472
|
-
s = re.sub(r
|
|
473
|
-
s = re.sub(r"\\'",
|
|
474
|
-
s = re.sub(r'\\"',
|
|
475
|
-
s = re.sub(r"'[^']*'",
|
|
476
|
-
s = re.sub(r'"[^"]*"',
|
|
548
|
+
s = re.sub(r'\\\\', '', s) # escaped backslash (maybe inside string)
|
|
549
|
+
s = re.sub(r"\\'", '', s) # escaped single quote
|
|
550
|
+
s = re.sub(r'\\"', '', s) # escaped double quote
|
|
551
|
+
s = re.sub(r"'[^']*'", '', s) # string literal (w/ single quote)
|
|
552
|
+
s = re.sub(r'"[^"]*"', '', s) # string literal (w/ double quote)
|
|
477
553
|
|
|
478
554
|
# Strip complex objects (maybe default value of arguments)
|
|
479
|
-
while re.search(
|
|
555
|
+
while re.search(
|
|
556
|
+
r'\([^)]*\)', s
|
|
557
|
+
): # contents of parenthesis (ex. NamedTuple(attr=...))
|
|
480
558
|
s = re.sub(r'\([^)]*\)', '', s)
|
|
481
|
-
while re.search(r'<[^>]*>', s):
|
|
559
|
+
while re.search(r'<[^>]*>', s): # contents of angle brackets (ex. <object>)
|
|
482
560
|
s = re.sub(r'<[^>]*>', '', s)
|
|
483
|
-
while re.search(r'{[^}]*}', s):
|
|
561
|
+
while re.search(r'{[^}]*}', s): # contents of curly brackets (ex. dict)
|
|
484
562
|
s = re.sub(r'{[^}]*}', '', s)
|
|
485
563
|
|
|
486
564
|
# Parse the signature to arguments + options
|
|
487
565
|
args: list[str] = []
|
|
488
566
|
opts: list[str] = []
|
|
489
567
|
|
|
490
|
-
opt_re = re.compile(r
|
|
568
|
+
opt_re = re.compile(r'^(.*, |)([a-zA-Z0-9_*]+)\s*=\s*')
|
|
491
569
|
while s:
|
|
492
570
|
m = opt_re.search(s)
|
|
493
571
|
if not m:
|
|
@@ -506,19 +584,21 @@ def mangle_signature(sig: str, max_chars: int = 30) -> str:
|
|
|
506
584
|
opts[i] = strip_arg_typehint(opt)
|
|
507
585
|
|
|
508
586
|
# Produce a more compact signature
|
|
509
|
-
sig = limited_join(
|
|
587
|
+
sig = limited_join(', ', args, max_chars=max_chars - 2)
|
|
510
588
|
if opts:
|
|
511
589
|
if not sig:
|
|
512
|
-
sig =
|
|
590
|
+
sig = '[%s]' % limited_join(', ', opts, max_chars=max_chars - 4)
|
|
513
591
|
elif len(sig) < max_chars - 4 - 2 - 3:
|
|
514
|
-
sig +=
|
|
515
|
-
|
|
592
|
+
sig += '[, %s]' % limited_join(
|
|
593
|
+
', ', opts, max_chars=max_chars - len(sig) - 4 - 2
|
|
594
|
+
)
|
|
516
595
|
|
|
517
|
-
return
|
|
596
|
+
return '(%s)' % sig
|
|
518
597
|
|
|
519
598
|
|
|
520
599
|
def extract_summary(doc: list[str], document: Any) -> str:
|
|
521
600
|
"""Extract summary from docstring."""
|
|
601
|
+
|
|
522
602
|
def parse(doc: list[str], settings: Any) -> nodes.document:
|
|
523
603
|
state_machine = RSTStateMachine(state_classes, 'Body')
|
|
524
604
|
node = new_document('', settings)
|
|
@@ -552,13 +632,13 @@ def extract_summary(doc: list[str], document: Any) -> str:
|
|
|
552
632
|
summary = doc[0].strip()
|
|
553
633
|
else:
|
|
554
634
|
# Try to find the "first sentence", which may span multiple lines
|
|
555
|
-
sentences = periods_re.split(
|
|
635
|
+
sentences = periods_re.split(' '.join(doc))
|
|
556
636
|
if len(sentences) == 1:
|
|
557
637
|
summary = sentences[0].strip()
|
|
558
638
|
else:
|
|
559
639
|
summary = ''
|
|
560
640
|
for i in range(len(sentences)):
|
|
561
|
-
summary =
|
|
641
|
+
summary = '. '.join(sentences[: i + 1]).rstrip('.') + '.'
|
|
562
642
|
node[:] = []
|
|
563
643
|
node = parse(doc, document.settings)
|
|
564
644
|
if summary.endswith(WELL_KNOWN_ABBREVIATIONS):
|
|
@@ -573,8 +653,9 @@ def extract_summary(doc: list[str], document: Any) -> str:
|
|
|
573
653
|
return summary
|
|
574
654
|
|
|
575
655
|
|
|
576
|
-
def limited_join(
|
|
577
|
-
|
|
656
|
+
def limited_join(
|
|
657
|
+
sep: str, items: list[str], max_chars: int = 30, overflow_marker: str = '...'
|
|
658
|
+
) -> str:
|
|
578
659
|
"""Join a number of strings into one, limiting the length to *max_chars*.
|
|
579
660
|
|
|
580
661
|
If the string overflows this limit, replace the last fitting item by
|
|
@@ -607,14 +688,15 @@ class ImportExceptionGroup(Exception):
|
|
|
607
688
|
It contains an error messages and a list of exceptions as its arguments.
|
|
608
689
|
"""
|
|
609
690
|
|
|
610
|
-
def __init__(
|
|
691
|
+
def __init__(
|
|
692
|
+
self, message: str | None, exceptions: Sequence[BaseException]
|
|
693
|
+
) -> None:
|
|
611
694
|
super().__init__(message)
|
|
612
695
|
self.exceptions = list(exceptions)
|
|
613
696
|
|
|
614
697
|
|
|
615
698
|
def get_import_prefixes_from_env(env: BuildEnvironment) -> list[str | None]:
|
|
616
|
-
"""
|
|
617
|
-
Obtain current Python import prefixes (for `import_by_name`)
|
|
699
|
+
"""Obtain current Python import prefixes (for `import_by_name`)
|
|
618
700
|
from ``document.env``
|
|
619
701
|
"""
|
|
620
702
|
prefixes: list[str | None] = [None]
|
|
@@ -626,7 +708,7 @@ def get_import_prefixes_from_env(env: BuildEnvironment) -> list[str | None]:
|
|
|
626
708
|
currclass = env.ref_context.get('py:class')
|
|
627
709
|
if currclass:
|
|
628
710
|
if currmodule:
|
|
629
|
-
prefixes.insert(0, currmodule
|
|
711
|
+
prefixes.insert(0, f'{currmodule}.{currclass}')
|
|
630
712
|
else:
|
|
631
713
|
prefixes.insert(0, currclass)
|
|
632
714
|
|
|
@@ -634,7 +716,7 @@ def get_import_prefixes_from_env(env: BuildEnvironment) -> list[str | None]:
|
|
|
634
716
|
|
|
635
717
|
|
|
636
718
|
def import_by_name(
|
|
637
|
-
name: str, prefixes: Sequence[str | None] = (None,)
|
|
719
|
+
name: str, prefixes: Sequence[str | None] = (None,)
|
|
638
720
|
) -> tuple[str, Any, Any, str]:
|
|
639
721
|
"""Import a Python object that has the given *name*, under one of the
|
|
640
722
|
*prefixes*. The first name that succeeds is used.
|
|
@@ -644,17 +726,26 @@ def import_by_name(
|
|
|
644
726
|
for prefix in prefixes:
|
|
645
727
|
if prefix is not None and name.startswith(f'{prefix}.'):
|
|
646
728
|
# Catch and avoid module cycles (e.g., sphinx.ext.sphinx.ext...)
|
|
647
|
-
msg = __(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
729
|
+
msg = __(
|
|
730
|
+
'Summarised items should not include the current module. '
|
|
731
|
+
'Replace %r with %r.'
|
|
732
|
+
)
|
|
733
|
+
logger.warning(
|
|
734
|
+
msg,
|
|
735
|
+
name,
|
|
736
|
+
name.removeprefix(f'{prefix}.'),
|
|
737
|
+
type='autosummary',
|
|
738
|
+
subtype='import_cycle',
|
|
739
|
+
)
|
|
651
740
|
continue
|
|
652
741
|
try:
|
|
653
742
|
if prefix:
|
|
654
743
|
prefixed_name = f'{prefix}.{name}'
|
|
655
744
|
else:
|
|
656
745
|
prefixed_name = name
|
|
657
|
-
obj, parent, modname = _import_by_name(
|
|
746
|
+
obj, parent, modname = _import_by_name(
|
|
747
|
+
prefixed_name, grouped_exception=True
|
|
748
|
+
)
|
|
658
749
|
return prefixed_name, obj, parent, modname
|
|
659
750
|
except ImportError:
|
|
660
751
|
tried.append(prefixed_name)
|
|
@@ -663,7 +754,8 @@ def import_by_name(
|
|
|
663
754
|
errors.append(exc)
|
|
664
755
|
|
|
665
756
|
exceptions: list[BaseException] = functools.reduce(
|
|
666
|
-
operator.iadd, (e.exceptions for e in errors), []
|
|
757
|
+
operator.iadd, (e.exceptions for e in errors), []
|
|
758
|
+
)
|
|
667
759
|
raise ImportExceptionGroup('no module named %s' % ' or '.join(tried), exceptions)
|
|
668
760
|
|
|
669
761
|
|
|
@@ -714,13 +806,14 @@ def _import_by_name(name: str, grouped_exception: bool = True) -> tuple[Any, Any
|
|
|
714
806
|
raise ImportError(*exc.args) from exc
|
|
715
807
|
|
|
716
808
|
|
|
717
|
-
def import_ivar_by_name(
|
|
718
|
-
|
|
809
|
+
def import_ivar_by_name(
|
|
810
|
+
name: str, prefixes: Sequence[str | None] = (None,), grouped_exception: bool = True
|
|
811
|
+
) -> tuple[str, Any, Any, str]:
|
|
719
812
|
"""Import an instance variable that has the given *name*, under one of the
|
|
720
813
|
*prefixes*. The first name that succeeds is used.
|
|
721
814
|
"""
|
|
722
815
|
try:
|
|
723
|
-
name, attr = name.rsplit(
|
|
816
|
+
name, attr = name.rsplit('.', 1)
|
|
724
817
|
real_name, obj, parent, modname = import_by_name(name, prefixes)
|
|
725
818
|
|
|
726
819
|
# Get ancestors of the object (class.__mro__ includes the class itself as
|
|
@@ -730,14 +823,16 @@ def import_ivar_by_name(name: str, prefixes: Sequence[str | None] = (None,),
|
|
|
730
823
|
candidate_objects = (obj,)
|
|
731
824
|
|
|
732
825
|
for candidate_obj in candidate_objects:
|
|
733
|
-
analyzer = ModuleAnalyzer.for_module(
|
|
826
|
+
analyzer = ModuleAnalyzer.for_module(
|
|
827
|
+
getattr(candidate_obj, '__module__', modname)
|
|
828
|
+
)
|
|
734
829
|
analyzer.analyze()
|
|
735
830
|
# check for presence in `annotations` to include dataclass attributes
|
|
736
831
|
found_attrs = set()
|
|
737
832
|
found_attrs |= {attr for (qualname, attr) in analyzer.attr_docs}
|
|
738
833
|
found_attrs |= {attr for (qualname, attr) in analyzer.annotations}
|
|
739
834
|
if attr in found_attrs:
|
|
740
|
-
return real_name
|
|
835
|
+
return f'{real_name}.{attr}', INSTANCEATTR, obj, modname
|
|
741
836
|
except (ImportError, ValueError, PycodeError) as exc:
|
|
742
837
|
raise ImportError from exc
|
|
743
838
|
except ImportExceptionGroup:
|
|
@@ -748,6 +843,7 @@ def import_ivar_by_name(name: str, prefixes: Sequence[str | None] = (None,),
|
|
|
748
843
|
|
|
749
844
|
# -- :autolink: (smart default role) -------------------------------------------
|
|
750
845
|
|
|
846
|
+
|
|
751
847
|
class AutoLink(SphinxRole):
|
|
752
848
|
"""Smart linking role.
|
|
753
849
|
|
|
@@ -758,13 +854,20 @@ class AutoLink(SphinxRole):
|
|
|
758
854
|
def run(self) -> tuple[list[Node], list[system_message]]:
|
|
759
855
|
pyobj_role = self.env.domains.python_domain.role('obj')
|
|
760
856
|
assert pyobj_role is not None
|
|
761
|
-
objects, errors = pyobj_role(
|
|
762
|
-
|
|
857
|
+
objects, errors = pyobj_role(
|
|
858
|
+
'obj',
|
|
859
|
+
self.rawtext,
|
|
860
|
+
self.text,
|
|
861
|
+
self.lineno,
|
|
862
|
+
self.inliner,
|
|
863
|
+
self.options,
|
|
864
|
+
self.content,
|
|
865
|
+
)
|
|
763
866
|
if errors:
|
|
764
867
|
return objects, errors
|
|
765
868
|
|
|
766
869
|
assert len(objects) == 1
|
|
767
|
-
pending_xref = cast(addnodes.pending_xref, objects[0])
|
|
870
|
+
pending_xref = cast('addnodes.pending_xref', objects[0])
|
|
768
871
|
try:
|
|
769
872
|
# try to import object by name
|
|
770
873
|
prefixes = get_import_prefixes_from_env(self.env)
|
|
@@ -777,9 +880,10 @@ class AutoLink(SphinxRole):
|
|
|
777
880
|
]
|
|
778
881
|
import_by_name(name, prefixes)
|
|
779
882
|
except ImportExceptionGroup:
|
|
780
|
-
literal = cast(nodes.literal, pending_xref[0])
|
|
781
|
-
objects[0] = nodes.emphasis(
|
|
782
|
-
|
|
883
|
+
literal = cast('nodes.literal', pending_xref[0])
|
|
884
|
+
objects[0] = nodes.emphasis(
|
|
885
|
+
self.rawtext, literal.astext(), classes=literal['classes']
|
|
886
|
+
)
|
|
783
887
|
|
|
784
888
|
return objects, errors
|
|
785
889
|
|
|
@@ -803,18 +907,23 @@ def process_generate_options(app: Sphinx) -> None:
|
|
|
803
907
|
genfiles = app.config.autosummary_generate
|
|
804
908
|
|
|
805
909
|
if genfiles is True:
|
|
806
|
-
env = app.
|
|
807
|
-
genfiles = [
|
|
808
|
-
|
|
910
|
+
env = app.env
|
|
911
|
+
genfiles = [
|
|
912
|
+
str(env.doc2path(x, base=False))
|
|
913
|
+
for x in env.found_docs
|
|
914
|
+
if env.doc2path(x).is_file()
|
|
915
|
+
]
|
|
809
916
|
elif genfiles is False:
|
|
810
917
|
pass
|
|
811
918
|
else:
|
|
812
919
|
ext = list(app.config.source_suffix)
|
|
813
|
-
genfiles = [
|
|
814
|
-
|
|
920
|
+
genfiles = [
|
|
921
|
+
genfile + (ext[0] if not genfile.endswith(tuple(ext)) else '')
|
|
922
|
+
for genfile in genfiles
|
|
923
|
+
]
|
|
815
924
|
|
|
816
925
|
for entry in genfiles[:]:
|
|
817
|
-
if not
|
|
926
|
+
if not (app.srcdir / entry).is_file():
|
|
818
927
|
logger.warning(__('autosummary_generate: file not found: %s'), entry)
|
|
819
928
|
genfiles.remove(entry)
|
|
820
929
|
|
|
@@ -823,45 +932,75 @@ def process_generate_options(app: Sphinx) -> None:
|
|
|
823
932
|
|
|
824
933
|
suffix = get_rst_suffix(app)
|
|
825
934
|
if suffix is None:
|
|
826
|
-
logger.warning(
|
|
827
|
-
|
|
935
|
+
logger.warning(
|
|
936
|
+
__(
|
|
937
|
+
'autosummary generates .rst files internally. '
|
|
938
|
+
'But your source_suffix does not contain .rst. Skipped.'
|
|
939
|
+
)
|
|
940
|
+
)
|
|
828
941
|
return
|
|
829
942
|
|
|
830
943
|
from sphinx.ext.autosummary.generate import generate_autosummary_docs
|
|
831
944
|
|
|
832
945
|
imported_members = app.config.autosummary_imported_members
|
|
833
946
|
with mock(app.config.autosummary_mock_imports):
|
|
834
|
-
generate_autosummary_docs(
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
947
|
+
generate_autosummary_docs(
|
|
948
|
+
genfiles,
|
|
949
|
+
suffix=suffix,
|
|
950
|
+
base_path=app.srcdir,
|
|
951
|
+
app=app,
|
|
952
|
+
imported_members=imported_members,
|
|
953
|
+
overwrite=app.config.autosummary_generate_overwrite,
|
|
954
|
+
encoding=app.config.source_encoding,
|
|
955
|
+
)
|
|
838
956
|
|
|
839
957
|
|
|
840
958
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
|
841
959
|
# I need autodoc
|
|
842
960
|
app.setup_extension('sphinx.ext.autodoc')
|
|
843
|
-
app.add_node(
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
961
|
+
app.add_node(
|
|
962
|
+
autosummary_toc,
|
|
963
|
+
html=(autosummary_toc_visit_html, autosummary_noop),
|
|
964
|
+
latex=(autosummary_noop, autosummary_noop),
|
|
965
|
+
text=(autosummary_noop, autosummary_noop),
|
|
966
|
+
man=(autosummary_noop, autosummary_noop),
|
|
967
|
+
texinfo=(autosummary_noop, autosummary_noop),
|
|
968
|
+
)
|
|
969
|
+
app.add_node(
|
|
970
|
+
autosummary_table,
|
|
971
|
+
html=(autosummary_table_visit_html, autosummary_noop),
|
|
972
|
+
latex=(autosummary_noop, autosummary_noop),
|
|
973
|
+
text=(autosummary_noop, autosummary_noop),
|
|
974
|
+
man=(autosummary_noop, autosummary_noop),
|
|
975
|
+
texinfo=(autosummary_noop, autosummary_noop),
|
|
976
|
+
)
|
|
855
977
|
app.add_directive('autosummary', Autosummary)
|
|
856
978
|
app.add_role('autolink', AutoLink())
|
|
857
979
|
app.connect('builder-inited', process_generate_options)
|
|
858
|
-
app.add_config_value('autosummary_context', {}, 'env')
|
|
859
|
-
app.add_config_value(
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
app.add_config_value(
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
app.add_config_value(
|
|
866
|
-
|
|
867
|
-
|
|
980
|
+
app.add_config_value('autosummary_context', {}, 'env', types=frozenset({dict}))
|
|
981
|
+
app.add_config_value(
|
|
982
|
+
'autosummary_filename_map', {}, 'html', types=frozenset({dict})
|
|
983
|
+
)
|
|
984
|
+
app.add_config_value(
|
|
985
|
+
'autosummary_generate', True, 'env', types=frozenset({bool, list})
|
|
986
|
+
)
|
|
987
|
+
app.add_config_value(
|
|
988
|
+
'autosummary_generate_overwrite', True, '', types=frozenset({bool})
|
|
989
|
+
)
|
|
990
|
+
app.add_config_value(
|
|
991
|
+
'autosummary_mock_imports',
|
|
992
|
+
lambda config: config.autodoc_mock_imports,
|
|
993
|
+
'env',
|
|
994
|
+
types=frozenset({list, tuple}),
|
|
995
|
+
)
|
|
996
|
+
app.add_config_value(
|
|
997
|
+
'autosummary_imported_members', False, '', types=frozenset({bool})
|
|
998
|
+
)
|
|
999
|
+
app.add_config_value(
|
|
1000
|
+
'autosummary_ignore_module_all', True, 'env', types=frozenset({bool})
|
|
1001
|
+
)
|
|
1002
|
+
|
|
1003
|
+
return {
|
|
1004
|
+
'version': sphinx.__display_version__,
|
|
1005
|
+
'parallel_read_safe': True,
|
|
1006
|
+
}
|