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.

Files changed (328) hide show
  1. sphinx/__init__.py +8 -4
  2. sphinx/__main__.py +2 -0
  3. sphinx/_cli/__init__.py +2 -5
  4. sphinx/_cli/util/colour.py +34 -11
  5. sphinx/_cli/util/errors.py +128 -61
  6. sphinx/addnodes.py +51 -35
  7. sphinx/application.py +362 -230
  8. sphinx/builders/__init__.py +87 -64
  9. sphinx/builders/_epub_base.py +65 -56
  10. sphinx/builders/changes.py +17 -23
  11. sphinx/builders/dirhtml.py +8 -13
  12. sphinx/builders/epub3.py +70 -38
  13. sphinx/builders/gettext.py +93 -73
  14. sphinx/builders/html/__init__.py +240 -186
  15. sphinx/builders/html/_assets.py +9 -2
  16. sphinx/builders/html/_build_info.py +3 -0
  17. sphinx/builders/latex/__init__.py +64 -54
  18. sphinx/builders/latex/constants.py +14 -11
  19. sphinx/builders/latex/nodes.py +2 -0
  20. sphinx/builders/latex/theming.py +8 -9
  21. sphinx/builders/latex/transforms.py +7 -5
  22. sphinx/builders/linkcheck.py +193 -149
  23. sphinx/builders/manpage.py +17 -17
  24. sphinx/builders/singlehtml.py +28 -16
  25. sphinx/builders/texinfo.py +28 -21
  26. sphinx/builders/text.py +10 -15
  27. sphinx/builders/xml.py +10 -19
  28. sphinx/cmd/build.py +49 -119
  29. sphinx/cmd/make_mode.py +35 -31
  30. sphinx/cmd/quickstart.py +78 -62
  31. sphinx/config.py +265 -163
  32. sphinx/directives/__init__.py +51 -54
  33. sphinx/directives/admonitions.py +107 -0
  34. sphinx/directives/code.py +24 -19
  35. sphinx/directives/other.py +21 -42
  36. sphinx/directives/patches.py +28 -16
  37. sphinx/domains/__init__.py +54 -31
  38. sphinx/domains/_domains_container.py +22 -17
  39. sphinx/domains/_index.py +5 -8
  40. sphinx/domains/c/__init__.py +366 -245
  41. sphinx/domains/c/_ast.py +378 -256
  42. sphinx/domains/c/_ids.py +89 -31
  43. sphinx/domains/c/_parser.py +283 -214
  44. sphinx/domains/c/_symbol.py +269 -198
  45. sphinx/domains/changeset.py +39 -24
  46. sphinx/domains/citation.py +54 -24
  47. sphinx/domains/cpp/__init__.py +517 -362
  48. sphinx/domains/cpp/_ast.py +999 -682
  49. sphinx/domains/cpp/_ids.py +133 -65
  50. sphinx/domains/cpp/_parser.py +746 -588
  51. sphinx/domains/cpp/_symbol.py +692 -489
  52. sphinx/domains/index.py +10 -8
  53. sphinx/domains/javascript.py +152 -74
  54. sphinx/domains/math.py +50 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +134 -61
  57. sphinx/domains/python/_object.py +155 -68
  58. sphinx/domains/rst.py +94 -49
  59. sphinx/domains/std/__init__.py +510 -249
  60. sphinx/environment/__init__.py +345 -61
  61. sphinx/environment/adapters/asset.py +7 -1
  62. sphinx/environment/adapters/indexentries.py +15 -20
  63. sphinx/environment/adapters/toctree.py +19 -9
  64. sphinx/environment/collectors/__init__.py +3 -1
  65. sphinx/environment/collectors/asset.py +18 -15
  66. sphinx/environment/collectors/dependencies.py +8 -10
  67. sphinx/environment/collectors/metadata.py +6 -4
  68. sphinx/environment/collectors/title.py +3 -1
  69. sphinx/environment/collectors/toctree.py +4 -4
  70. sphinx/errors.py +1 -3
  71. sphinx/events.py +4 -4
  72. sphinx/ext/apidoc/__init__.py +66 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_extension.py +262 -0
  76. sphinx/ext/apidoc/_generate.py +356 -0
  77. sphinx/ext/apidoc/_shared.py +99 -0
  78. sphinx/ext/autodoc/__init__.py +837 -483
  79. sphinx/ext/autodoc/directive.py +57 -21
  80. sphinx/ext/autodoc/importer.py +184 -67
  81. sphinx/ext/autodoc/mock.py +25 -10
  82. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  83. sphinx/ext/autodoc/type_comment.py +56 -29
  84. sphinx/ext/autodoc/typehints.py +49 -26
  85. sphinx/ext/autosectionlabel.py +28 -11
  86. sphinx/ext/autosummary/__init__.py +281 -142
  87. sphinx/ext/autosummary/generate.py +121 -51
  88. sphinx/ext/coverage.py +152 -91
  89. sphinx/ext/doctest.py +169 -101
  90. sphinx/ext/duration.py +12 -6
  91. sphinx/ext/extlinks.py +33 -21
  92. sphinx/ext/githubpages.py +8 -8
  93. sphinx/ext/graphviz.py +175 -109
  94. sphinx/ext/ifconfig.py +11 -6
  95. sphinx/ext/imgconverter.py +48 -25
  96. sphinx/ext/imgmath.py +127 -97
  97. sphinx/ext/inheritance_diagram.py +177 -103
  98. sphinx/ext/intersphinx/__init__.py +22 -13
  99. sphinx/ext/intersphinx/__main__.py +3 -1
  100. sphinx/ext/intersphinx/_cli.py +18 -14
  101. sphinx/ext/intersphinx/_load.py +91 -82
  102. sphinx/ext/intersphinx/_resolve.py +108 -74
  103. sphinx/ext/intersphinx/_shared.py +2 -2
  104. sphinx/ext/linkcode.py +28 -12
  105. sphinx/ext/mathjax.py +60 -29
  106. sphinx/ext/napoleon/__init__.py +19 -7
  107. sphinx/ext/napoleon/docstring.py +229 -231
  108. sphinx/ext/todo.py +44 -49
  109. sphinx/ext/viewcode.py +105 -57
  110. sphinx/extension.py +3 -1
  111. sphinx/highlighting.py +13 -7
  112. sphinx/io.py +9 -13
  113. sphinx/jinja2glue.py +29 -26
  114. sphinx/locale/__init__.py +8 -9
  115. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  116. sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
  117. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  118. sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
  119. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  120. sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
  121. sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
  122. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
  124. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
  125. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
  126. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
  127. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  128. sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
  129. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  130. sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
  131. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  132. sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
  133. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  134. sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
  135. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  136. sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
  137. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
  139. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
  141. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
  143. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
  145. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
  147. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
  149. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
  151. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
  153. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
  155. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
  157. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
  159. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
  161. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
  163. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
  165. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
  167. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
  169. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
  171. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
  173. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
  175. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
  177. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
  179. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
  181. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
  183. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
  185. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
  187. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
  189. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
  191. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  192. sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
  193. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  194. sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
  195. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  196. sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
  197. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  198. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
  199. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  200. sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
  201. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  202. sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
  203. sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
  204. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
  206. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
  208. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
  210. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
  212. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
  214. sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
  215. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
  217. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
  219. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
  221. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
  223. sphinx/locale/sphinx.pot +2069 -1964
  224. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  225. sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
  226. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  227. sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
  228. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  229. sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
  230. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  231. sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
  232. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  233. sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
  234. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
  236. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
  238. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  239. sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
  240. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  241. sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
  242. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  243. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
  244. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  245. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
  246. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  247. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
  248. sphinx/parsers.py +8 -7
  249. sphinx/project.py +2 -2
  250. sphinx/pycode/__init__.py +31 -21
  251. sphinx/pycode/ast.py +6 -3
  252. sphinx/pycode/parser.py +14 -8
  253. sphinx/pygments_styles.py +4 -5
  254. sphinx/registry.py +192 -92
  255. sphinx/roles.py +58 -7
  256. sphinx/search/__init__.py +75 -54
  257. sphinx/search/en.py +11 -13
  258. sphinx/search/fi.py +1 -1
  259. sphinx/search/ja.py +8 -6
  260. sphinx/search/nl.py +1 -1
  261. sphinx/search/zh.py +19 -21
  262. sphinx/testing/fixtures.py +26 -29
  263. sphinx/testing/path.py +26 -62
  264. sphinx/testing/restructuredtext.py +14 -8
  265. sphinx/testing/util.py +21 -19
  266. sphinx/texinputs/make.bat.jinja +50 -50
  267. sphinx/texinputs/sphinx.sty +4 -3
  268. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  269. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  270. sphinx/themes/basic/static/searchtools.js +8 -5
  271. sphinx/theming.py +49 -61
  272. sphinx/transforms/__init__.py +17 -38
  273. sphinx/transforms/compact_bullet_list.py +5 -3
  274. sphinx/transforms/i18n.py +8 -21
  275. sphinx/transforms/post_transforms/__init__.py +142 -93
  276. sphinx/transforms/post_transforms/code.py +5 -5
  277. sphinx/transforms/post_transforms/images.py +28 -24
  278. sphinx/transforms/references.py +3 -1
  279. sphinx/util/__init__.py +109 -60
  280. sphinx/util/_files.py +39 -23
  281. sphinx/util/_importer.py +4 -1
  282. sphinx/util/_inventory_file_reader.py +76 -0
  283. sphinx/util/_io.py +2 -2
  284. sphinx/util/_lines.py +6 -3
  285. sphinx/util/_pathlib.py +40 -2
  286. sphinx/util/build_phase.py +2 -0
  287. sphinx/util/cfamily.py +19 -14
  288. sphinx/util/console.py +44 -179
  289. sphinx/util/display.py +9 -10
  290. sphinx/util/docfields.py +140 -122
  291. sphinx/util/docstrings.py +1 -1
  292. sphinx/util/docutils.py +118 -77
  293. sphinx/util/fileutil.py +25 -26
  294. sphinx/util/http_date.py +2 -0
  295. sphinx/util/i18n.py +77 -64
  296. sphinx/util/images.py +8 -6
  297. sphinx/util/inspect.py +147 -38
  298. sphinx/util/inventory.py +215 -116
  299. sphinx/util/logging.py +33 -33
  300. sphinx/util/matching.py +12 -4
  301. sphinx/util/nodes.py +18 -13
  302. sphinx/util/osutil.py +38 -39
  303. sphinx/util/parallel.py +22 -13
  304. sphinx/util/parsing.py +2 -1
  305. sphinx/util/png.py +6 -2
  306. sphinx/util/requests.py +33 -2
  307. sphinx/util/rst.py +3 -2
  308. sphinx/util/tags.py +1 -1
  309. sphinx/util/template.py +18 -10
  310. sphinx/util/texescape.py +8 -6
  311. sphinx/util/typing.py +148 -122
  312. sphinx/versioning.py +3 -3
  313. sphinx/writers/html.py +3 -1
  314. sphinx/writers/html5.py +63 -52
  315. sphinx/writers/latex.py +83 -67
  316. sphinx/writers/manpage.py +19 -38
  317. sphinx/writers/texinfo.py +47 -47
  318. sphinx/writers/text.py +50 -32
  319. sphinx/writers/xml.py +11 -8
  320. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
  321. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
  322. sphinx-8.2.0.dist-info/RECORD +606 -0
  323. {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
  324. sphinx/builders/html/transforms.py +0 -90
  325. sphinx/ext/apidoc.py +0 -721
  326. sphinx/util/exceptions.py +0 -74
  327. sphinx-8.1.2.dist-info/RECORD +0 -598
  328. {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
- :nosignatures:
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 os import path
58
+ from pathlib import Path
60
59
  from types import ModuleType
61
- from typing import TYPE_CHECKING, Any, ClassVar, cast
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, Documenter, Options
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(self: HTML5Translator, node: autosummary_table) -> None:
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(" ", "\u00a0")
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 = None
163
+ self.doctreedir = Path()
158
164
  self.events = None
159
165
  self.extensions: dict[str, Extension] = {}
160
- self.srcdir = None
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 = get_documenter(app, parent, None)
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 = [cls for cls in app.registry.documenters.values()
204
- if cls.can_document_member(obj, '', False, parent_doc)]
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(self.env, self.state.document.reporter,
235
- Options(), self.lineno, self.state)
236
-
237
- names = [x.strip().split()[0] for x in self.content
238
- if x.strip() and re.search(r'^[~a-zA-Z_]', x.strip()[0])]
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 = __('autosummary references excluded document %r. Ignored.')
283
+ msg = __(
284
+ 'autosummary references excluded document %r. Ignored.'
285
+ )
256
286
  else:
257
- msg = __('autosummary: stub file not found %r. '
258
- 'Check your autosummary_generate setting.')
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(__('A captioned autosummary requires :toctree: option. ignored.'),
277
- location=nodes[-1])
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(self, app: Sphinx, obj: Any,
300
- parent: Any, full_name: str) -> Documenter:
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 get_documenter and is meant as a hook for extensions.
344
+ Wraps _get_documenter and is meant as a hook for extensions.
305
345
  """
306
- doccls = get_documenter(app, obj, parent)
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(name, prefixes=prefixes)
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"* {type(e).__name__}: {e}" for e in exc.exceptions})
329
- logger.warning(__('autosummary: failed to import %s.\nPossible hints:\n%s'),
330
- name, '\n'.join(errors), location=self.get_location())
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(self.env.app, obj, parent, full_name)
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(__('failed to parse name %s'), real_name,
344
- location=self.get_location())
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(__('failed to import object %s'), real_name,
349
- location=self.get_location())
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
- try:
368
- sig = documenter.format_signature(show_annotation=False)
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
- max_chars = max(10, max_item_chars - len(display_name))
377
- sig = mangle_signature(sig, max_chars=max_chars)
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('', classes=['autosummary longtable'])
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(self.state, vl,
416
- allow_section_headings=False)
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 'nosignatures' not in self.options:
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"\)\s*->\s.*$", ")", s)
542
+ s = re.sub(r'\)\s*->\s.*$', ')', s)
467
543
 
468
544
  # Remove parenthesis
469
- s = re.sub(r"^\((.*)\)$", r"\1", s).strip()
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"\\\\", "", s) # escaped backslash (maybe inside string)
473
- s = re.sub(r"\\'", "", s) # escaped single quote
474
- s = re.sub(r'\\"', "", s) # escaped double quote
475
- s = re.sub(r"'[^']*'", "", s) # string literal (w/ single quote)
476
- s = re.sub(r'"[^"]*"', "", s) # string literal (w/ double quote)
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(r'\([^)]*\)', s): # contents of parenthesis (ex. NamedTuple(attr=...))
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): # contents of angle brackets (ex. <object>)
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): # contents of curly brackets (ex. dict)
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"^(.*, |)([a-zA-Z0-9_*]+)\s*=\s*")
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(", ", args, max_chars=max_chars - 2)
587
+ sig = limited_join(', ', args, max_chars=max_chars - 2)
510
588
  if opts:
511
589
  if not sig:
512
- sig = "[%s]" % limited_join(", ", opts, max_chars=max_chars - 4)
590
+ sig = '[%s]' % limited_join(', ', opts, max_chars=max_chars - 4)
513
591
  elif len(sig) < max_chars - 4 - 2 - 3:
514
- sig += "[, %s]" % limited_join(", ", opts,
515
- max_chars=max_chars - len(sig) - 4 - 2)
592
+ sig += '[, %s]' % limited_join(
593
+ ', ', opts, max_chars=max_chars - len(sig) - 4 - 2
594
+ )
516
595
 
517
- return "(%s)" % sig
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(" ".join(doc))
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 = ". ".join(sentences[:i + 1]).rstrip(".") + "."
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(sep: str, items: list[str], max_chars: int = 30,
577
- overflow_marker: str = "...") -> str:
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__(self, message: str | None, exceptions: Sequence[BaseException]) -> None:
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 + "." + currclass)
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 = __('Summarised items should not include the current module. '
648
- 'Replace %r with %r.')
649
- logger.warning(msg, name, name.removeprefix(f'{prefix}.'),
650
- type='autosummary', subtype='import_cycle')
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(prefixed_name, grouped_exception=True)
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(name: str, prefixes: Sequence[str | None] = (None,),
718
- grouped_exception: bool = True) -> tuple[str, Any, Any, str]:
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(".", 1)
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(getattr(candidate_obj, '__module__', modname))
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 + "." + attr, INSTANCEATTR, obj, modname
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('obj', self.rawtext, self.text, self.lineno,
762
- self.inliner, self.options, self.content)
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(self.rawtext, literal.astext(),
782
- classes=literal['classes'])
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.builder.env
807
- genfiles = [str(env.doc2path(x, base=False)) for x in env.found_docs
808
- if os.path.isfile(env.doc2path(x))]
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 = [genfile + (ext[0] if not genfile.endswith(tuple(ext)) else '')
814
- for genfile in genfiles]
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 path.isfile(path.join(app.srcdir, entry)):
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(__('autosummary generates .rst files internally. '
827
- 'But your source_suffix does not contain .rst. Skipped.'))
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(genfiles, suffix=suffix, base_path=app.srcdir,
835
- app=app, imported_members=imported_members,
836
- overwrite=app.config.autosummary_generate_overwrite,
837
- encoding=app.config.source_encoding)
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(autosummary_toc,
844
- html=(autosummary_toc_visit_html, autosummary_noop),
845
- latex=(autosummary_noop, autosummary_noop),
846
- text=(autosummary_noop, autosummary_noop),
847
- man=(autosummary_noop, autosummary_noop),
848
- texinfo=(autosummary_noop, autosummary_noop))
849
- app.add_node(autosummary_table,
850
- html=(autosummary_table_visit_html, autosummary_noop),
851
- latex=(autosummary_noop, autosummary_noop),
852
- text=(autosummary_noop, autosummary_noop),
853
- man=(autosummary_noop, autosummary_noop),
854
- texinfo=(autosummary_noop, autosummary_noop))
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('autosummary_filename_map', {}, 'html')
860
- app.add_config_value('autosummary_generate', True, 'env', {bool, list})
861
- app.add_config_value('autosummary_generate_overwrite', True, '')
862
- app.add_config_value('autosummary_mock_imports',
863
- lambda config: config.autodoc_mock_imports, 'env')
864
- app.add_config_value('autosummary_imported_members', [], '', bool)
865
- app.add_config_value('autosummary_ignore_module_all', True, 'env', bool)
866
-
867
- return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
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
+ }