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

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

Potentially problematic release.


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

Files changed (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.0.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.6.dist-info → sphinx-7.3.0.dist-info}/METADATA +13 -12
  369. sphinx-7.3.0.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.0.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.6.dist-info → sphinx-7.3.0.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import operator
5
6
  import time
6
7
  from codecs import open
7
8
  from collections import defaultdict
@@ -16,7 +17,7 @@ from sphinx.builders import Builder
16
17
  from sphinx.errors import ThemeError
17
18
  from sphinx.locale import __
18
19
  from sphinx.util import logging
19
- from sphinx.util.console import bold # type: ignore[attr-defined]
20
+ from sphinx.util.console import bold
20
21
  from sphinx.util.display import status_iterator
21
22
  from sphinx.util.i18n import CatalogInfo, docname_to_domain
22
23
  from sphinx.util.index_entries import split_index_msg
@@ -27,18 +28,21 @@ from sphinx.util.template import SphinxRenderer
27
28
 
28
29
  if TYPE_CHECKING:
29
30
  import os
30
- from collections.abc import Generator, Iterable
31
+ from collections.abc import Iterable, Iterator
31
32
 
32
33
  from docutils.nodes import Element
33
34
 
34
35
  from sphinx.application import Sphinx
36
+ from sphinx.config import Config
37
+ from sphinx.util.typing import ExtensionMetadata
35
38
 
36
39
  logger = logging.getLogger(__name__)
37
40
 
38
41
 
39
42
  class Message:
40
43
  """An entry of translatable message."""
41
- def __init__(self, text: str, locations: list[tuple[str, int]], uuids: list[str]):
44
+
45
+ def __init__(self, text: str, locations: list[tuple[str, int]], uuids: list[str]) -> None:
42
46
  self.text = text
43
47
  self.locations = locations
44
48
  self.uuids = uuids
@@ -64,9 +68,9 @@ class Catalog:
64
68
  line = origin.line
65
69
  if line is None:
66
70
  line = -1
67
- self.metadata[msg].append((origin.source, line, origin.uid))
71
+ self.metadata[msg].append((origin.source, line, origin.uid)) # type: ignore[arg-type]
68
72
 
69
- def __iter__(self) -> Generator[Message, None, None]:
73
+ def __iter__(self) -> Iterator[Message]:
70
74
  for message in self.messages:
71
75
  positions = sorted({(source, line) for source, line, uuid
72
76
  in self.metadata[message]})
@@ -118,6 +122,7 @@ class I18nTags(Tags):
118
122
  To translate all text inside of only nodes, this class
119
123
  always returns True value even if no tags are defined.
120
124
  """
125
+
121
126
  def eval_condition(self, condition: Any) -> bool:
122
127
  return True
123
128
 
@@ -126,6 +131,7 @@ class I18nBuilder(Builder):
126
131
  """
127
132
  General i18n builder.
128
133
  """
134
+
129
135
  name = 'i18n'
130
136
  versioning_method = 'text'
131
137
  use_message_catalog = False
@@ -211,6 +217,7 @@ class MessageCatalogBuilder(I18nBuilder):
211
217
  """
212
218
  Builds gettext-style message catalogs (.pot files).
213
219
  """
220
+
214
221
  name = 'gettext'
215
222
  epilog = __('The message catalogs are in %(outdir)s.')
216
223
 
@@ -275,7 +282,7 @@ class MessageCatalogBuilder(I18nBuilder):
275
282
  __("writing message catalogs... "),
276
283
  "darkgreen", len(self.catalogs),
277
284
  self.app.verbosity,
278
- lambda textdomain__: textdomain__[0]):
285
+ operator.itemgetter(0)):
279
286
  # noop if config.gettext_compact is set
280
287
  ensuredir(path.join(self.outdir, path.dirname(textdomain)))
281
288
 
@@ -288,7 +295,16 @@ class MessageCatalogBuilder(I18nBuilder):
288
295
  pofile.write(content)
289
296
 
290
297
 
291
- def setup(app: Sphinx) -> dict[str, Any]:
298
+ def _gettext_compact_validator(app: Sphinx, config: Config) -> None:
299
+ gettext_compact = config.gettext_compact
300
+ # Convert 0/1 from the command line to ``bool`` types
301
+ if gettext_compact == '0':
302
+ config.gettext_compact = False # type: ignore[attr-defined]
303
+ elif gettext_compact == '1':
304
+ config.gettext_compact = True # type: ignore[attr-defined]
305
+
306
+
307
+ def setup(app: Sphinx) -> ExtensionMetadata:
292
308
  app.add_builder(MessageCatalogBuilder)
293
309
 
294
310
  app.add_config_value('gettext_compact', True, 'gettext', {bool, str})
@@ -298,6 +314,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
298
314
  app.add_config_value('gettext_additional_targets', [], 'env')
299
315
  app.add_config_value('gettext_last_translator', 'FULL NAME <EMAIL@ADDRESS>', 'gettext')
300
316
  app.add_config_value('gettext_language_team', 'LANGUAGE <LL@li.org>', 'gettext')
317
+ app.connect('config-inited', _gettext_compact_validator, priority=800)
301
318
 
302
319
  return {
303
320
  'version': 'builtin',
@@ -10,6 +10,7 @@ import posixpath
10
10
  import re
11
11
  import sys
12
12
  import time
13
+ import types
13
14
  import warnings
14
15
  from os import path
15
16
  from typing import IO, TYPE_CHECKING, Any
@@ -49,13 +50,16 @@ from sphinx.writers.html import HTMLWriter
49
50
  from sphinx.writers.html5 import HTML5Translator
50
51
 
51
52
  if TYPE_CHECKING:
52
- from collections.abc import Iterable, Iterator, Sequence
53
+ from collections.abc import Iterable, Iterator, Set
53
54
 
54
55
  from docutils.nodes import Node
56
+ from docutils.readers import Reader
55
57
 
56
58
  from sphinx.application import Sphinx
59
+ from sphinx.config import _ConfigRebuild
57
60
  from sphinx.environment import BuildEnvironment
58
61
  from sphinx.util.tags import Tags
62
+ from sphinx.util.typing import ExtensionMetadata
59
63
 
60
64
  #: the filename for the inventory of objects
61
65
  INVENTORY_FILENAME = 'objects.inv'
@@ -75,16 +79,20 @@ DOMAIN_INDEX_TYPE = tuple[
75
79
  ]
76
80
 
77
81
 
78
- def get_stable_hash(obj: Any) -> str:
79
- """
80
- Return a stable hash for a Python data structure. We can't just use
81
- the md5 of str(obj) since for example dictionary items are enumerated
82
- in unpredictable order due to hash randomization in newer Pythons.
82
+ def _stable_hash(obj: Any) -> str:
83
+ """Return a stable hash for a Python data structure.
84
+
85
+ We can't just use the md5 of str(obj) as the order of collections
86
+ may be random.
83
87
  """
84
88
  if isinstance(obj, dict):
85
- return get_stable_hash(list(obj.items()))
86
- elif isinstance(obj, (list, tuple)):
87
- obj = sorted(get_stable_hash(o) for o in obj)
89
+ obj = sorted(map(_stable_hash, obj.items()))
90
+ if isinstance(obj, (list, tuple, set, frozenset)):
91
+ obj = sorted(map(_stable_hash, obj))
92
+ elif isinstance(obj, (type, types.FunctionType)):
93
+ # The default repr() of functions includes the ID, which is not ideal.
94
+ # We use the fully qualified name instead.
95
+ obj = f'{obj.__module__}.{obj.__qualname__}'
88
96
  return hashlib.md5(str(obj).encode(), usedforsecurity=False).hexdigest()
89
97
 
90
98
 
@@ -107,7 +115,7 @@ class BuildInfo:
107
115
  """
108
116
 
109
117
  @classmethod
110
- def load(cls, f: IO) -> BuildInfo:
118
+ def load(cls: type[BuildInfo], f: IO) -> BuildInfo:
111
119
  try:
112
120
  lines = f.readlines()
113
121
  assert lines[0].rstrip() == '# Sphinx build info version 1'
@@ -125,17 +133,17 @@ class BuildInfo:
125
133
  self,
126
134
  config: Config | None = None,
127
135
  tags: Tags | None = None,
128
- config_categories: Sequence[str] = (),
136
+ config_categories: Set[_ConfigRebuild] = frozenset(),
129
137
  ) -> None:
130
138
  self.config_hash = ''
131
139
  self.tags_hash = ''
132
140
 
133
141
  if config:
134
142
  values = {c.name: c.value for c in config.filter(config_categories)}
135
- self.config_hash = get_stable_hash(values)
143
+ self.config_hash = _stable_hash(values)
136
144
 
137
145
  if tags:
138
- self.tags_hash = get_stable_hash(sorted(tags))
146
+ self.tags_hash = _stable_hash(sorted(tags))
139
147
 
140
148
  def __eq__(self, other: BuildInfo) -> bool: # type: ignore[override]
141
149
  return (self.config_hash == other.config_hash and
@@ -154,6 +162,7 @@ class StandaloneHTMLBuilder(Builder):
154
162
  """
155
163
  Builds standalone HTML docs.
156
164
  """
165
+
157
166
  name = 'html'
158
167
  format = 'html'
159
168
  epilog = __('The HTML pages are in %(outdir)s.')
@@ -192,7 +201,7 @@ class StandaloneHTMLBuilder(Builder):
192
201
  self._js_files: list[_JavaScript] = []
193
202
 
194
203
  # Cached Publisher for writing doctrees to HTML
195
- reader = docutils.readers.doctree.Reader(parser_name='restructuredtext')
204
+ reader: Reader = docutils.readers.doctree.Reader(parser_name='restructuredtext')
196
205
  pub = Publisher(
197
206
  reader=reader,
198
207
  parser=reader.parser,
@@ -234,7 +243,7 @@ class StandaloneHTMLBuilder(Builder):
234
243
  self.use_index = self.get_builder_config('use_index', 'html')
235
244
 
236
245
  def create_build_info(self) -> BuildInfo:
237
- return BuildInfo(self.config, self.tags, ['html'])
246
+ return BuildInfo(self.config, self.tags, frozenset({'html'}))
238
247
 
239
248
  def _get_translations_js(self) -> str:
240
249
  candidates = [path.join(dir, self.config.language,
@@ -256,8 +265,7 @@ class StandaloneHTMLBuilder(Builder):
256
265
  elif self.config.html_style is not None:
257
266
  yield from self.config.html_style
258
267
  elif self.theme:
259
- stylesheet = self.theme.get_config('theme', 'stylesheet')
260
- yield from map(str.strip, stylesheet.split(','))
268
+ yield from self.theme.stylesheets
261
269
  else:
262
270
  yield 'default.css'
263
271
 
@@ -266,9 +274,9 @@ class StandaloneHTMLBuilder(Builder):
266
274
 
267
275
  def init_templates(self) -> None:
268
276
  theme_factory = HTMLThemeFactory(self.app)
269
- themename, themeoptions = self.get_theme_config()
270
- self.theme = theme_factory.create(themename)
271
- self.theme_options = themeoptions.copy()
277
+ theme_name, theme_options = self.get_theme_config()
278
+ self.theme = theme_factory.create(theme_name)
279
+ self.theme_options = theme_options
272
280
  self.create_template_bridge()
273
281
  self.templates.init(self, self.theme)
274
282
 
@@ -277,13 +285,15 @@ class StandaloneHTMLBuilder(Builder):
277
285
  if self.config.pygments_style is not None:
278
286
  style = self.config.pygments_style
279
287
  elif self.theme:
280
- style = self.theme.get_config('theme', 'pygments_style', 'none')
288
+ # From the ``pygments_style`` theme setting
289
+ style = self.theme.pygments_style_default or 'none'
281
290
  else:
282
291
  style = 'sphinx'
283
292
  self.highlighter = PygmentsBridge('html', style)
284
293
 
285
294
  if self.theme:
286
- dark_style = self.theme.get_config('theme', 'pygments_dark_style', None)
295
+ # From the ``pygments_dark_style`` theme setting
296
+ dark_style = self.theme.pygments_style_dark
287
297
  else:
288
298
  dark_style = None
289
299
 
@@ -298,8 +308,7 @@ class StandaloneHTMLBuilder(Builder):
298
308
 
299
309
  @property
300
310
  def css_files(self) -> list[_CascadingStyleSheet]:
301
- _deprecation_warning(__name__, f'{self.__class__.__name__}.css_files', '',
302
- remove=(9, 0))
311
+ _deprecation_warning(__name__, f'{self.__class__.__name__}.css_files', remove=(9, 0))
303
312
  return self._css_files
304
313
 
305
314
  def init_css_files(self) -> None:
@@ -325,8 +334,8 @@ class StandaloneHTMLBuilder(Builder):
325
334
 
326
335
  @property
327
336
  def script_files(self) -> list[_JavaScript]:
328
- _deprecation_warning(__name__, f'{self.__class__.__name__}.script_files', '',
329
- remove=(9, 0))
337
+ canonical_name = f'{self.__class__.__name__}.script_files'
338
+ _deprecation_warning(__name__, canonical_name, remove=(9, 0))
330
339
  return self._js_files
331
340
 
332
341
  def init_js_files(self) -> None:
@@ -429,7 +438,7 @@ class StandaloneHTMLBuilder(Builder):
429
438
  doc.append(node)
430
439
  self._publisher.set_source(doc)
431
440
  self._publisher.publish()
432
- return self._publisher.writer.parts # type: ignore[union-attr]
441
+ return self._publisher.writer.parts
433
442
 
434
443
  def prepare_writing(self, docnames: set[str]) -> None:
435
444
  # create the search indexer
@@ -547,10 +556,11 @@ class StandaloneHTMLBuilder(Builder):
547
556
  'html5_doctype': True,
548
557
  }
549
558
  if self.theme:
550
- self.globalcontext.update(
551
- ('theme_' + key, val) for (key, val) in
552
- self.theme.get_options(self.theme_options).items())
553
- self.globalcontext.update(self.config.html_context)
559
+ self.globalcontext |= {
560
+ f'theme_{key}': val for key, val in
561
+ self.theme.get_options(self.theme_options).items()
562
+ }
563
+ self.globalcontext |= self.config.html_context
554
564
 
555
565
  def get_doc_context(self, docname: str, body: str, metatags: str) -> dict[str, Any]:
556
566
  """Collect items for the template context of a page."""
@@ -708,10 +718,8 @@ class StandaloneHTMLBuilder(Builder):
708
718
  # the total count of lines for each index letter, used to distribute
709
719
  # the entries into two columns
710
720
  genindex = IndexEntries(self.env).create_index(self)
711
- indexcounts = []
712
- for _k, entries in genindex:
713
- indexcounts.append(sum(1 + len(subitems)
714
- for _, (_, subitems, _) in entries))
721
+ indexcounts = [sum(1 + len(subitems) for _, (_, subitems, _) in entries)
722
+ for _k, entries in genindex]
715
723
 
716
724
  genindexcontext = {
717
725
  'genindexentries': genindex,
@@ -760,7 +768,7 @@ class StandaloneHTMLBuilder(Builder):
760
768
 
761
769
  def copy_download_files(self) -> None:
762
770
  def to_relpath(f: str) -> str:
763
- return relative_path(self.srcdir, f) # type: ignore[arg-type]
771
+ return relative_path(self.srcdir, f)
764
772
 
765
773
  # copy downloadable files
766
774
  if self.env.dlfiles:
@@ -777,7 +785,7 @@ class StandaloneHTMLBuilder(Builder):
777
785
  path.join(self.srcdir, src), err)
778
786
 
779
787
  def create_pygments_style_file(self) -> None:
780
- """create a style file for pygments."""
788
+ """Create a style file for pygments."""
781
789
  with open(path.join(self.outdir, '_static', 'pygments.css'), 'w',
782
790
  encoding="utf-8") as f:
783
791
  f.write(self.highlighter.get_stylesheet())
@@ -810,7 +818,7 @@ class StandaloneHTMLBuilder(Builder):
810
818
  filename, error)
811
819
 
812
820
  if self.theme:
813
- for entry in self.theme.get_theme_dirs()[::-1]:
821
+ for entry in reversed(self.theme.get_theme_dirs()):
814
822
  copy_asset(path.join(entry, 'static'),
815
823
  path.join(self.outdir, '_static'),
816
824
  excluded=DOTFILES, context=context,
@@ -821,7 +829,7 @@ class StandaloneHTMLBuilder(Builder):
821
829
  logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
822
830
  filename, error)
823
831
 
824
- excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
832
+ excluded = Matcher([*self.config.exclude_patterns, '**/.*'])
825
833
  for entry in self.config.html_static_path:
826
834
  copy_asset(path.join(self.confdir, entry),
827
835
  path.join(self.outdir, '_static'),
@@ -858,7 +866,7 @@ class StandaloneHTMLBuilder(Builder):
858
866
  logger.warning(__('cannot copy static file %r'), err)
859
867
 
860
868
  def copy_extra_files(self) -> None:
861
- """copy html_extra_path files."""
869
+ """Copy html_extra_path files."""
862
870
  try:
863
871
  with progress_message(__('copying extra files')):
864
872
  excluded = Matcher(self.config.exclude_patterns)
@@ -878,7 +886,7 @@ class StandaloneHTMLBuilder(Builder):
878
886
  def cleanup(self) -> None:
879
887
  # clean up theme stuff
880
888
  if self.theme:
881
- self.theme.cleanup()
889
+ self.theme._cleanup()
882
890
 
883
891
  def post_process_images(self, doctree: Node) -> None:
884
892
  """Pick the best candidate for an image and link down-scaled images to
@@ -888,7 +896,7 @@ class StandaloneHTMLBuilder(Builder):
888
896
 
889
897
  if self.config.html_scaled_image_link and self.html_scaled_image_link:
890
898
  for node in doctree.findall(nodes.image):
891
- if not any((key in node) for key in ['scale', 'width', 'height']):
899
+ if not any((key in node) for key in ('scale', 'width', 'height')):
892
900
  # resizing options are not given. scaled image link is available
893
901
  # only for resized images.
894
902
  continue
@@ -933,7 +941,7 @@ class StandaloneHTMLBuilder(Builder):
933
941
  if self.indexer is not None and title:
934
942
  filename = self.env.doc2path(pagename, base=False)
935
943
  metadata = self.env.metadata.get(pagename, {})
936
- if 'nosearch' in metadata:
944
+ if 'no-search' in metadata or 'nosearch' in metadata:
937
945
  self.indexer.feed(pagename, filename, '', new_document(''))
938
946
  else:
939
947
  self.indexer.feed(pagename, filename, title, doctree)
@@ -953,27 +961,11 @@ class StandaloneHTMLBuilder(Builder):
953
961
  def has_wildcard(pattern: str) -> bool:
954
962
  return any(char in pattern for char in '*?[')
955
963
 
956
- sidebars = None
957
964
  matched = None
958
965
  customsidebar = None
959
966
 
960
967
  # default sidebars settings for selected theme
961
- if self.theme.name == 'alabaster':
962
- # provide default settings for alabaster (for compatibility)
963
- # Note: this will be removed before Sphinx-2.0
964
- try:
965
- # get default sidebars settings from alabaster (if defined)
966
- theme_default_sidebars = self.theme.config.get('theme', 'sidebars')
967
- if theme_default_sidebars:
968
- sidebars = [name.strip() for name in theme_default_sidebars.split(',')]
969
- except Exception:
970
- # fallback to better default settings
971
- sidebars = ['about.html', 'navigation.html', 'relations.html',
972
- 'searchbox.html', 'donate.html']
973
- else:
974
- theme_default_sidebars = self.theme.get_config('theme', 'sidebars', None)
975
- if theme_default_sidebars:
976
- sidebars = [name.strip() for name in theme_default_sidebars.split(',')]
968
+ sidebars = list(self.theme.sidebar_templates)
977
969
 
978
970
  # user sidebar settings
979
971
  html_sidebars = self.get_builder_config('sidebars', 'html')
@@ -992,7 +984,7 @@ class StandaloneHTMLBuilder(Builder):
992
984
  matched = pattern
993
985
  sidebars = patsidebars
994
986
 
995
- if sidebars is None:
987
+ if len(sidebars) == 0:
996
988
  # keep defaults
997
989
  pass
998
990
 
@@ -1040,9 +1032,7 @@ class StandaloneHTMLBuilder(Builder):
1040
1032
  return True
1041
1033
  if name == 'search' and self.search:
1042
1034
  return True
1043
- if name == 'genindex' and self.get_builder_config('use_index', 'html'):
1044
- return True
1045
- return False
1035
+ return name == 'genindex' and self.get_builder_config('use_index', 'html')
1046
1036
  ctx['hasdoc'] = hasdoc
1047
1037
 
1048
1038
  ctx['toctree'] = lambda **kwargs: self._get_local_toctree(pagename, **kwargs)
@@ -1055,13 +1045,16 @@ class StandaloneHTMLBuilder(Builder):
1055
1045
  outdir = self.app.outdir
1056
1046
 
1057
1047
  def css_tag(css: _CascadingStyleSheet) -> str:
1058
- attrs = []
1059
- for key, value in css.attributes.items():
1060
- if value is not None:
1061
- attrs.append(f'{key}="{html.escape(value, quote=True)}"')
1048
+ attrs = [f'{key}="{html.escape(value, quote=True)}"'
1049
+ for key, value in css.attributes.items()
1050
+ if value is not None]
1062
1051
  uri = pathto(os.fspath(css.filename), resource=True)
1063
- if checksum := _file_checksum(outdir, css.filename):
1064
- uri += f'?v={checksum}'
1052
+ # the EPUB format does not allow the use of query components
1053
+ # the Windows help compiler requires that css links
1054
+ # don't have a query component
1055
+ if self.name not in {'epub', 'htmlhelp'}:
1056
+ if checksum := _file_checksum(outdir, css.filename):
1057
+ uri += f'?v={checksum}'
1065
1058
  return f'<link {" ".join(sorted(attrs))} href="{uri}" />'
1066
1059
 
1067
1060
  ctx['css_tag'] = css_tag
@@ -1071,13 +1064,10 @@ class StandaloneHTMLBuilder(Builder):
1071
1064
  # str value (old styled)
1072
1065
  return f'<script src="{pathto(js, resource=True)}"></script>'
1073
1066
 
1074
- attrs = []
1075
1067
  body = js.attributes.get('body', '')
1076
- for key, value in js.attributes.items():
1077
- if key == 'body':
1078
- continue
1079
- if value is not None:
1080
- attrs.append(f'{key}="{html.escape(value, quote=True)}"')
1068
+ attrs = [f'{key}="{html.escape(value, quote=True)}"'
1069
+ for key, value in js.attributes.items()
1070
+ if key != 'body' and value is not None]
1081
1071
 
1082
1072
  if not js.filename:
1083
1073
  if attrs:
@@ -1091,8 +1081,10 @@ class StandaloneHTMLBuilder(Builder):
1091
1081
  # https://docs.mathjax.org/en/v2.7-latest/configuration.html#considerations-for-using-combined-configuration-files
1092
1082
  # https://github.com/sphinx-doc/sphinx/issues/11658
1093
1083
  pass
1094
- elif checksum := _file_checksum(outdir, js.filename):
1095
- uri += f'?v={checksum}'
1084
+ # the EPUB format does not allow the use of query components
1085
+ elif self.name != 'epub':
1086
+ if checksum := _file_checksum(outdir, js.filename):
1087
+ uri += f'?v={checksum}'
1096
1088
  if attrs:
1097
1089
  return f'<script {" ".join(sorted(attrs))} src="{uri}"></script>'
1098
1090
  return f'<script src="{uri}"></script>'
@@ -1182,7 +1174,7 @@ class StandaloneHTMLBuilder(Builder):
1182
1174
 
1183
1175
 
1184
1176
  def convert_html_css_files(app: Sphinx, config: Config) -> None:
1185
- """This converts string styled html_css_files to tuple styled one."""
1177
+ """Convert string styled html_css_files to tuple styled one."""
1186
1178
  html_css_files: list[tuple[str, dict]] = []
1187
1179
  for entry in config.html_css_files:
1188
1180
  if isinstance(entry, str):
@@ -1205,7 +1197,7 @@ def _format_modified_time(timestamp: float) -> str:
1205
1197
 
1206
1198
 
1207
1199
  def convert_html_js_files(app: Sphinx, config: Config) -> None:
1208
- """This converts string styled html_js_files to tuple styled one."""
1200
+ """Convert string styled html_js_files to tuple styled one."""
1209
1201
  html_js_files: list[tuple[str, dict]] = []
1210
1202
  for entry in config.html_js_files:
1211
1203
  if isinstance(entry, str):
@@ -1302,7 +1294,7 @@ def error_on_html_4(_app: Sphinx, config: Config) -> None:
1302
1294
  ))
1303
1295
 
1304
1296
 
1305
- def setup(app: Sphinx) -> dict[str, Any]:
1297
+ def setup(app: Sphinx) -> ExtensionMetadata:
1306
1298
  # builders
1307
1299
  app.add_builder(StandaloneHTMLBuilder)
1308
1300
 
@@ -1310,21 +1302,20 @@ def setup(app: Sphinx) -> dict[str, Any]:
1310
1302
  app.add_config_value('html_theme', 'alabaster', 'html')
1311
1303
  app.add_config_value('html_theme_path', [], 'html')
1312
1304
  app.add_config_value('html_theme_options', {}, 'html')
1313
- app.add_config_value('html_title',
1314
- lambda self: _('%s %s documentation') % (self.project, self.release),
1315
- 'html', [str])
1305
+ app.add_config_value(
1306
+ 'html_title', lambda c: _('%s %s documentation') % (c.project, c.release), 'html', str)
1316
1307
  app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
1317
- app.add_config_value('html_style', None, 'html', [list, str])
1318
- app.add_config_value('html_logo', None, 'html', [str])
1319
- app.add_config_value('html_favicon', None, 'html', [str])
1308
+ app.add_config_value('html_style', None, 'html', {list, str})
1309
+ app.add_config_value('html_logo', None, 'html', str)
1310
+ app.add_config_value('html_favicon', None, 'html', str)
1320
1311
  app.add_config_value('html_css_files', [], 'html')
1321
1312
  app.add_config_value('html_js_files', [], 'html')
1322
1313
  app.add_config_value('html_static_path', [], 'html')
1323
1314
  app.add_config_value('html_extra_path', [], 'html')
1324
- app.add_config_value('html_last_updated_fmt', None, 'html', [str])
1315
+ app.add_config_value('html_last_updated_fmt', None, 'html', str)
1325
1316
  app.add_config_value('html_sidebars', {}, 'html')
1326
1317
  app.add_config_value('html_additional_pages', {}, 'html')
1327
- app.add_config_value('html_domain_indices', True, 'html', [list])
1318
+ app.add_config_value('html_domain_indices', True, 'html', list)
1328
1319
  app.add_config_value('html_permalinks', True, 'html')
1329
1320
  app.add_config_value('html_permalinks_icon', '¶', 'html')
1330
1321
  app.add_config_value('html_use_index', True, 'html')
@@ -1333,8 +1324,8 @@ def setup(app: Sphinx) -> dict[str, Any]:
1333
1324
  app.add_config_value('html_show_sourcelink', True, 'html')
1334
1325
  app.add_config_value('html_sourcelink_suffix', '.txt', 'html')
1335
1326
  app.add_config_value('html_use_opensearch', '', 'html')
1336
- app.add_config_value('html_file_suffix', None, 'html', [str])
1337
- app.add_config_value('html_link_suffix', None, 'html', [str])
1327
+ app.add_config_value('html_file_suffix', None, 'html', str)
1328
+ app.add_config_value('html_link_suffix', None, 'html', str)
1338
1329
  app.add_config_value('html_show_copyright', True, 'html')
1339
1330
  app.add_config_value('html_show_search_summary', True, 'html')
1340
1331
  app.add_config_value('html_show_sphinx', True, 'html')
@@ -1342,12 +1333,13 @@ def setup(app: Sphinx) -> dict[str, Any]:
1342
1333
  app.add_config_value('html_output_encoding', 'utf-8', 'html')
1343
1334
  app.add_config_value('html_compact_lists', True, 'html')
1344
1335
  app.add_config_value('html_secnumber_suffix', '. ', 'html')
1345
- app.add_config_value('html_search_language', None, 'html', [str])
1336
+ app.add_config_value('html_search_language', None, 'html', str)
1346
1337
  app.add_config_value('html_search_options', {}, 'html')
1347
1338
  app.add_config_value('html_search_scorer', '', '')
1348
1339
  app.add_config_value('html_scaled_image_link', True, 'html')
1349
1340
  app.add_config_value('html_baseurl', '', 'html')
1350
- app.add_config_value('html_codeblock_linenos_style', 'inline', 'html', # RemovedInSphinx70Warning # noqa: E501
1341
+ # removal is indefinitely on hold (ref: https://github.com/sphinx-doc/sphinx/issues/10265)
1342
+ app.add_config_value('html_codeblock_linenos_style', 'inline', 'html',
1351
1343
  ENUM('table', 'inline'))
1352
1344
  app.add_config_value('html_math_renderer', None, 'env')
1353
1345
  app.add_config_value('html4_writer', False, 'html')
@@ -1380,14 +1372,14 @@ def setup(app: Sphinx) -> dict[str, Any]:
1380
1372
  }
1381
1373
 
1382
1374
 
1383
- # deprecated name -> (object to return, canonical path or empty string)
1384
- _DEPRECATED_OBJECTS = {
1375
+ # deprecated name -> (object to return, canonical path or empty string, removal version)
1376
+ _DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
1385
1377
  'Stylesheet': (_CascadingStyleSheet, 'sphinx.builders.html._assets._CascadingStyleSheet', (9, 0)), # NoQA: E501
1386
1378
  'JavaScript': (_JavaScript, 'sphinx.builders.html._assets._JavaScript', (9, 0)),
1387
1379
  }
1388
1380
 
1389
1381
 
1390
- def __getattr__(name):
1382
+ def __getattr__(name: str) -> Any:
1391
1383
  if name not in _DEPRECATED_OBJECTS:
1392
1384
  msg = f'module {__name__!r} has no attribute {name!r}'
1393
1385
  raise AttributeError(msg)