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
@@ -0,0 +1,426 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import re
5
+ from typing import TYPE_CHECKING, ClassVar
6
+
7
+ from docutils import nodes
8
+ from docutils.parsers.rst import directives
9
+
10
+ from sphinx import addnodes
11
+ from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
12
+ from sphinx.directives import ObjectDescription
13
+ from sphinx.domains.python._annotations import (
14
+ _parse_annotation,
15
+ _parse_arglist,
16
+ _parse_type_list,
17
+ _pseudo_parse_arglist,
18
+ parse_reftarget,
19
+ )
20
+ from sphinx.locale import _
21
+ from sphinx.util import logging
22
+ from sphinx.util.docfields import Field, GroupedField, TypedField
23
+ from sphinx.util.nodes import (
24
+ make_id,
25
+ )
26
+
27
+ if TYPE_CHECKING:
28
+
29
+ from docutils.nodes import Node
30
+ from docutils.parsers.rst.states import Inliner
31
+
32
+ from sphinx.environment import BuildEnvironment
33
+ from sphinx.util.typing import OptionSpec, TextlikeNode
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+ # REs for Python signatures
38
+ py_sig_re = re.compile(
39
+ r'''^ ([\w.]*\.)? # class name(s)
40
+ (\w+) \s* # thing name
41
+ (?: \[\s*(.*)\s*])? # optional: type parameters list
42
+ (?: \(\s*(.*)\s*\) # optional: arguments
43
+ (?:\s* -> \s* (.*))? # return annotation
44
+ )? $ # and nothing more
45
+ ''', re.VERBOSE)
46
+
47
+
48
+ # This override allows our inline type specifiers to behave like :class: link
49
+ # when it comes to handling "." and "~" prefixes.
50
+ class PyXrefMixin:
51
+ def make_xref(
52
+ self,
53
+ rolename: str,
54
+ domain: str,
55
+ target: str,
56
+ innernode: type[TextlikeNode] = nodes.emphasis,
57
+ contnode: Node | None = None,
58
+ env: BuildEnvironment | None = None,
59
+ inliner: Inliner | None = None,
60
+ location: Node | None = None,
61
+ ) -> Node:
62
+ # we use inliner=None to make sure we get the old behaviour with a single
63
+ # pending_xref node
64
+ result = super().make_xref(rolename, domain, target, # type: ignore[misc]
65
+ innernode, contnode,
66
+ env, inliner=None, location=None)
67
+ if isinstance(result, pending_xref):
68
+ assert env is not None
69
+ result['refspecific'] = True
70
+ result['py:module'] = env.ref_context.get('py:module')
71
+ result['py:class'] = env.ref_context.get('py:class')
72
+
73
+ reftype, reftarget, reftitle, _ = parse_reftarget(target)
74
+ if reftarget != reftitle:
75
+ result['reftype'] = reftype
76
+ result['reftarget'] = reftarget
77
+
78
+ result.clear()
79
+ result += innernode(reftitle, reftitle) # type: ignore[call-arg]
80
+ elif env.config.python_use_unqualified_type_names:
81
+ children = result.children
82
+ result.clear()
83
+
84
+ shortname = target.split('.')[-1]
85
+ textnode = innernode('', shortname) # type: ignore[call-arg]
86
+ contnodes = [pending_xref_condition('', '', textnode, condition='resolved'),
87
+ pending_xref_condition('', '', *children, condition='*')]
88
+ result.extend(contnodes)
89
+
90
+ return result
91
+
92
+ def make_xrefs(
93
+ self,
94
+ rolename: str,
95
+ domain: str,
96
+ target: str,
97
+ innernode: type[TextlikeNode] = nodes.emphasis,
98
+ contnode: Node | None = None,
99
+ env: BuildEnvironment | None = None,
100
+ inliner: Inliner | None = None,
101
+ location: Node | None = None,
102
+ ) -> list[Node]:
103
+ delims = r'(\s*[\[\]\(\),](?:\s*o[rf]\s)?\s*|\s+o[rf]\s+|\s*\|\s*|\.\.\.)'
104
+ delims_re = re.compile(delims)
105
+ sub_targets = re.split(delims, target)
106
+
107
+ split_contnode = bool(contnode and contnode.astext() == target)
108
+
109
+ in_literal = False
110
+ results = []
111
+ for sub_target in filter(None, sub_targets):
112
+ if split_contnode:
113
+ contnode = nodes.Text(sub_target)
114
+
115
+ if in_literal or delims_re.match(sub_target):
116
+ results.append(contnode or innernode(sub_target, sub_target)) # type: ignore[call-arg]
117
+ else:
118
+ results.append(self.make_xref(rolename, domain, sub_target,
119
+ innernode, contnode, env, inliner, location))
120
+
121
+ if sub_target in ('Literal', 'typing.Literal', '~typing.Literal'):
122
+ in_literal = True
123
+
124
+ return results
125
+
126
+
127
+ class PyField(PyXrefMixin, Field):
128
+ pass
129
+
130
+
131
+ class PyGroupedField(PyXrefMixin, GroupedField):
132
+ pass
133
+
134
+
135
+ class PyTypedField(PyXrefMixin, TypedField):
136
+ pass
137
+
138
+
139
+ class PyObject(ObjectDescription[tuple[str, str]]):
140
+ """
141
+ Description of a general Python object.
142
+
143
+ :cvar allow_nesting: Class is an object that allows for nested namespaces
144
+ :vartype allow_nesting: bool
145
+ """
146
+
147
+ option_spec: ClassVar[OptionSpec] = {
148
+ 'no-index': directives.flag,
149
+ 'no-index-entry': directives.flag,
150
+ 'no-contents-entry': directives.flag,
151
+ 'no-typesetting': directives.flag,
152
+ 'noindex': directives.flag,
153
+ 'noindexentry': directives.flag,
154
+ 'nocontentsentry': directives.flag,
155
+ 'single-line-parameter-list': directives.flag,
156
+ 'single-line-type-parameter-list': directives.flag,
157
+ 'module': directives.unchanged,
158
+ 'canonical': directives.unchanged,
159
+ 'annotation': directives.unchanged,
160
+ }
161
+
162
+ doc_field_types = [
163
+ PyTypedField('parameter', label=_('Parameters'),
164
+ names=('param', 'parameter', 'arg', 'argument',
165
+ 'keyword', 'kwarg', 'kwparam'),
166
+ typerolename='class', typenames=('paramtype', 'type'),
167
+ can_collapse=True),
168
+ PyTypedField('variable', label=_('Variables'),
169
+ names=('var', 'ivar', 'cvar'),
170
+ typerolename='class', typenames=('vartype',),
171
+ can_collapse=True),
172
+ PyGroupedField('exceptions', label=_('Raises'), rolename='exc',
173
+ names=('raises', 'raise', 'exception', 'except'),
174
+ can_collapse=True),
175
+ Field('returnvalue', label=_('Returns'), has_arg=False,
176
+ names=('returns', 'return')),
177
+ PyField('returntype', label=_('Return type'), has_arg=False,
178
+ names=('rtype',), bodyrolename='class'),
179
+ ]
180
+
181
+ allow_nesting = False
182
+
183
+ def get_signature_prefix(self, sig: str) -> list[nodes.Node]:
184
+ """May return a prefix to put before the object name in the
185
+ signature.
186
+ """
187
+ return []
188
+
189
+ def needs_arglist(self) -> bool:
190
+ """May return true if an empty argument list is to be generated even if
191
+ the document contains none.
192
+ """
193
+ return False
194
+
195
+ def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]:
196
+ """Transform a Python signature into RST nodes.
197
+
198
+ Return (fully qualified name of the thing, classname if any).
199
+
200
+ If inside a class, the current class name is handled intelligently:
201
+ * it is stripped from the displayed name if present
202
+ * it is added to the full name (return value) if not present
203
+ """
204
+ m = py_sig_re.match(sig)
205
+ if m is None:
206
+ raise ValueError
207
+ prefix, name, tp_list, arglist, retann = m.groups()
208
+
209
+ # determine module and class name (if applicable), as well as full name
210
+ modname = self.options.get('module', self.env.ref_context.get('py:module'))
211
+ classname = self.env.ref_context.get('py:class')
212
+ if classname:
213
+ add_module = False
214
+ if prefix and (prefix == classname or
215
+ prefix.startswith(classname + ".")):
216
+ fullname = prefix + name
217
+ # class name is given again in the signature
218
+ prefix = prefix[len(classname):].lstrip('.')
219
+ elif prefix:
220
+ # class name is given in the signature, but different
221
+ # (shouldn't happen)
222
+ fullname = classname + '.' + prefix + name
223
+ else:
224
+ # class name is not given in the signature
225
+ fullname = classname + '.' + name
226
+ else:
227
+ add_module = True
228
+ if prefix:
229
+ classname = prefix.rstrip('.')
230
+ fullname = prefix + name
231
+ else:
232
+ classname = ''
233
+ fullname = name
234
+
235
+ signode['module'] = modname
236
+ signode['class'] = classname
237
+ signode['fullname'] = fullname
238
+
239
+ max_len = (self.env.config.python_maximum_signature_line_length
240
+ or self.env.config.maximum_signature_line_length
241
+ or 0)
242
+
243
+ # determine if the function arguments (without its type parameters)
244
+ # should be formatted on a multiline or not by removing the width of
245
+ # the type parameters list (if any)
246
+ sig_len = len(sig)
247
+ tp_list_span = m.span(3)
248
+ multi_line_parameter_list = (
249
+ 'single-line-parameter-list' not in self.options
250
+ and (sig_len - (tp_list_span[1] - tp_list_span[0])) > max_len > 0
251
+ )
252
+
253
+ # determine whether the type parameter list must be wrapped or not
254
+ arglist_span = m.span(4)
255
+ multi_line_type_parameter_list = (
256
+ 'single-line-type-parameter-list' not in self.options
257
+ and (sig_len - (arglist_span[1] - arglist_span[0])) > max_len > 0
258
+ )
259
+
260
+ sig_prefix = self.get_signature_prefix(sig)
261
+ if sig_prefix:
262
+ if type(sig_prefix) is str:
263
+ msg = ("Python directive method get_signature_prefix()"
264
+ " must return a list of nodes."
265
+ f" Return value was '{sig_prefix}'.")
266
+ raise TypeError(msg)
267
+ signode += addnodes.desc_annotation(str(sig_prefix), '', *sig_prefix)
268
+
269
+ if prefix:
270
+ signode += addnodes.desc_addname(prefix, prefix)
271
+ elif modname and add_module and self.env.config.add_module_names:
272
+ nodetext = modname + '.'
273
+ signode += addnodes.desc_addname(nodetext, nodetext)
274
+
275
+ signode += addnodes.desc_name(name, name)
276
+
277
+ if tp_list:
278
+ try:
279
+ signode += _parse_type_list(tp_list, self.env, multi_line_type_parameter_list)
280
+ except Exception as exc:
281
+ logger.warning("could not parse tp_list (%r): %s", tp_list, exc,
282
+ location=signode)
283
+
284
+ if arglist:
285
+ try:
286
+ signode += _parse_arglist(arglist, self.env, multi_line_parameter_list)
287
+ except SyntaxError:
288
+ # fallback to parse arglist original parser
289
+ # (this may happen if the argument list is incorrectly used
290
+ # as a list of bases when documenting a class)
291
+ # it supports to represent optional arguments (ex. "func(foo [, bar])")
292
+ _pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
293
+ except (NotImplementedError, ValueError) as exc:
294
+ # duplicated parameter names raise ValueError and not a SyntaxError
295
+ logger.warning("could not parse arglist (%r): %s", arglist, exc,
296
+ location=signode)
297
+ _pseudo_parse_arglist(signode, arglist, multi_line_parameter_list)
298
+ else:
299
+ if self.needs_arglist():
300
+ # for callables, add an empty parameter list
301
+ signode += addnodes.desc_parameterlist()
302
+
303
+ if retann:
304
+ children = _parse_annotation(retann, self.env)
305
+ signode += addnodes.desc_returns(retann, '', *children)
306
+
307
+ anno = self.options.get('annotation')
308
+ if anno:
309
+ signode += addnodes.desc_annotation(' ' + anno, '',
310
+ addnodes.desc_sig_space(),
311
+ nodes.Text(anno))
312
+
313
+ return fullname, prefix
314
+
315
+ def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
316
+ if 'fullname' not in sig_node:
317
+ return ()
318
+ modname = sig_node.get('module')
319
+ fullname = sig_node['fullname']
320
+
321
+ if modname:
322
+ return (modname, *fullname.split('.'))
323
+ else:
324
+ return tuple(fullname.split('.'))
325
+
326
+ def get_index_text(self, modname: str, name: tuple[str, str]) -> str:
327
+ """Return the text for the index entry of the object."""
328
+ msg = 'must be implemented in subclasses'
329
+ raise NotImplementedError(msg)
330
+
331
+ def add_target_and_index(self, name_cls: tuple[str, str], sig: str,
332
+ signode: desc_signature) -> None:
333
+ modname = self.options.get('module', self.env.ref_context.get('py:module'))
334
+ fullname = (modname + '.' if modname else '') + name_cls[0]
335
+ node_id = make_id(self.env, self.state.document, '', fullname)
336
+ signode['ids'].append(node_id)
337
+ self.state.document.note_explicit_target(signode)
338
+
339
+ domain = self.env.domains['py']
340
+ domain.note_object(fullname, self.objtype, node_id, location=signode)
341
+
342
+ canonical_name = self.options.get('canonical')
343
+ if canonical_name:
344
+ domain.note_object(canonical_name, self.objtype, node_id, aliased=True,
345
+ location=signode)
346
+
347
+ if 'no-index-entry' not in self.options:
348
+ indextext = self.get_index_text(modname, name_cls)
349
+ if indextext:
350
+ self.indexnode['entries'].append(('single', indextext, node_id, '', None))
351
+
352
+ def before_content(self) -> None:
353
+ """Handle object nesting before content
354
+
355
+ :py:class:`PyObject` represents Python language constructs. For
356
+ constructs that are nestable, such as a Python classes, this method will
357
+ build up a stack of the nesting hierarchy so that it can be later
358
+ de-nested correctly, in :py:meth:`after_content`.
359
+
360
+ For constructs that aren't nestable, the stack is bypassed, and instead
361
+ only the most recent object is tracked. This object prefix name will be
362
+ removed with :py:meth:`after_content`.
363
+ """
364
+ prefix = None
365
+ if self.names:
366
+ # fullname and name_prefix come from the `handle_signature` method.
367
+ # fullname represents the full object name that is constructed using
368
+ # object nesting and explicit prefixes. `name_prefix` is the
369
+ # explicit prefix given in a signature
370
+ (fullname, name_prefix) = self.names[-1]
371
+ if self.allow_nesting:
372
+ prefix = fullname
373
+ elif name_prefix:
374
+ prefix = name_prefix.strip('.')
375
+ if prefix:
376
+ self.env.ref_context['py:class'] = prefix
377
+ if self.allow_nesting:
378
+ classes = self.env.ref_context.setdefault('py:classes', [])
379
+ classes.append(prefix)
380
+ if 'module' in self.options:
381
+ modules = self.env.ref_context.setdefault('py:modules', [])
382
+ modules.append(self.env.ref_context.get('py:module'))
383
+ self.env.ref_context['py:module'] = self.options['module']
384
+
385
+ def after_content(self) -> None:
386
+ """Handle object de-nesting after content
387
+
388
+ If this class is a nestable object, removing the last nested class prefix
389
+ ends further nesting in the object.
390
+
391
+ If this class is not a nestable object, the list of classes should not
392
+ be altered as we didn't affect the nesting levels in
393
+ :py:meth:`before_content`.
394
+ """
395
+ classes = self.env.ref_context.setdefault('py:classes', [])
396
+ if self.allow_nesting:
397
+ with contextlib.suppress(IndexError):
398
+ classes.pop()
399
+
400
+ self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0
401
+ else None)
402
+ if 'module' in self.options:
403
+ modules = self.env.ref_context.setdefault('py:modules', [])
404
+ if modules:
405
+ self.env.ref_context['py:module'] = modules.pop()
406
+ else:
407
+ self.env.ref_context.pop('py:module')
408
+
409
+ def _toc_entry_name(self, sig_node: desc_signature) -> str:
410
+ if not sig_node.get('_toc_parts'):
411
+ return ''
412
+
413
+ config = self.env.app.config
414
+ objtype = sig_node.parent.get('objtype')
415
+ if config.add_function_parentheses and objtype in {'function', 'method'}:
416
+ parens = '()'
417
+ else:
418
+ parens = ''
419
+ *parents, name = sig_node['_toc_parts']
420
+ if config.toc_object_entries_show_parents == 'domain':
421
+ return sig_node.get('fullname', name) + parens
422
+ if config.toc_object_entries_show_parents == 'hide':
423
+ return name + parens
424
+ if config.toc_object_entries_show_parents == 'all':
425
+ return '.'.join([*parents, name + parens])
426
+ return ''
sphinx/domains/rst.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import re
6
- from typing import TYPE_CHECKING, Any, cast
6
+ from typing import TYPE_CHECKING, Any, ClassVar, cast
7
7
 
8
8
  from docutils.parsers.rst import directives
9
9
 
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
24
24
  from sphinx.application import Sphinx
25
25
  from sphinx.builders import Builder
26
26
  from sphinx.environment import BuildEnvironment
27
- from sphinx.util.typing import OptionSpec
27
+ from sphinx.util.typing import ExtensionMetadata, OptionSpec
28
28
 
29
29
  logger = logging.getLogger(__name__)
30
30
 
@@ -35,7 +35,8 @@ class ReSTMarkup(ObjectDescription[str]):
35
35
  """
36
36
  Description of generic reST markup.
37
37
  """
38
- option_spec: OptionSpec = {
38
+
39
+ option_spec: ClassVar[OptionSpec] = {
39
40
  'no-index': directives.flag,
40
41
  'no-index-entry': directives.flag,
41
42
  'no-contents-entry': directives.flag,
@@ -112,6 +113,7 @@ class ReSTDirective(ReSTMarkup):
112
113
  """
113
114
  Description of a reST directive.
114
115
  """
116
+
115
117
  def handle_signature(self, sig: str, signode: desc_signature) -> str:
116
118
  name, args = parse_directive(sig)
117
119
  desc_name = f'.. {name}::'
@@ -139,7 +141,8 @@ class ReSTDirectiveOption(ReSTMarkup):
139
141
  """
140
142
  Description of an option for reST directive.
141
143
  """
142
- option_spec: OptionSpec = ReSTMarkup.option_spec.copy()
144
+
145
+ option_spec: ClassVar[OptionSpec] = ReSTMarkup.option_spec.copy()
143
146
  option_spec.update({
144
147
  'type': directives.unchanged,
145
148
  })
@@ -165,8 +168,8 @@ class ReSTDirectiveOption(ReSTMarkup):
165
168
 
166
169
  directive_name = self.current_directive
167
170
  if directive_name:
168
- prefix = '-'.join([self.objtype, directive_name])
169
- objname = ':'.join([directive_name, name])
171
+ prefix = f'{self.objtype}-{directive_name}'
172
+ objname = f'{directive_name}:{name}'
170
173
  else:
171
174
  prefix = self.objtype
172
175
  objname = name
@@ -199,6 +202,7 @@ class ReSTRole(ReSTMarkup):
199
202
  """
200
203
  Description of a reST role.
201
204
  """
205
+
202
206
  def handle_signature(self, sig: str, signode: desc_signature) -> str:
203
207
  desc_name = f':{sig}:'
204
208
  signode['fullname'] = sig.strip()
@@ -211,6 +215,7 @@ class ReSTRole(ReSTMarkup):
211
215
 
212
216
  class ReSTDomain(Domain):
213
217
  """ReStructuredText domain."""
218
+
214
219
  name = 'rst'
215
220
  label = 'reStructuredText'
216
221
 
@@ -288,7 +293,7 @@ class ReSTDomain(Domain):
288
293
  yield name, name, typ, docname, node_id, 1
289
294
 
290
295
 
291
- def setup(app: Sphinx) -> dict[str, Any]:
296
+ def setup(app: Sphinx) -> ExtensionMetadata:
292
297
  app.add_domain(ReSTDomain)
293
298
 
294
299
  return {
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  from copy import copy
7
- from typing import TYPE_CHECKING, Any, Callable, Final, cast
7
+ from typing import TYPE_CHECKING, Any, Callable, ClassVar, Final, cast
8
8
 
9
9
  from docutils import nodes
10
10
  from docutils.nodes import Element, Node, system_message
@@ -27,14 +27,14 @@ if TYPE_CHECKING:
27
27
  from sphinx.application import Sphinx
28
28
  from sphinx.builders import Builder
29
29
  from sphinx.environment import BuildEnvironment
30
- from sphinx.util.typing import OptionSpec, RoleFunction
30
+ from sphinx.util.typing import ExtensionMetadata, OptionSpec, RoleFunction
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
 
34
34
  # RE for option descriptions
35
35
  option_desc_re = re.compile(r'((?:/|--|-|\+)?[^\s=]+)(=?\s*.*)')
36
36
  # RE for grammar tokens
37
- token_re = re.compile(r'`((~?\w*:)?\w+)`', re.U)
37
+ token_re = re.compile(r'`((~?[\w-]*:)?\w+)`')
38
38
 
39
39
  samp_role = EmphasizedLiteral()
40
40
 
@@ -43,6 +43,7 @@ class GenericObject(ObjectDescription[str]):
43
43
  """
44
44
  A generic x-ref directive registered with Sphinx.add_object_type().
45
45
  """
46
+
46
47
  indextemplate: str = ''
47
48
  parse_node: Callable[[BuildEnvironment, str, desc_signature], str] | None = None
48
49
 
@@ -104,13 +105,14 @@ class Target(SphinxDirective):
104
105
  """
105
106
  Generic target for user-defined cross-reference types.
106
107
  """
108
+
107
109
  indextemplate = ''
108
110
 
109
111
  has_content = False
110
112
  required_arguments = 1
111
113
  optional_arguments = 0
112
114
  final_argument_whitespace = True
113
- option_spec: OptionSpec = {}
115
+ option_spec: ClassVar[OptionSpec] = {}
114
116
 
115
117
  def run(self) -> list[Node]:
116
118
  # normalize whitespace in fullname like XRefRole does
@@ -204,7 +206,7 @@ class Cmdoption(ObjectDescription[str]):
204
206
 
205
207
  def add_target_and_index(self, firstname: str, sig: str, signode: desc_signature) -> None:
206
208
  currprogram = self.env.ref_context.get('std:program')
207
- for optname in signode.get('allnames', []):
209
+ for optname in signode.get('allnames', []): # type: ignore[var-annotated]
208
210
  prefixes = ['cmdoption']
209
211
  if currprogram:
210
212
  prefixes.append(currprogram)
@@ -226,8 +228,8 @@ class Cmdoption(ObjectDescription[str]):
226
228
  descr = _('%s command line option') % currprogram
227
229
  else:
228
230
  descr = _('command line option')
229
- for option in signode.get('allnames', []):
230
- entry = '; '.join([descr, option])
231
+ for option in signode.get('allnames', []): # type: ignore[var-annotated]
232
+ entry = f'{descr}; {option}'
231
233
  self.indexnode['entries'].append(('pair', entry, signode['ids'][0], '', None))
232
234
 
233
235
 
@@ -240,7 +242,7 @@ class Program(SphinxDirective):
240
242
  required_arguments = 1
241
243
  optional_arguments = 0
242
244
  final_argument_whitespace = True
243
- option_spec: OptionSpec = {}
245
+ option_spec: ClassVar[OptionSpec] = {}
244
246
 
245
247
  def run(self) -> list[Node]:
246
248
  program = ws_re.sub('-', self.arguments[0].strip())
@@ -260,7 +262,7 @@ class OptionXRefRole(XRefRole):
260
262
 
261
263
  def split_term_classifiers(line: str) -> list[str | None]:
262
264
  # split line into a term and classifiers. if no classifier, None is used..
263
- parts: list[str | None] = re.split(' +: +', line) + [None]
265
+ parts: list[str | None] = [*re.split(' +: +', line), None]
264
266
  return parts
265
267
 
266
268
 
@@ -304,7 +306,7 @@ class Glossary(SphinxDirective):
304
306
  required_arguments = 0
305
307
  optional_arguments = 0
306
308
  final_argument_whitespace = False
307
- option_spec: OptionSpec = {
309
+ option_spec: ClassVar[OptionSpec] = {
308
310
  'sorted': directives.flag,
309
311
  }
310
312
 
@@ -383,7 +385,7 @@ class Glossary(SphinxDirective):
383
385
  parts = split_term_classifiers(line)
384
386
  # parse the term with inline markup
385
387
  # classifiers (parts[1:]) will not be shown on doctree
386
- textnodes, sysmsg = self.state.inline_text(parts[0], # type: ignore[arg-type]
388
+ textnodes, sysmsg = self.state.inline_text(parts[0],
387
389
  lineno)
388
390
 
389
391
  # use first classifier as a index key
@@ -406,7 +408,7 @@ class Glossary(SphinxDirective):
406
408
  dlist = nodes.definition_list('', *items)
407
409
  dlist['classes'].append('glossary')
408
410
  node += dlist
409
- return messages + [node]
411
+ return [*messages, node]
410
412
 
411
413
 
412
414
  def token_xrefs(text: str, productionGroup: str = '') -> list[Node]:
@@ -451,7 +453,7 @@ class ProductionList(SphinxDirective):
451
453
  required_arguments = 1
452
454
  optional_arguments = 0
453
455
  final_argument_whitespace = True
454
- option_spec: OptionSpec = {}
456
+ option_spec: ClassVar[OptionSpec] = {}
455
457
 
456
458
  def run(self) -> list[Node]:
457
459
  domain = cast(StandardDomain, self.env.get_domain('std'))
@@ -1000,7 +1002,7 @@ class StandardDomain(Domain):
1000
1002
  yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
1001
1003
  for (prog, option), info in self.progoptions.items():
1002
1004
  if prog:
1003
- fullname = ".".join([prog, option])
1005
+ fullname = f'{prog}.{option}'
1004
1006
  yield (fullname, fullname, 'cmdoption', info[0], info[1], 1)
1005
1007
  else:
1006
1008
  yield (option, option, 'cmdoption', info[0], info[1], 1)
@@ -1089,7 +1091,8 @@ class StandardDomain(Domain):
1089
1091
  command.insert(0, progname)
1090
1092
  option = command.pop()
1091
1093
  if command:
1092
- return '.'.join(['-'.join(command), option])
1094
+ command_str = '-'.join(command)
1095
+ return f'{command_str}.{option}'
1093
1096
  else:
1094
1097
  return None
1095
1098
  else:
@@ -1111,7 +1114,7 @@ def warn_missing_reference(app: Sphinx, domain: Domain, node: pending_xref,
1111
1114
  return True
1112
1115
 
1113
1116
 
1114
- def setup(app: Sphinx) -> dict[str, Any]:
1117
+ def setup(app: Sphinx) -> ExtensionMetadata:
1115
1118
  app.add_domain(StandardDomain)
1116
1119
  app.connect('warn-missing-reference', warn_missing_reference)
1117
1120