Sphinx 7.2.6__py3-none-any.whl → 7.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Sphinx might be problematic. Click here for more details.

Files changed (388) hide show
  1. sphinx/__init__.py +8 -9
  2. sphinx/addnodes.py +31 -28
  3. sphinx/application.py +9 -15
  4. sphinx/builders/__init__.py +5 -6
  5. sphinx/builders/_epub_base.py +17 -9
  6. sphinx/builders/changes.py +10 -5
  7. sphinx/builders/dirhtml.py +4 -2
  8. sphinx/builders/dummy.py +3 -2
  9. sphinx/builders/epub3.py +5 -3
  10. sphinx/builders/gettext.py +24 -7
  11. sphinx/builders/html/__init__.py +88 -96
  12. sphinx/builders/html/_assets.py +16 -16
  13. sphinx/builders/html/transforms.py +4 -2
  14. sphinx/builders/latex/__init__.py +40 -33
  15. sphinx/builders/latex/nodes.py +6 -2
  16. sphinx/builders/latex/transforms.py +17 -8
  17. sphinx/builders/latex/util.py +1 -1
  18. sphinx/builders/linkcheck.py +86 -27
  19. sphinx/builders/manpage.py +8 -6
  20. sphinx/builders/singlehtml.py +5 -4
  21. sphinx/builders/texinfo.py +18 -14
  22. sphinx/builders/text.py +3 -2
  23. sphinx/builders/xml.py +5 -2
  24. sphinx/cmd/build.py +119 -76
  25. sphinx/cmd/make_mode.py +4 -9
  26. sphinx/cmd/quickstart.py +13 -16
  27. sphinx/config.py +432 -250
  28. sphinx/deprecation.py +23 -13
  29. sphinx/directives/__init__.py +8 -8
  30. sphinx/directives/code.py +7 -7
  31. sphinx/directives/other.py +23 -13
  32. sphinx/directives/patches.py +7 -6
  33. sphinx/domains/__init__.py +2 -2
  34. sphinx/domains/c/__init__.py +796 -0
  35. sphinx/domains/c/_ast.py +1421 -0
  36. sphinx/domains/c/_ids.py +65 -0
  37. sphinx/domains/c/_parser.py +1048 -0
  38. sphinx/domains/c/_symbol.py +700 -0
  39. sphinx/domains/changeset.py +11 -7
  40. sphinx/domains/citation.py +5 -2
  41. sphinx/domains/cpp/__init__.py +1089 -0
  42. sphinx/domains/cpp/_ast.py +3635 -0
  43. sphinx/domains/cpp/_ids.py +537 -0
  44. sphinx/domains/cpp/_parser.py +2117 -0
  45. sphinx/domains/cpp/_symbol.py +1092 -0
  46. sphinx/domains/index.py +6 -4
  47. sphinx/domains/javascript.py +16 -13
  48. sphinx/domains/math.py +9 -4
  49. sphinx/domains/python/__init__.py +890 -0
  50. sphinx/domains/python/_annotations.py +507 -0
  51. sphinx/domains/python/_object.py +426 -0
  52. sphinx/domains/rst.py +12 -7
  53. sphinx/domains/{std.py → std/__init__.py} +19 -16
  54. sphinx/environment/__init__.py +21 -19
  55. sphinx/environment/adapters/indexentries.py +2 -2
  56. sphinx/environment/adapters/toctree.py +10 -9
  57. sphinx/environment/collectors/__init__.py +6 -3
  58. sphinx/environment/collectors/asset.py +4 -3
  59. sphinx/environment/collectors/dependencies.py +3 -2
  60. sphinx/environment/collectors/metadata.py +6 -5
  61. sphinx/environment/collectors/title.py +3 -2
  62. sphinx/environment/collectors/toctree.py +5 -4
  63. sphinx/errors.py +13 -2
  64. sphinx/events.py +14 -9
  65. sphinx/ext/apidoc.py +9 -11
  66. sphinx/ext/autodoc/__init__.py +105 -71
  67. sphinx/ext/autodoc/directive.py +7 -6
  68. sphinx/ext/autodoc/importer.py +102 -36
  69. sphinx/ext/autodoc/mock.py +7 -5
  70. sphinx/ext/autodoc/preserve_defaults.py +4 -3
  71. sphinx/ext/autodoc/type_comment.py +2 -1
  72. sphinx/ext/autodoc/typehints.py +5 -4
  73. sphinx/ext/autosectionlabel.py +3 -2
  74. sphinx/ext/autosummary/__init__.py +21 -17
  75. sphinx/ext/autosummary/generate.py +9 -9
  76. sphinx/ext/coverage.py +26 -20
  77. sphinx/ext/doctest.py +38 -33
  78. sphinx/ext/duration.py +1 -0
  79. sphinx/ext/extlinks.py +4 -3
  80. sphinx/ext/githubpages.py +3 -2
  81. sphinx/ext/graphviz.py +10 -7
  82. sphinx/ext/ifconfig.py +5 -5
  83. sphinx/ext/imgconverter.py +6 -5
  84. sphinx/ext/imgmath.py +9 -8
  85. sphinx/ext/inheritance_diagram.py +31 -31
  86. sphinx/ext/intersphinx.py +140 -23
  87. sphinx/ext/linkcode.py +3 -2
  88. sphinx/ext/mathjax.py +2 -1
  89. sphinx/ext/napoleon/__init__.py +12 -7
  90. sphinx/ext/napoleon/docstring.py +34 -32
  91. sphinx/ext/todo.py +10 -7
  92. sphinx/ext/viewcode.py +12 -11
  93. sphinx/extension.py +18 -8
  94. sphinx/highlighting.py +39 -20
  95. sphinx/io.py +17 -8
  96. sphinx/jinja2glue.py +16 -15
  97. sphinx/locale/__init__.py +30 -23
  98. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
  100. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
  102. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
  104. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
  106. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
  108. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
  110. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
  112. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
  114. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
  116. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
  118. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
  120. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
  122. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
  124. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
  126. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
  128. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
  130. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
  132. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
  134. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
  136. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  137. sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
  138. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  139. sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
  140. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  141. sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
  142. sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
  143. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
  145. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
  147. sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
  148. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  149. sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
  150. sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
  151. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
  153. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
  155. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
  157. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
  159. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
  161. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
  163. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
  165. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
  167. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
  169. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
  171. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
  173. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
  175. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
  177. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
  179. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
  180. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  181. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
  182. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  183. sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
  184. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  185. sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
  186. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  187. sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
  188. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  189. sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
  190. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  191. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
  192. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
  194. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
  196. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
  198. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
  200. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
  202. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
  204. sphinx/locale/sphinx.pot +813 -755
  205. sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
  206. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
  208. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
  210. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  212. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
  214. sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
  215. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
  217. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
  219. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
  221. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
  223. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  224. sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
  225. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  226. sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
  227. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  228. sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
  229. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  230. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
  231. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  232. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
  233. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
  234. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
  236. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
  238. sphinx/parsers.py +7 -5
  239. sphinx/project.py +18 -11
  240. sphinx/pycode/__init__.py +6 -5
  241. sphinx/pycode/ast.py +23 -8
  242. sphinx/pycode/parser.py +6 -5
  243. sphinx/registry.py +12 -6
  244. sphinx/roles.py +103 -57
  245. sphinx/search/__init__.py +17 -18
  246. sphinx/search/da.py +2 -2
  247. sphinx/search/de.py +2 -2
  248. sphinx/search/en.py +1 -1
  249. sphinx/search/es.py +2 -2
  250. sphinx/search/fi.py +2 -2
  251. sphinx/search/fr.py +2 -2
  252. sphinx/search/hu.py +2 -2
  253. sphinx/search/it.py +2 -2
  254. sphinx/search/ja.py +13 -22
  255. sphinx/search/nl.py +2 -2
  256. sphinx/search/no.py +2 -2
  257. sphinx/search/pt.py +2 -2
  258. sphinx/search/ro.py +1 -1
  259. sphinx/search/ru.py +2 -2
  260. sphinx/search/sv.py +2 -2
  261. sphinx/search/tr.py +1 -1
  262. sphinx/search/zh.py +2 -3
  263. sphinx/templates/graphviz/graphviz.css +1 -1
  264. sphinx/testing/fixtures.py +41 -24
  265. sphinx/testing/path.py +1 -1
  266. sphinx/testing/util.py +142 -53
  267. sphinx/texinputs/sphinx.xdy +1 -1
  268. sphinx/texinputs/sphinxlatextables.sty +1 -1
  269. sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
  270. sphinx/themes/agogo/layout.html +4 -4
  271. sphinx/themes/agogo/static/agogo.css_t +1 -1
  272. sphinx/themes/agogo/theme.toml +22 -0
  273. sphinx/themes/basic/defindex.html +1 -1
  274. sphinx/themes/basic/domainindex.html +1 -1
  275. sphinx/themes/basic/genindex-single.html +1 -1
  276. sphinx/themes/basic/genindex-split.html +1 -1
  277. sphinx/themes/basic/genindex.html +1 -1
  278. sphinx/themes/basic/globaltoc.html +1 -1
  279. sphinx/themes/basic/layout.html +1 -1
  280. sphinx/themes/basic/localtoc.html +1 -1
  281. sphinx/themes/basic/page.html +1 -1
  282. sphinx/themes/basic/relations.html +1 -1
  283. sphinx/themes/basic/search.html +5 -20
  284. sphinx/themes/basic/searchbox.html +3 -3
  285. sphinx/themes/basic/searchfield.html +3 -3
  286. sphinx/themes/basic/sourcelink.html +1 -1
  287. sphinx/themes/basic/static/basic.css_t +1 -1
  288. sphinx/themes/basic/static/doctools.js +1 -1
  289. sphinx/themes/basic/static/language_data.js_t +2 -2
  290. sphinx/themes/basic/static/searchtools.js +105 -60
  291. sphinx/themes/basic/theme.toml +23 -0
  292. sphinx/themes/bizstyle/layout.html +1 -6
  293. sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
  294. sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
  295. sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
  296. sphinx/themes/bizstyle/theme.toml +12 -0
  297. sphinx/themes/classic/layout.html +1 -1
  298. sphinx/themes/classic/static/classic.css_t +1 -1
  299. sphinx/themes/classic/static/sidebar.js_t +1 -1
  300. sphinx/themes/classic/theme.toml +34 -0
  301. sphinx/themes/default/theme.toml +2 -0
  302. sphinx/themes/epub/epub-cover.html +1 -1
  303. sphinx/themes/epub/layout.html +1 -1
  304. sphinx/themes/epub/static/epub.css_t +1 -1
  305. sphinx/themes/epub/theme.toml +10 -0
  306. sphinx/themes/haiku/layout.html +3 -3
  307. sphinx/themes/haiku/static/haiku.css_t +2 -2
  308. sphinx/themes/haiku/theme.toml +16 -0
  309. sphinx/themes/nature/static/nature.css_t +1 -1
  310. sphinx/themes/nature/theme.toml +6 -0
  311. sphinx/themes/nonav/layout.html +1 -1
  312. sphinx/themes/nonav/static/nonav.css_t +1 -1
  313. sphinx/themes/nonav/theme.toml +10 -0
  314. sphinx/themes/pyramid/static/epub.css_t +1 -1
  315. sphinx/themes/pyramid/static/pyramid.css_t +1 -1
  316. sphinx/themes/pyramid/theme.toml +6 -0
  317. sphinx/themes/scrolls/artwork/logo.svg +1 -1
  318. sphinx/themes/scrolls/layout.html +2 -2
  319. sphinx/themes/scrolls/static/scrolls.css_t +1 -1
  320. sphinx/themes/scrolls/theme.toml +15 -0
  321. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
  322. sphinx/themes/sphinxdoc/theme.toml +6 -0
  323. sphinx/themes/traditional/static/traditional.css_t +1 -1
  324. sphinx/themes/traditional/theme.toml +9 -0
  325. sphinx/theming.py +427 -131
  326. sphinx/transforms/__init__.py +21 -24
  327. sphinx/transforms/compact_bullet_list.py +5 -5
  328. sphinx/transforms/i18n.py +30 -28
  329. sphinx/transforms/post_transforms/__init__.py +9 -7
  330. sphinx/transforms/post_transforms/code.py +4 -1
  331. sphinx/transforms/post_transforms/images.py +17 -13
  332. sphinx/transforms/references.py +3 -1
  333. sphinx/util/__init__.py +15 -11
  334. sphinx/util/_io.py +34 -0
  335. sphinx/util/_pathlib.py +23 -18
  336. sphinx/util/build_phase.py +1 -0
  337. sphinx/util/cfamily.py +19 -11
  338. sphinx/util/console.py +101 -21
  339. sphinx/util/display.py +3 -2
  340. sphinx/util/docfields.py +12 -8
  341. sphinx/util/docutils.py +21 -35
  342. sphinx/util/exceptions.py +3 -2
  343. sphinx/util/fileutil.py +5 -5
  344. sphinx/util/http_date.py +9 -2
  345. sphinx/util/i18n.py +40 -9
  346. sphinx/util/inspect.py +317 -245
  347. sphinx/util/inventory.py +22 -5
  348. sphinx/util/logging.py +81 -7
  349. sphinx/util/matching.py +2 -1
  350. sphinx/util/math.py +1 -2
  351. sphinx/util/nodes.py +39 -29
  352. sphinx/util/osutil.py +25 -6
  353. sphinx/util/parallel.py +6 -1
  354. sphinx/util/requests.py +8 -5
  355. sphinx/util/rst.py +8 -6
  356. sphinx/util/tags.py +3 -3
  357. sphinx/util/template.py +8 -3
  358. sphinx/util/typing.py +76 -42
  359. sphinx/versioning.py +6 -2
  360. sphinx/writers/html.py +1 -1
  361. sphinx/writers/html5.py +17 -13
  362. sphinx/writers/latex.py +12 -12
  363. sphinx/writers/manpage.py +13 -7
  364. sphinx/writers/texinfo.py +13 -10
  365. sphinx/writers/text.py +13 -23
  366. sphinx/writers/xml.py +1 -1
  367. sphinx-7.2.6.dist-info/LICENSE → sphinx-7.3.1.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/METADATA +14 -12
  369. sphinx-7.3.1.dist-info/RECORD +581 -0
  370. sphinx/domains/c.py +0 -3906
  371. sphinx/domains/cpp.py +0 -8233
  372. sphinx/domains/python.py +0 -1769
  373. sphinx/themes/agogo/theme.conf +0 -20
  374. sphinx/themes/basic/theme.conf +0 -16
  375. sphinx/themes/bizstyle/theme.conf +0 -10
  376. sphinx/themes/classic/theme.conf +0 -32
  377. sphinx/themes/default/theme.conf +0 -2
  378. sphinx/themes/epub/theme.conf +0 -8
  379. sphinx/themes/haiku/theme.conf +0 -14
  380. sphinx/themes/nature/theme.conf +0 -4
  381. sphinx/themes/nonav/theme.conf +0 -8
  382. sphinx/themes/pyramid/theme.conf +0 -4
  383. sphinx/themes/scrolls/theme.conf +0 -13
  384. sphinx/themes/sphinxdoc/theme.conf +0 -4
  385. sphinx/themes/traditional/theme.conf +0 -7
  386. sphinx-7.2.6.dist-info/RECORD +0 -569
  387. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/entry_points.txt +0 -0
@@ -8,7 +8,8 @@ import os
8
8
  import sys
9
9
  import traceback
10
10
  import typing
11
- from typing import TYPE_CHECKING, Any, Callable, NamedTuple
11
+ from enum import Enum
12
+ from typing import TYPE_CHECKING, NamedTuple
12
13
 
13
14
  from sphinx.ext.autodoc.mock import ismock, undecorate
14
15
  from sphinx.pycode import ModuleAnalyzer, PycodeError
@@ -20,16 +21,91 @@ from sphinx.util.inspect import (
20
21
  isclass,
21
22
  isenumclass,
22
23
  safe_getattr,
24
+ unwrap_all,
23
25
  )
24
26
 
25
27
  if TYPE_CHECKING:
28
+ from collections.abc import Callable, Iterator, Mapping
26
29
  from types import ModuleType
30
+ from typing import Any
27
31
 
28
32
  from sphinx.ext.autodoc import ObjectMember
29
33
 
30
34
  logger = logging.getLogger(__name__)
31
35
 
32
36
 
37
+ def _filter_enum_dict(
38
+ enum_class: type[Enum],
39
+ attrgetter: Callable[[Any, str, Any], Any],
40
+ enum_class_dict: Mapping[str, object],
41
+ ) -> Iterator[tuple[str, type, Any]]:
42
+ """Find the attributes to document of an enumeration class.
43
+
44
+ The output consists of triplets ``(attribute name, defining class, value)``
45
+ where the attribute name can appear more than once during the iteration
46
+ but with different defining class. The order of occurrence is guided by
47
+ the MRO of *enum_class*.
48
+ """
49
+ # attributes that were found on a mixin type or the data type
50
+ candidate_in_mro: set[str] = set()
51
+ # sunder names that were picked up (and thereby allowed to be redefined)
52
+ # see: https://docs.python.org/3/howto/enum.html#supported-dunder-names
53
+ sunder_names = {'_name_', '_value_', '_missing_', '_order_', '_generate_next_value_'}
54
+ # attributes that can be picked up on a mixin type or the enum's data type
55
+ public_names = {'name', 'value', *object.__dict__, *sunder_names}
56
+ # names that are ignored by default
57
+ ignore_names = Enum.__dict__.keys() - public_names
58
+
59
+ def is_native_api(obj: object, name: str) -> bool:
60
+ """Check whether *obj* is the same as ``Enum.__dict__[name]``."""
61
+ return unwrap_all(obj) is unwrap_all(Enum.__dict__[name])
62
+
63
+ def should_ignore(name: str, value: Any) -> bool:
64
+ if name in sunder_names:
65
+ return is_native_api(value, name)
66
+ return name in ignore_names
67
+
68
+ sentinel = object()
69
+
70
+ def query(name: str, defining_class: type) -> tuple[str, type, Any] | None:
71
+ value = attrgetter(enum_class, name, sentinel)
72
+ if value is not sentinel:
73
+ return (name, defining_class, value)
74
+ return None
75
+
76
+ # attributes defined on a parent type, possibly shadowed later by
77
+ # the attributes defined directly inside the enumeration class
78
+ for parent in enum_class.__mro__:
79
+ if parent in {enum_class, Enum, object}:
80
+ continue
81
+
82
+ parent_dict = attrgetter(parent, '__dict__', {})
83
+ for name, value in parent_dict.items():
84
+ if should_ignore(name, value):
85
+ continue
86
+
87
+ candidate_in_mro.add(name)
88
+ if (item := query(name, parent)) is not None:
89
+ yield item
90
+
91
+ # exclude members coming from the native Enum unless
92
+ # they were redefined on a mixin type or the data type
93
+ excluded_members = Enum.__dict__.keys() - candidate_in_mro
94
+ yield from filter(None, (query(name, enum_class) for name in enum_class_dict
95
+ if name not in excluded_members))
96
+
97
+ # check if allowed members from ``Enum`` were redefined at the enum level
98
+ special_names = sunder_names | public_names
99
+ special_names &= enum_class_dict.keys()
100
+ special_names &= Enum.__dict__.keys()
101
+ for name in special_names:
102
+ if (
103
+ not is_native_api(enum_class_dict[name], name)
104
+ and (item := query(name, enum_class)) is not None
105
+ ):
106
+ yield item
107
+
108
+
33
109
  def mangle(subject: Any, name: str) -> str:
34
110
  """Mangle the given name."""
35
111
  try:
@@ -61,9 +137,7 @@ def unmangle(subject: Any, name: str) -> str | None:
61
137
 
62
138
 
63
139
  def import_module(modname: str, warningiserror: bool = False) -> Any:
64
- """
65
- Call importlib.import_module(modname), convert exceptions to ImportError
66
- """
140
+ """Call importlib.import_module(modname), convert exceptions to ImportError."""
67
141
  try:
68
142
  with logging.skip_warningiserror(not warningiserror):
69
143
  return importlib.import_module(modname)
@@ -97,7 +171,7 @@ def import_object(modname: str, objpath: list[str], objtype: str = '',
97
171
  try:
98
172
  module = None
99
173
  exc_on_importing = None
100
- objpath = list(objpath)
174
+ objpath = objpath.copy()
101
175
  while module is None:
102
176
  try:
103
177
  original_module_names = frozenset(sys.modules)
@@ -194,15 +268,11 @@ def get_object_members(
194
268
 
195
269
  # enum members
196
270
  if isenumclass(subject):
197
- for name, value in subject.__members__.items():
198
- if name not in members:
199
- members[name] = Attribute(name, True, value)
200
-
201
- superclass = subject.__mro__[1]
202
- for name in obj_dict:
203
- if name not in superclass.__dict__:
204
- value = safe_getattr(subject, name)
205
- members[name] = Attribute(name, True, value)
271
+ for name, defining_class, value in _filter_enum_dict(subject, attrgetter, obj_dict):
272
+ # the order of occurrence of *name* matches the subject's MRO,
273
+ # allowing inherited attributes to be shadowed correctly
274
+ if unmangled := unmangle(defining_class, name):
275
+ members[unmangled] = Attribute(unmangled, defining_class is subject, value)
206
276
 
207
277
  # members in __slots__
208
278
  try:
@@ -220,18 +290,18 @@ def get_object_members(
220
290
  try:
221
291
  value = attrgetter(subject, name)
222
292
  directly_defined = name in obj_dict
223
- name = unmangle(subject, name)
224
- if name and name not in members:
225
- members[name] = Attribute(name, directly_defined, value)
293
+ unmangled = unmangle(subject, name)
294
+ if unmangled and unmangled not in members:
295
+ members[unmangled] = Attribute(unmangled, directly_defined, value)
226
296
  except AttributeError:
227
297
  continue
228
298
 
229
299
  # annotation only member (ex. attr: int)
230
- for i, cls in enumerate(getmro(subject)):
300
+ for cls in getmro(subject):
231
301
  for name in getannotations(cls):
232
- name = unmangle(cls, name)
233
- if name and name not in members:
234
- members[name] = Attribute(name, i == 0, INSTANCEATTR)
302
+ unmangled = unmangle(cls, name)
303
+ if unmangled and unmangled not in members:
304
+ members[unmangled] = Attribute(unmangled, cls is subject, INSTANCEATTR)
235
305
 
236
306
  if analyzer:
237
307
  # append instance attributes (cf. self.attr1) if analyzer knows
@@ -255,15 +325,11 @@ def get_class_members(subject: Any, objpath: Any, attrgetter: Callable,
255
325
 
256
326
  # enum members
257
327
  if isenumclass(subject):
258
- for name, value in subject.__members__.items():
259
- if name not in members:
260
- members[name] = ObjectMember(name, value, class_=subject)
261
-
262
- superclass = subject.__mro__[1]
263
- for name in obj_dict:
264
- if name not in superclass.__dict__:
265
- value = safe_getattr(subject, name)
266
- members[name] = ObjectMember(name, value, class_=subject)
328
+ for name, defining_class, value in _filter_enum_dict(subject, attrgetter, obj_dict):
329
+ # the order of occurrence of *name* matches the subject's MRO,
330
+ # allowing inherited attributes to be shadowed correctly
331
+ if unmangled := unmangle(defining_class, name):
332
+ members[unmangled] = ObjectMember(unmangled, value, class_=defining_class)
267
333
 
268
334
  # members in __slots__
269
335
  try:
@@ -308,15 +374,15 @@ def get_class_members(subject: Any, objpath: Any, attrgetter: Callable,
308
374
 
309
375
  # annotation only member (ex. attr: int)
310
376
  for name in getannotations(cls):
311
- name = unmangle(cls, name)
312
- if name and name not in members:
313
- if analyzer and (qualname, name) in analyzer.attr_docs:
314
- docstring = '\n'.join(analyzer.attr_docs[qualname, name])
377
+ unmangled = unmangle(cls, name)
378
+ if unmangled and unmangled not in members:
379
+ if analyzer and (qualname, unmangled) in analyzer.attr_docs:
380
+ docstring = '\n'.join(analyzer.attr_docs[qualname, unmangled])
315
381
  else:
316
382
  docstring = None
317
383
 
318
- members[name] = ObjectMember(name, INSTANCEATTR, class_=cls,
319
- docstring=docstring)
384
+ members[unmangled] = ObjectMember(unmangled, INSTANCEATTR, class_=cls,
385
+ docstring=docstring)
320
386
 
321
387
  # append or complete instance attributes (cf. self.attr1) if analyzer knows
322
388
  if analyzer:
@@ -14,7 +14,7 @@ from sphinx.util import logging
14
14
  from sphinx.util.inspect import isboundmethod, safe_getattr
15
15
 
16
16
  if TYPE_CHECKING:
17
- from collections.abc import Generator, Iterator, Sequence
17
+ from collections.abc import Iterator, Sequence
18
18
 
19
19
  logger = logging.getLogger(__name__)
20
20
 
@@ -80,6 +80,7 @@ def _make_subclass(name: str, module: str, superclass: Any = _MockObject,
80
80
 
81
81
  class _MockModule(ModuleType):
82
82
  """Used by autodoc_mock_imports."""
83
+
83
84
  __file__ = os.devnull
84
85
  __sphinx_mock__ = True
85
86
 
@@ -97,6 +98,7 @@ class _MockModule(ModuleType):
97
98
 
98
99
  class MockLoader(Loader):
99
100
  """A loader for mocking."""
101
+
100
102
  def __init__(self, finder: MockFinder) -> None:
101
103
  super().__init__()
102
104
  self.finder = finder
@@ -135,12 +137,12 @@ class MockFinder(MetaPathFinder):
135
137
 
136
138
 
137
139
  @contextlib.contextmanager
138
- def mock(modnames: list[str]) -> Generator[None, None, None]:
140
+ def mock(modnames: list[str]) -> Iterator[None]:
139
141
  """Insert mock modules during context::
140
142
 
141
- with mock(['target.module.name']):
142
- # mock modules are enabled here
143
- ...
143
+ with mock(['target.module.name']):
144
+ # mock modules are enabled here
145
+ ...
144
146
  """
145
147
  try:
146
148
  finder = MockFinder(modnames)
@@ -22,6 +22,7 @@ if TYPE_CHECKING:
22
22
  from typing import Any
23
23
 
24
24
  from sphinx.application import Sphinx
25
+ from sphinx.util.typing import ExtensionMetadata
25
26
 
26
27
  logger = logging.getLogger(__name__)
27
28
  _LAMBDA_NAME = (lambda: None).__name__
@@ -96,7 +97,7 @@ def _get_arguments(obj: Any, /) -> ast.arguments | None:
96
97
  return _get_arguments_inner(subject)
97
98
 
98
99
 
99
- def _is_lambda(x, /):
100
+ def _is_lambda(x: Any, /) -> bool:
100
101
  return isinstance(x, types.LambdaType) and x.__name__ == _LAMBDA_NAME
101
102
 
102
103
 
@@ -189,8 +190,8 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
189
190
  logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc)
190
191
 
191
192
 
192
- def setup(app: Sphinx) -> dict[str, Any]:
193
- app.add_config_value('autodoc_preserve_defaults', False, True)
193
+ def setup(app: Sphinx) -> ExtensionMetadata:
194
+ app.add_config_value('autodoc_preserve_defaults', False, 'env')
194
195
  app.connect('autodoc-before-process-signature', update_defvalue)
195
196
 
196
197
  return {
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
15
15
  from collections.abc import Sequence
16
16
 
17
17
  from sphinx.application import Sphinx
18
+ from sphinx.util.typing import ExtensionMetadata
18
19
 
19
20
  logger = logging.getLogger(__name__)
20
21
 
@@ -134,7 +135,7 @@ def update_annotations_using_type_comments(app: Sphinx, obj: Any, bound_method:
134
135
  logger.warning(__("Failed to parse type_comment for %r: %s"), obj, exc)
135
136
 
136
137
 
137
- def setup(app: Sphinx) -> dict[str, Any]:
138
+ def setup(app: Sphinx) -> ExtensionMetadata:
138
139
  app.connect('autodoc-before-process-signature', update_annotations_using_type_comments)
139
140
 
140
141
  return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
@@ -11,16 +11,17 @@ from docutils import nodes
11
11
  import sphinx
12
12
  from sphinx import addnodes
13
13
  from sphinx.util import inspect
14
- from sphinx.util.typing import stringify_annotation
14
+ from sphinx.util.typing import ExtensionMetadata, stringify_annotation
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from docutils.nodes import Element
18
18
 
19
19
  from sphinx.application import Sphinx
20
+ from sphinx.ext.autodoc import Options
20
21
 
21
22
 
22
23
  def record_typehints(app: Sphinx, objtype: str, name: str, obj: Any,
23
- options: dict, args: str, retann: str) -> None:
24
+ options: Options, args: str, retann: str) -> None:
24
25
  """Record type hints to env object."""
25
26
  if app.config.autodoc_typehints_format == 'short':
26
27
  mode = 'smart'
@@ -50,7 +51,7 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element
50
51
  try:
51
52
  signature = cast(addnodes.desc_signature, contentnode.parent[0])
52
53
  if signature['module']:
53
- fullname = '.'.join([signature['module'], signature['fullname']])
54
+ fullname = f'{signature["module"]}.{signature["fullname"]}'
54
55
  else:
55
56
  fullname = signature['fullname']
56
57
  except KeyError:
@@ -208,7 +209,7 @@ def augment_descriptions_with_types(
208
209
  node += field
209
210
 
210
211
 
211
- def setup(app: Sphinx) -> dict[str, Any]:
212
+ def setup(app: Sphinx) -> ExtensionMetadata:
212
213
  app.connect('autodoc-process-signature', record_typehints)
213
214
  app.connect('object-description-transform', merge_typehints)
214
215
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any, cast
5
+ from typing import TYPE_CHECKING, cast
6
6
 
7
7
  from docutils import nodes
8
8
 
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
16
16
  from docutils.nodes import Node
17
17
 
18
18
  from sphinx.application import Sphinx
19
+ from sphinx.util.typing import ExtensionMetadata
19
20
 
20
21
  logger = logging.getLogger(__name__)
21
22
 
@@ -57,7 +58,7 @@ def register_sections_as_label(app: Sphinx, document: Node) -> None:
57
58
  domain.labels[name] = docname, labelid, sectname
58
59
 
59
60
 
60
- def setup(app: Sphinx) -> dict[str, Any]:
61
+ def setup(app: Sphinx) -> ExtensionMetadata:
61
62
  app.add_config_value('autosectionlabel_prefix_document', False, 'env')
62
63
  app.add_config_value('autosectionlabel_maxdepth', None, 'env')
63
64
  app.connect('doctree-read', register_sections_as_label)
@@ -48,7 +48,9 @@ This can be used as the default role to make links 'smart'.
48
48
 
49
49
  from __future__ import annotations
50
50
 
51
+ import functools
51
52
  import inspect
53
+ import operator
52
54
  import os
53
55
  import posixpath
54
56
  import re
@@ -56,7 +58,7 @@ import sys
56
58
  from inspect import Parameter
57
59
  from os import path
58
60
  from types import ModuleType
59
- from typing import TYPE_CHECKING, Any, cast
61
+ from typing import TYPE_CHECKING, Any, ClassVar, cast
60
62
 
61
63
  from docutils import nodes
62
64
  from docutils.parsers.rst import directives
@@ -93,7 +95,7 @@ if TYPE_CHECKING:
93
95
 
94
96
  from sphinx.application import Sphinx
95
97
  from sphinx.extension import Extension
96
- from sphinx.util.typing import OptionSpec
98
+ from sphinx.util.typing import ExtensionMetadata, OptionSpec
97
99
  from sphinx.writers.html import HTML5Translator
98
100
 
99
101
  logger = logging.getLogger(__name__)
@@ -162,7 +164,7 @@ class FakeDirective(DocumenterBridge):
162
164
  settings = Struct(tab_width=8)
163
165
  document = Struct(settings=settings)
164
166
  app = FakeApplication()
165
- app.config.add('autodoc_class_signature', 'mixed', True, None)
167
+ app.config.add('autodoc_class_signature', 'mixed', 'env', ())
166
168
  env = BuildEnvironment(app) # type: ignore[arg-type]
167
169
  state = Struct(document=document)
168
170
  super().__init__(env, None, Options(), 0, state)
@@ -216,7 +218,7 @@ class Autosummary(SphinxDirective):
216
218
  optional_arguments = 0
217
219
  final_argument_whitespace = False
218
220
  has_content = True
219
- option_spec: OptionSpec = {
221
+ option_spec: ClassVar[OptionSpec] = {
220
222
  'caption': directives.unchanged_required,
221
223
  'toctree': directives.unchanged,
222
224
  'nosignatures': directives.flag,
@@ -284,9 +286,9 @@ class Autosummary(SphinxDirective):
284
286
  return import_ivar_by_name(name, prefixes)
285
287
  except ImportError as exc2:
286
288
  if exc2.__cause__:
287
- errors: list[BaseException] = exc.exceptions + [exc2.__cause__]
289
+ errors: list[BaseException] = [*exc.exceptions, exc2.__cause__]
288
290
  else:
289
- errors = exc.exceptions + [exc2]
291
+ errors = [*exc.exceptions, exc2]
290
292
 
291
293
  raise ImportExceptionGroup(exc.args[0], errors) from None
292
294
 
@@ -591,7 +593,7 @@ def limited_join(sep: str, items: list[str], max_chars: int = 30,
591
593
  else:
592
594
  break
593
595
 
594
- return sep.join(list(items[:n_items]) + [overflow_marker])
596
+ return sep.join([*list(items[:n_items]), overflow_marker])
595
597
 
596
598
 
597
599
  # -- Importing items -----------------------------------------------------------
@@ -603,7 +605,7 @@ class ImportExceptionGroup(Exception):
603
605
  It contains an error messages and a list of exceptions as its arguments.
604
606
  """
605
607
 
606
- def __init__(self, message: str | None, exceptions: Sequence[BaseException]):
608
+ def __init__(self, message: str | None, exceptions: Sequence[BaseException]) -> None:
607
609
  super().__init__(message)
608
610
  self.exceptions = list(exceptions)
609
611
 
@@ -640,7 +642,7 @@ def import_by_name(
640
642
  for prefix in prefixes:
641
643
  try:
642
644
  if prefix:
643
- prefixed_name = '.'.join([prefix, name])
645
+ prefixed_name = f'{prefix}.{name}'
644
646
  else:
645
647
  prefixed_name = name
646
648
  obj, parent, modname = _import_by_name(prefixed_name, grouped_exception=True)
@@ -651,7 +653,8 @@ def import_by_name(
651
653
  tried.append(prefixed_name)
652
654
  errors.append(exc)
653
655
 
654
- exceptions: list[BaseException] = sum((e.exceptions for e in errors), [])
656
+ exceptions: list[BaseException] = functools.reduce(
657
+ operator.iadd, (e.exceptions for e in errors), [])
655
658
  raise ImportExceptionGroup('no module named %s' % ' or '.join(tried), exceptions)
656
659
 
657
660
 
@@ -742,6 +745,7 @@ class AutoLink(SphinxRole):
742
745
  Expands to ':obj:`text`' if `text` is an object that can be imported;
743
746
  otherwise expands to '*text*'.
744
747
  """
748
+
745
749
  def run(self) -> tuple[list[Node], list[system_message]]:
746
750
  pyobj_role = self.env.get_domain('py').role('obj')
747
751
  assert pyobj_role is not None
@@ -766,7 +770,7 @@ class AutoLink(SphinxRole):
766
770
 
767
771
  def get_rst_suffix(app: Sphinx) -> str | None:
768
772
  def get_supported_format(suffix: str) -> tuple[str, ...]:
769
- parser_class = app.registry.get_source_parsers().get(suffix)
773
+ parser_class = app.registry.get_source_parsers().get(suffix.removeprefix('.'))
770
774
  if parser_class is None:
771
775
  return ('restructuredtext',)
772
776
  return parser_class.supported
@@ -803,7 +807,7 @@ def process_generate_options(app: Sphinx) -> None:
803
807
 
804
808
  suffix = get_rst_suffix(app)
805
809
  if suffix is None:
806
- logger.warning(__('autosummary generats .rst files internally. '
810
+ logger.warning(__('autosummary generates .rst files internally. '
807
811
  'But your source_suffix does not contain .rst. Skipped.'))
808
812
  return
809
813
 
@@ -817,7 +821,7 @@ def process_generate_options(app: Sphinx) -> None:
817
821
  encoding=app.config.source_encoding)
818
822
 
819
823
 
820
- def setup(app: Sphinx) -> dict[str, Any]:
824
+ def setup(app: Sphinx) -> ExtensionMetadata:
821
825
  # I need autodoc
822
826
  app.setup_extension('sphinx.ext.autodoc')
823
827
  app.add_node(autosummary_toc,
@@ -835,13 +839,13 @@ def setup(app: Sphinx) -> dict[str, Any]:
835
839
  app.add_directive('autosummary', Autosummary)
836
840
  app.add_role('autolink', AutoLink())
837
841
  app.connect('builder-inited', process_generate_options)
838
- app.add_config_value('autosummary_context', {}, True)
842
+ app.add_config_value('autosummary_context', {}, 'env')
839
843
  app.add_config_value('autosummary_filename_map', {}, 'html')
840
- app.add_config_value('autosummary_generate', True, True, [bool, list])
841
- app.add_config_value('autosummary_generate_overwrite', True, False)
844
+ app.add_config_value('autosummary_generate', True, 'env', {bool, list})
845
+ app.add_config_value('autosummary_generate_overwrite', True, '')
842
846
  app.add_config_value('autosummary_mock_imports',
843
847
  lambda config: config.autodoc_mock_imports, 'env')
844
- app.add_config_value('autosummary_imported_members', [], False, [bool])
848
+ app.add_config_value('autosummary_imported_members', [], '', bool)
845
849
  app.add_config_value('autosummary_ignore_module_all', True, 'env', bool)
846
850
 
847
851
  return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
@@ -71,10 +71,9 @@ class DummyApplication:
71
71
  self._warncount = 0
72
72
  self.warningiserror = False
73
73
 
74
- self.config.add('autosummary_context', {}, True, None)
75
- self.config.add('autosummary_filename_map', {}, True, None)
74
+ self.config.add('autosummary_context', {}, 'env', ())
75
+ self.config.add('autosummary_filename_map', {}, 'env', ())
76
76
  self.config.add('autosummary_ignore_module_all', True, 'env', bool)
77
- self.config.init_values()
78
77
 
79
78
  def emit_firstresult(self, *args: Any) -> None:
80
79
  pass
@@ -134,7 +133,8 @@ class AutosummaryRenderer:
134
133
 
135
134
  if app.translator:
136
135
  self.env.add_extension("jinja2.ext.i18n")
137
- self.env.install_gettext_translations(app.translator)
136
+ # ``install_gettext_translations`` is injected by the ``jinja2.ext.i18n`` extension
137
+ self.env.install_gettext_translations(app.translator) # type: ignore[attr-defined]
138
138
 
139
139
  def render(self, template_name: str, context: dict) -> str:
140
140
  """Render a template file."""
@@ -249,8 +249,8 @@ class ModuleScanner:
249
249
  def members_of(obj: Any, conf: Config) -> Sequence[str]:
250
250
  """Get the members of ``obj``, possibly ignoring the ``__all__`` module attribute
251
251
 
252
- Follows the ``conf.autosummary_ignore_module_all`` setting."""
253
-
252
+ Follows the ``conf.autosummary_ignore_module_all`` setting.
253
+ """
254
254
  if conf.autosummary_ignore_module_all:
255
255
  return dir(obj)
256
256
  else:
@@ -331,7 +331,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
331
331
  if doc.objtype in ('method', 'attribute', 'property'):
332
332
  ns['class'] = qualname.rsplit(".", 1)[0]
333
333
 
334
- if doc.objtype in ('class',):
334
+ if doc.objtype == 'class':
335
335
  shortname = qualname
336
336
  else:
337
337
  shortname = qualname.rsplit(".", 1)[-1]
@@ -509,9 +509,9 @@ def generate_autosummary_docs(sources: list[str],
509
509
  qualname = name.replace(modname + ".", "")
510
510
  except ImportError as exc2:
511
511
  if exc2.__cause__:
512
- exceptions: list[BaseException] = exc.exceptions + [exc2.__cause__]
512
+ exceptions: list[BaseException] = [*exc.exceptions, exc2.__cause__]
513
513
  else:
514
- exceptions = exc.exceptions + [exc2]
514
+ exceptions = [*exc.exceptions, exc2]
515
515
 
516
516
  errors = list({f"* {type(e).__name__}: {e}" for e in exceptions})
517
517
  logger.warning(__('[autosummary] failed to import %s.\nPossible hints:\n%s'),
sphinx/ext/coverage.py CHANGED
@@ -19,13 +19,14 @@ import sphinx
19
19
  from sphinx.builders import Builder
20
20
  from sphinx.locale import __
21
21
  from sphinx.util import logging
22
- from sphinx.util.console import red # type: ignore[attr-defined]
22
+ from sphinx.util.console import red
23
23
  from sphinx.util.inspect import safe_getattr
24
24
 
25
25
  if TYPE_CHECKING:
26
26
  from collections.abc import Iterator
27
27
 
28
28
  from sphinx.application import Sphinx
29
+ from sphinx.util.typing import ExtensionMetadata
29
30
 
30
31
  logger = logging.getLogger(__name__)
31
32
 
@@ -69,6 +70,7 @@ class CoverageBuilder(Builder):
69
70
  """
70
71
  Evaluates coverage of code in the documentation.
71
72
  """
73
+
72
74
  name = 'coverage'
73
75
  epilog = __('Testing of coverage in the sources finished, look at the '
74
76
  'results in %(outdir)s' + path.sep + 'python.txt.')
@@ -270,7 +272,7 @@ class CoverageBuilder(Builder):
270
272
  self.py_documented[mod_name] = documented_objects
271
273
 
272
274
  def _write_py_statistics(self, op: TextIO) -> None:
273
- """ Outputs the table of ``op``."""
275
+ """Outputs the table of ``op``."""
274
276
  all_modules = set(self.py_documented.keys()).union(
275
277
  set(self.py_undocumented.keys()))
276
278
  all_objects: set[str] = set()
@@ -290,11 +292,15 @@ class CoverageBuilder(Builder):
290
292
  value = 100.0
291
293
 
292
294
  table.append([module, '%.2f%%' % value, '%d' % len(self.py_undocumented[module])])
293
- table.append([
294
- 'TOTAL',
295
- f'{100 * len(all_documented_objects) / len(all_objects):.2f}%',
296
- f'{len(all_objects) - len(all_documented_objects)}',
297
- ])
295
+
296
+ if all_objects:
297
+ table.append([
298
+ 'TOTAL',
299
+ f'{100 * len(all_documented_objects) / len(all_objects):.2f}%',
300
+ f'{len(all_objects) - len(all_documented_objects)}',
301
+ ])
302
+ else:
303
+ table.append(['TOTAL', '100', '0'])
298
304
 
299
305
  for line in _write_table(table):
300
306
  op.write(f'{line}\n')
@@ -383,18 +389,18 @@ class CoverageBuilder(Builder):
383
389
  self.py_undocumented, self.py_documented), dumpfile)
384
390
 
385
391
 
386
- def setup(app: Sphinx) -> dict[str, Any]:
392
+ def setup(app: Sphinx) -> ExtensionMetadata:
387
393
  app.add_builder(CoverageBuilder)
388
- app.add_config_value('coverage_ignore_modules', [], False)
389
- app.add_config_value('coverage_ignore_functions', [], False)
390
- app.add_config_value('coverage_ignore_classes', [], False)
391
- app.add_config_value('coverage_ignore_pyobjects', [], False)
392
- app.add_config_value('coverage_c_path', [], False)
393
- app.add_config_value('coverage_c_regexes', {}, False)
394
- app.add_config_value('coverage_ignore_c_items', {}, False)
395
- app.add_config_value('coverage_write_headline', True, False)
396
- app.add_config_value('coverage_statistics_to_report', True, False, (bool,))
397
- app.add_config_value('coverage_statistics_to_stdout', True, False, (bool,))
398
- app.add_config_value('coverage_skip_undoc_in_source', False, False)
399
- app.add_config_value('coverage_show_missing_items', False, False)
394
+ app.add_config_value('coverage_ignore_modules', [], '')
395
+ app.add_config_value('coverage_ignore_functions', [], '')
396
+ app.add_config_value('coverage_ignore_classes', [], '')
397
+ app.add_config_value('coverage_ignore_pyobjects', [], '')
398
+ app.add_config_value('coverage_c_path', [], '')
399
+ app.add_config_value('coverage_c_regexes', {}, '')
400
+ app.add_config_value('coverage_ignore_c_items', {}, '')
401
+ app.add_config_value('coverage_write_headline', True, '')
402
+ app.add_config_value('coverage_statistics_to_report', True, '', bool)
403
+ app.add_config_value('coverage_statistics_to_stdout', True, '', bool)
404
+ app.add_config_value('coverage_skip_undoc_in_source', False, '')
405
+ app.add_config_value('coverage_show_missing_items', False, '')
400
406
  return {'version': sphinx.__display_version__, 'parallel_read_safe': True}