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,507 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+ import functools
5
+ import operator
6
+ import token
7
+ from collections import deque
8
+ from inspect import Parameter
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from docutils import nodes
12
+
13
+ from sphinx import addnodes
14
+ from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
15
+ from sphinx.pycode.parser import Token, TokenProcessor
16
+ from sphinx.util.inspect import signature_from_str
17
+
18
+ if TYPE_CHECKING:
19
+ from collections.abc import Iterable, Iterator
20
+
21
+ from docutils.nodes import Element, Node
22
+
23
+ from sphinx.environment import BuildEnvironment
24
+
25
+
26
+ def parse_reftarget(reftarget: str, suppress_prefix: bool = False,
27
+ ) -> tuple[str, str, str, bool]:
28
+ """Parse a type string and return (reftype, reftarget, title, refspecific flag)"""
29
+ refspecific = False
30
+ if reftarget.startswith('.'):
31
+ reftarget = reftarget[1:]
32
+ title = reftarget
33
+ refspecific = True
34
+ elif reftarget.startswith('~'):
35
+ reftarget = reftarget[1:]
36
+ title = reftarget.split('.')[-1]
37
+ elif suppress_prefix:
38
+ title = reftarget.split('.')[-1]
39
+ elif reftarget.startswith('typing.'):
40
+ title = reftarget[7:]
41
+ else:
42
+ title = reftarget
43
+
44
+ if reftarget == 'None' or reftarget.startswith('typing.'):
45
+ # typing module provides non-class types. Obj reference is good to refer them.
46
+ reftype = 'obj'
47
+ else:
48
+ reftype = 'class'
49
+
50
+ return reftype, reftarget, title, refspecific
51
+
52
+
53
+ def type_to_xref(target: str, env: BuildEnvironment, *,
54
+ suppress_prefix: bool = False) -> addnodes.pending_xref:
55
+ """Convert a type string to a cross reference node."""
56
+ if env:
57
+ kwargs = {'py:module': env.ref_context.get('py:module'),
58
+ 'py:class': env.ref_context.get('py:class')}
59
+ else:
60
+ kwargs = {}
61
+
62
+ reftype, target, title, refspecific = parse_reftarget(target, suppress_prefix)
63
+
64
+ if env.config.python_use_unqualified_type_names:
65
+ # Note: It would be better to use qualname to describe the object to support support
66
+ # nested classes. But python domain can't access the real python object because this
67
+ # module should work not-dynamically.
68
+ shortname = title.split('.')[-1]
69
+ contnodes: list[Node] = [pending_xref_condition('', shortname, condition='resolved'),
70
+ pending_xref_condition('', title, condition='*')]
71
+ else:
72
+ contnodes = [nodes.Text(title)]
73
+
74
+ return pending_xref('', *contnodes,
75
+ refdomain='py', reftype=reftype, reftarget=target,
76
+ refspecific=refspecific, **kwargs)
77
+
78
+
79
+ def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
80
+ """Parse type annotation."""
81
+ short_literals = env.config.python_display_short_literal_types
82
+
83
+ def unparse(node: ast.AST) -> list[Node]:
84
+ if isinstance(node, ast.Attribute):
85
+ return [nodes.Text(f"{unparse(node.value)[0]}.{node.attr}")]
86
+ if isinstance(node, ast.BinOp):
87
+ result: list[Node] = unparse(node.left)
88
+ result.extend(unparse(node.op))
89
+ result.extend(unparse(node.right))
90
+ return result
91
+ if isinstance(node, ast.BitOr):
92
+ return [addnodes.desc_sig_space(),
93
+ addnodes.desc_sig_punctuation('', '|'),
94
+ addnodes.desc_sig_space()]
95
+ if isinstance(node, ast.Constant):
96
+ if node.value is Ellipsis:
97
+ return [addnodes.desc_sig_punctuation('', "...")]
98
+ if isinstance(node.value, bool):
99
+ return [addnodes.desc_sig_keyword('', repr(node.value))]
100
+ if isinstance(node.value, int):
101
+ return [addnodes.desc_sig_literal_number('', repr(node.value))]
102
+ if isinstance(node.value, str):
103
+ return [addnodes.desc_sig_literal_string('', repr(node.value))]
104
+ else:
105
+ # handles None, which is further handled by type_to_xref later
106
+ # and fallback for other types that should be converted
107
+ return [nodes.Text(repr(node.value))]
108
+ if isinstance(node, ast.Expr):
109
+ return unparse(node.value)
110
+ if isinstance(node, ast.Invert):
111
+ return [addnodes.desc_sig_punctuation('', '~')]
112
+ if isinstance(node, ast.USub):
113
+ return [addnodes.desc_sig_punctuation('', '-')]
114
+ if isinstance(node, ast.List):
115
+ result = [addnodes.desc_sig_punctuation('', '[')]
116
+ if node.elts:
117
+ # check if there are elements in node.elts to only pop the
118
+ # last element of result if the for-loop was run at least
119
+ # once
120
+ for elem in node.elts:
121
+ result.extend(unparse(elem))
122
+ result.append(addnodes.desc_sig_punctuation('', ','))
123
+ result.append(addnodes.desc_sig_space())
124
+ result.pop()
125
+ result.pop()
126
+ result.append(addnodes.desc_sig_punctuation('', ']'))
127
+ return result
128
+ if isinstance(node, ast.Module):
129
+ return functools.reduce(operator.iadd, (unparse(e) for e in node.body), [])
130
+ if isinstance(node, ast.Name):
131
+ return [nodes.Text(node.id)]
132
+ if isinstance(node, ast.Subscript):
133
+ if getattr(node.value, 'id', '') in {'Optional', 'Union'}:
134
+ return _unparse_pep_604_annotation(node)
135
+ if short_literals and getattr(node.value, 'id', '') == 'Literal':
136
+ return _unparse_pep_604_annotation(node)
137
+ result = unparse(node.value)
138
+ result.append(addnodes.desc_sig_punctuation('', '['))
139
+ result.extend(unparse(node.slice))
140
+ result.append(addnodes.desc_sig_punctuation('', ']'))
141
+
142
+ # Wrap the Text nodes inside brackets by literal node if the subscript is a Literal
143
+ if result[0] in ('Literal', 'typing.Literal'):
144
+ for i, subnode in enumerate(result[1:], start=1):
145
+ if isinstance(subnode, nodes.Text):
146
+ result[i] = nodes.literal('', '', subnode)
147
+ return result
148
+ if isinstance(node, ast.UnaryOp):
149
+ return unparse(node.op) + unparse(node.operand)
150
+ if isinstance(node, ast.Tuple):
151
+ if node.elts:
152
+ result = []
153
+ for elem in node.elts:
154
+ result.extend(unparse(elem))
155
+ result.append(addnodes.desc_sig_punctuation('', ','))
156
+ result.append(addnodes.desc_sig_space())
157
+ result.pop()
158
+ result.pop()
159
+ else:
160
+ result = [addnodes.desc_sig_punctuation('', '('),
161
+ addnodes.desc_sig_punctuation('', ')')]
162
+
163
+ return result
164
+ raise SyntaxError # unsupported syntax
165
+
166
+ def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
167
+ subscript = node.slice
168
+
169
+ flattened: list[Node] = []
170
+ if isinstance(subscript, ast.Tuple):
171
+ flattened.extend(unparse(subscript.elts[0]))
172
+ for elt in subscript.elts[1:]:
173
+ flattened.extend(unparse(ast.BitOr()))
174
+ flattened.extend(unparse(elt))
175
+ else:
176
+ # e.g. a Union[] inside an Optional[]
177
+ flattened.extend(unparse(subscript))
178
+
179
+ if getattr(node.value, 'id', '') == 'Optional':
180
+ flattened.extend(unparse(ast.BitOr()))
181
+ flattened.append(nodes.Text('None'))
182
+
183
+ return flattened
184
+
185
+ try:
186
+ tree = ast.parse(annotation, type_comments=True)
187
+ result: list[Node] = []
188
+ for node in unparse(tree):
189
+ if isinstance(node, nodes.literal):
190
+ result.append(node[0])
191
+ elif isinstance(node, nodes.Text) and node.strip():
192
+ if (result and isinstance(result[-1], addnodes.desc_sig_punctuation) and
193
+ result[-1].astext() == '~'):
194
+ result.pop()
195
+ result.append(type_to_xref(str(node), env, suppress_prefix=True))
196
+ else:
197
+ result.append(type_to_xref(str(node), env))
198
+ else:
199
+ result.append(node)
200
+ return result
201
+ except SyntaxError:
202
+ return [type_to_xref(annotation, env)]
203
+
204
+
205
+ class _TypeParameterListParser(TokenProcessor):
206
+ def __init__(self, sig: str) -> None:
207
+ signature = sig.replace('\n', '').strip()
208
+ super().__init__([signature])
209
+ # Each item is a tuple (name, kind, default, annotation) mimicking
210
+ # ``inspect.Parameter`` to allow default values on VAR_POSITIONAL
211
+ # or VAR_KEYWORD parameters.
212
+ self.type_params: list[tuple[str, int, Any, Any]] = []
213
+
214
+ def fetch_type_param_spec(self) -> list[Token]:
215
+ tokens = []
216
+ while current := self.fetch_token():
217
+ tokens.append(current)
218
+ for ldelim, rdelim in ('(', ')'), ('{', '}'), ('[', ']'):
219
+ if current == [token.OP, ldelim]:
220
+ tokens += self.fetch_until([token.OP, rdelim])
221
+ break
222
+ else:
223
+ if current == token.INDENT:
224
+ tokens += self.fetch_until(token.DEDENT)
225
+ elif current.match(
226
+ [token.OP, ':'], [token.OP, '='], [token.OP, ',']):
227
+ tokens.pop()
228
+ break
229
+ return tokens
230
+
231
+ def parse(self) -> None:
232
+ while current := self.fetch_token():
233
+ if current == token.NAME:
234
+ tp_name = current.value.strip()
235
+ if self.previous and self.previous.match([token.OP, '*'], [token.OP, '**']):
236
+ if self.previous == [token.OP, '*']:
237
+ tp_kind = Parameter.VAR_POSITIONAL
238
+ else:
239
+ tp_kind = Parameter.VAR_KEYWORD # type: ignore[assignment]
240
+ else:
241
+ tp_kind = Parameter.POSITIONAL_OR_KEYWORD # type: ignore[assignment]
242
+
243
+ tp_ann: Any = Parameter.empty
244
+ tp_default: Any = Parameter.empty
245
+
246
+ current = self.fetch_token()
247
+ if current and current.match([token.OP, ':'], [token.OP, '=']):
248
+ if current == [token.OP, ':']:
249
+ tokens = self.fetch_type_param_spec()
250
+ tp_ann = self._build_identifier(tokens)
251
+
252
+ if self.current and self.current == [token.OP, '=']:
253
+ tokens = self.fetch_type_param_spec()
254
+ tp_default = self._build_identifier(tokens)
255
+
256
+ if tp_kind != Parameter.POSITIONAL_OR_KEYWORD and tp_ann != Parameter.empty:
257
+ msg = ('type parameter bound or constraint is not allowed '
258
+ f'for {tp_kind.description} parameters')
259
+ raise SyntaxError(msg)
260
+
261
+ type_param = (tp_name, tp_kind, tp_default, tp_ann)
262
+ self.type_params.append(type_param)
263
+
264
+ def _build_identifier(self, tokens: list[Token]) -> str:
265
+ from itertools import chain, islice
266
+
267
+ def triplewise(iterable: Iterable[Token]) -> Iterator[tuple[Token, ...]]:
268
+ # sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
269
+ it = iter(iterable)
270
+ window = deque(islice(it, 3), maxlen=3)
271
+ if len(window) == 3:
272
+ yield tuple(window)
273
+ for x in it:
274
+ window.append(x)
275
+ yield tuple(window)
276
+
277
+ idents: list[str] = []
278
+ tokens: Iterable[Token] = iter(tokens) # type: ignore[no-redef]
279
+ # do not format opening brackets
280
+ for tok in tokens:
281
+ if not tok.match([token.OP, '('], [token.OP, '['], [token.OP, '{']):
282
+ # check if the first non-delimiter character is an unpack operator
283
+ is_unpack_operator = tok.match([token.OP, '*'], [token.OP, ['**']])
284
+ idents.append(self._pformat_token(tok, native=is_unpack_operator))
285
+ break
286
+ idents.append(tok.value)
287
+
288
+ # check the remaining tokens
289
+ stop = Token(token.ENDMARKER, '', (-1, -1), (-1, -1), '<sentinel>')
290
+ is_unpack_operator = False
291
+ for tok, op, after in triplewise(chain(tokens, [stop, stop])):
292
+ ident = self._pformat_token(tok, native=is_unpack_operator)
293
+ idents.append(ident)
294
+ # determine if the next token is an unpack operator depending
295
+ # on the left and right hand side of the operator symbol
296
+ is_unpack_operator = (
297
+ op.match([token.OP, '*'], [token.OP, '**']) and not (
298
+ tok.match(token.NAME, token.NUMBER, token.STRING,
299
+ [token.OP, ')'], [token.OP, ']'], [token.OP, '}'])
300
+ and after.match(token.NAME, token.NUMBER, token.STRING,
301
+ [token.OP, '('], [token.OP, '['], [token.OP, '{'])
302
+ )
303
+ )
304
+
305
+ return ''.join(idents).strip()
306
+
307
+ def _pformat_token(self, tok: Token, native: bool = False) -> str:
308
+ if native:
309
+ return tok.value
310
+
311
+ if tok.match(token.NEWLINE, token.ENDMARKER):
312
+ return ''
313
+
314
+ if tok.match([token.OP, ':'], [token.OP, ','], [token.OP, '#']):
315
+ return f'{tok.value} '
316
+
317
+ # Arithmetic operators are allowed because PEP 695 specifies the
318
+ # default type parameter to be *any* expression (so "T1 << T2" is
319
+ # allowed if it makes sense). The caller is responsible to ensure
320
+ # that a multiplication operator ("*") is not to be confused with
321
+ # an unpack operator (which will not be surrounded by spaces).
322
+ #
323
+ # The operators are ordered according to how likely they are to
324
+ # be used and for (possible) future implementations (e.g., "&" for
325
+ # an intersection type).
326
+ if tok.match(
327
+ # Most likely operators to appear
328
+ [token.OP, '='], [token.OP, '|'],
329
+ # Type composition (future compatibility)
330
+ [token.OP, '&'], [token.OP, '^'], [token.OP, '<'], [token.OP, '>'],
331
+ # Unlikely type composition
332
+ [token.OP, '+'], [token.OP, '-'], [token.OP, '*'], [token.OP, '**'],
333
+ # Unlikely operators but included for completeness
334
+ [token.OP, '@'], [token.OP, '/'], [token.OP, '//'], [token.OP, '%'],
335
+ [token.OP, '<<'], [token.OP, '>>'], [token.OP, '>>>'],
336
+ [token.OP, '<='], [token.OP, '>='], [token.OP, '=='], [token.OP, '!='],
337
+ ):
338
+ return f' {tok.value} '
339
+
340
+ return tok.value
341
+
342
+
343
+ def _parse_type_list(
344
+ tp_list: str, env: BuildEnvironment,
345
+ multi_line_parameter_list: bool = False,
346
+ ) -> addnodes.desc_type_parameter_list:
347
+ """Parse a list of type parameters according to PEP 695."""
348
+ type_params = addnodes.desc_type_parameter_list(tp_list)
349
+ type_params['multi_line_parameter_list'] = multi_line_parameter_list
350
+ # formal parameter names are interpreted as type parameter names and
351
+ # type annotations are interpreted as type parameter bound or constraints
352
+ parser = _TypeParameterListParser(tp_list)
353
+ parser.parse()
354
+ for (tp_name, tp_kind, tp_default, tp_ann) in parser.type_params:
355
+ # no positional-only or keyword-only allowed in a type parameters list
356
+ if tp_kind in {Parameter.POSITIONAL_ONLY, Parameter.KEYWORD_ONLY}:
357
+ msg = ('positional-only or keyword-only parameters '
358
+ 'are prohibited in type parameter lists')
359
+ raise SyntaxError(msg)
360
+
361
+ node = addnodes.desc_type_parameter()
362
+ if tp_kind == Parameter.VAR_POSITIONAL:
363
+ node += addnodes.desc_sig_operator('', '*')
364
+ elif tp_kind == Parameter.VAR_KEYWORD:
365
+ node += addnodes.desc_sig_operator('', '**')
366
+ node += addnodes.desc_sig_name('', tp_name)
367
+
368
+ if tp_ann is not Parameter.empty:
369
+ annotation = _parse_annotation(tp_ann, env)
370
+ if not annotation:
371
+ continue
372
+
373
+ node += addnodes.desc_sig_punctuation('', ':')
374
+ node += addnodes.desc_sig_space()
375
+
376
+ type_ann_expr = addnodes.desc_sig_name('', '',
377
+ *annotation) # type: ignore[arg-type]
378
+ # a type bound is ``T: U`` whereas type constraints
379
+ # must be enclosed with parentheses. ``T: (U, V)``
380
+ if tp_ann.startswith('(') and tp_ann.endswith(')'):
381
+ type_ann_text = type_ann_expr.astext()
382
+ if type_ann_text.startswith('(') and type_ann_text.endswith(')'):
383
+ node += type_ann_expr
384
+ else:
385
+ # surrounding braces are lost when using _parse_annotation()
386
+ node += addnodes.desc_sig_punctuation('', '(')
387
+ node += type_ann_expr # type constraint
388
+ node += addnodes.desc_sig_punctuation('', ')')
389
+ else:
390
+ node += type_ann_expr # type bound
391
+
392
+ if tp_default is not Parameter.empty:
393
+ # Always surround '=' with spaces, even if there is no annotation
394
+ node += addnodes.desc_sig_space()
395
+ node += addnodes.desc_sig_operator('', '=')
396
+ node += addnodes.desc_sig_space()
397
+ node += nodes.inline('', tp_default,
398
+ classes=['default_value'],
399
+ support_smartquotes=False)
400
+
401
+ type_params += node
402
+ return type_params
403
+
404
+
405
+ def _parse_arglist(
406
+ arglist: str, env: BuildEnvironment, multi_line_parameter_list: bool = False,
407
+ ) -> addnodes.desc_parameterlist:
408
+ """Parse a list of arguments using AST parser"""
409
+ params = addnodes.desc_parameterlist(arglist)
410
+ params['multi_line_parameter_list'] = multi_line_parameter_list
411
+ sig = signature_from_str('(%s)' % arglist)
412
+ last_kind = None
413
+ for param in sig.parameters.values():
414
+ if param.kind != param.POSITIONAL_ONLY and last_kind == param.POSITIONAL_ONLY:
415
+ # PEP-570: Separator for Positional Only Parameter: /
416
+ params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
417
+ if param.kind == param.KEYWORD_ONLY and last_kind in (param.POSITIONAL_OR_KEYWORD,
418
+ param.POSITIONAL_ONLY,
419
+ None):
420
+ # PEP-3102: Separator for Keyword Only Parameter: *
421
+ params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '*'))
422
+
423
+ node = addnodes.desc_parameter()
424
+ if param.kind == param.VAR_POSITIONAL:
425
+ node += addnodes.desc_sig_operator('', '*')
426
+ node += addnodes.desc_sig_name('', param.name)
427
+ elif param.kind == param.VAR_KEYWORD:
428
+ node += addnodes.desc_sig_operator('', '**')
429
+ node += addnodes.desc_sig_name('', param.name)
430
+ else:
431
+ node += addnodes.desc_sig_name('', param.name)
432
+
433
+ if param.annotation is not param.empty:
434
+ children = _parse_annotation(param.annotation, env)
435
+ node += addnodes.desc_sig_punctuation('', ':')
436
+ node += addnodes.desc_sig_space()
437
+ node += addnodes.desc_sig_name('', '', *children) # type: ignore[arg-type]
438
+ if param.default is not param.empty:
439
+ if param.annotation is not param.empty:
440
+ node += addnodes.desc_sig_space()
441
+ node += addnodes.desc_sig_operator('', '=')
442
+ node += addnodes.desc_sig_space()
443
+ else:
444
+ node += addnodes.desc_sig_operator('', '=')
445
+ node += nodes.inline('', param.default, classes=['default_value'],
446
+ support_smartquotes=False)
447
+
448
+ params += node
449
+ last_kind = param.kind
450
+
451
+ if last_kind == Parameter.POSITIONAL_ONLY:
452
+ # PEP-570: Separator for Positional Only Parameter: /
453
+ params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
454
+
455
+ return params
456
+
457
+
458
+ def _pseudo_parse_arglist(
459
+ signode: desc_signature, arglist: str, multi_line_parameter_list: bool = False,
460
+ ) -> None:
461
+ """"Parse" a list of arguments separated by commas.
462
+
463
+ Arguments can have "optional" annotations given by enclosing them in
464
+ brackets. Currently, this will split at any comma, even if it's inside a
465
+ string literal (e.g. default argument value).
466
+ """
467
+ paramlist = addnodes.desc_parameterlist()
468
+ paramlist['multi_line_parameter_list'] = multi_line_parameter_list
469
+ stack: list[Element] = [paramlist]
470
+ try:
471
+ for argument in arglist.split(','):
472
+ argument = argument.strip()
473
+ ends_open = ends_close = 0
474
+ while argument.startswith('['):
475
+ stack.append(addnodes.desc_optional())
476
+ stack[-2] += stack[-1]
477
+ argument = argument[1:].strip()
478
+ while argument.startswith(']'):
479
+ stack.pop()
480
+ argument = argument[1:].strip()
481
+ while argument.endswith(']') and not argument.endswith('[]'):
482
+ ends_close += 1
483
+ argument = argument[:-1].strip()
484
+ while argument.endswith('['):
485
+ ends_open += 1
486
+ argument = argument[:-1].strip()
487
+ if argument:
488
+ stack[-1] += addnodes.desc_parameter(
489
+ '', '', addnodes.desc_sig_name(argument, argument))
490
+ while ends_open:
491
+ stack.append(addnodes.desc_optional())
492
+ stack[-2] += stack[-1]
493
+ ends_open -= 1
494
+ while ends_close:
495
+ stack.pop()
496
+ ends_close -= 1
497
+ if len(stack) != 1:
498
+ raise IndexError
499
+ except IndexError:
500
+ # if there are too few or too many elements on the stack, just give up
501
+ # and treat the whole argument list as one argument, discarding the
502
+ # already partially populated paramlist node
503
+ paramlist = addnodes.desc_parameterlist()
504
+ paramlist += addnodes.desc_parameter(arglist, arglist)
505
+ signode += paramlist
506
+ else:
507
+ signode += paramlist