Sphinx 8.0.2__py3-none-any.whl → 8.1.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 (424) hide show
  1. sphinx/__init__.py +6 -3
  2. sphinx/_cli/__init__.py +40 -20
  3. sphinx/_cli/util/colour.py +5 -4
  4. sphinx/_cli/util/errors.py +28 -11
  5. sphinx/application.py +361 -38
  6. sphinx/builders/__init__.py +229 -83
  7. sphinx/builders/_epub_base.py +118 -71
  8. sphinx/builders/changes.py +39 -21
  9. sphinx/builders/dirhtml.py +4 -4
  10. sphinx/builders/dummy.py +2 -5
  11. sphinx/builders/epub3.py +43 -22
  12. sphinx/builders/gettext.py +43 -25
  13. sphinx/builders/html/__init__.py +284 -218
  14. sphinx/builders/html/_assets.py +62 -26
  15. sphinx/builders/html/_build_info.py +76 -0
  16. sphinx/builders/html/transforms.py +11 -9
  17. sphinx/builders/latex/__init__.py +139 -81
  18. sphinx/builders/latex/constants.py +7 -7
  19. sphinx/builders/latex/nodes.py +3 -2
  20. sphinx/builders/latex/theming.py +7 -5
  21. sphinx/builders/latex/transforms.py +27 -19
  22. sphinx/builders/linkcheck.py +146 -72
  23. sphinx/builders/manpage.py +30 -13
  24. sphinx/builders/singlehtml.py +22 -14
  25. sphinx/builders/texinfo.py +67 -37
  26. sphinx/builders/text.py +5 -5
  27. sphinx/builders/xml.py +6 -9
  28. sphinx/cmd/build.py +282 -103
  29. sphinx/cmd/make_mode.py +106 -63
  30. sphinx/cmd/quickstart.py +341 -145
  31. sphinx/config.py +45 -12
  32. sphinx/deprecation.py +8 -2
  33. sphinx/directives/__init__.py +28 -19
  34. sphinx/directives/code.py +86 -56
  35. sphinx/directives/other.py +50 -36
  36. sphinx/directives/patches.py +29 -19
  37. sphinx/domains/__init__.py +20 -120
  38. sphinx/domains/_domains_container.py +281 -0
  39. sphinx/domains/_index.py +110 -0
  40. sphinx/domains/c/__init__.py +3 -3
  41. sphinx/domains/c/_parser.py +10 -6
  42. sphinx/domains/changeset.py +5 -3
  43. sphinx/domains/citation.py +5 -3
  44. sphinx/domains/cpp/__init__.py +9 -11
  45. sphinx/domains/cpp/_parser.py +8 -7
  46. sphinx/domains/index.py +3 -3
  47. sphinx/domains/javascript.py +12 -7
  48. sphinx/domains/math.py +2 -2
  49. sphinx/domains/python/__init__.py +10 -5
  50. sphinx/domains/python/_object.py +1 -1
  51. sphinx/domains/rst.py +5 -5
  52. sphinx/domains/std/__init__.py +16 -11
  53. sphinx/environment/__init__.py +206 -146
  54. sphinx/environment/adapters/asset.py +3 -2
  55. sphinx/environment/adapters/indexentries.py +74 -33
  56. sphinx/environment/adapters/toctree.py +100 -43
  57. sphinx/environment/collectors/__init__.py +19 -8
  58. sphinx/environment/collectors/asset.py +47 -15
  59. sphinx/environment/collectors/dependencies.py +8 -4
  60. sphinx/environment/collectors/metadata.py +7 -2
  61. sphinx/environment/collectors/title.py +7 -2
  62. sphinx/environment/collectors/toctree.py +54 -22
  63. sphinx/errors.py +4 -1
  64. sphinx/events.py +314 -7
  65. sphinx/ext/apidoc.py +42 -18
  66. sphinx/ext/autodoc/__init__.py +52 -24
  67. sphinx/ext/autodoc/importer.py +6 -9
  68. sphinx/ext/autosectionlabel.py +1 -2
  69. sphinx/ext/autosummary/__init__.py +3 -1
  70. sphinx/ext/autosummary/generate.py +28 -14
  71. sphinx/ext/coverage.py +7 -7
  72. sphinx/ext/doctest.py +4 -8
  73. sphinx/ext/duration.py +6 -5
  74. sphinx/ext/inheritance_diagram.py +1 -1
  75. sphinx/ext/intersphinx/_cli.py +6 -4
  76. sphinx/ext/intersphinx/_load.py +77 -32
  77. sphinx/ext/intersphinx/_resolve.py +173 -79
  78. sphinx/ext/intersphinx/_shared.py +7 -5
  79. sphinx/ext/linkcode.py +7 -1
  80. sphinx/ext/mathjax.py +1 -2
  81. sphinx/ext/napoleon/__init__.py +37 -24
  82. sphinx/ext/napoleon/docstring.py +202 -134
  83. sphinx/ext/todo.py +5 -3
  84. sphinx/highlighting.py +9 -2
  85. sphinx/io.py +1 -1
  86. sphinx/jinja2glue.py +27 -6
  87. sphinx/locale/__init__.py +6 -2
  88. sphinx/locale/ar/LC_MESSAGES/sphinx.js +8 -1
  89. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  90. sphinx/locale/ar/LC_MESSAGES/sphinx.po +2246 -2288
  91. sphinx/locale/bg/LC_MESSAGES/sphinx.js +4 -1
  92. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  93. sphinx/locale/bg/LC_MESSAGES/sphinx.po +2113 -2159
  94. sphinx/locale/bn/LC_MESSAGES/sphinx.js +4 -1
  95. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  96. sphinx/locale/bn/LC_MESSAGES/sphinx.po +2349 -2395
  97. sphinx/locale/ca/LC_MESSAGES/sphinx.js +4 -1
  98. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/ca/LC_MESSAGES/sphinx.po +2846 -2892
  100. sphinx/locale/cak/LC_MESSAGES/sphinx.js +4 -1
  101. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  102. sphinx/locale/cak/LC_MESSAGES/sphinx.po +2213 -2259
  103. sphinx/locale/cs/LC_MESSAGES/sphinx.js +6 -1
  104. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/cs/LC_MESSAGES/sphinx.po +2225 -2269
  106. sphinx/locale/cy/LC_MESSAGES/sphinx.js +6 -1
  107. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  108. sphinx/locale/cy/LC_MESSAGES/sphinx.po +2403 -2447
  109. sphinx/locale/da/LC_MESSAGES/sphinx.js +4 -1
  110. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/da/LC_MESSAGES/sphinx.po +2214 -2260
  112. sphinx/locale/de/LC_MESSAGES/sphinx.js +4 -1
  113. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  114. sphinx/locale/de/LC_MESSAGES/sphinx.po +2230 -2276
  115. sphinx/locale/de_DE/LC_MESSAGES/sphinx.js +4 -1
  116. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2113 -2159
  118. sphinx/locale/el/LC_MESSAGES/sphinx.js +4 -1
  119. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  120. sphinx/locale/el/LC_MESSAGES/sphinx.po +2619 -2665
  121. sphinx/locale/en_DE/LC_MESSAGES/sphinx.js +4 -1
  122. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2113 -2159
  124. sphinx/locale/en_FR/LC_MESSAGES/sphinx.js +4 -1
  125. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  126. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2113 -2159
  127. sphinx/locale/en_GB/LC_MESSAGES/sphinx.js +4 -1
  128. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2519 -2565
  130. sphinx/locale/en_HK/LC_MESSAGES/sphinx.js +4 -1
  131. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  132. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2113 -2159
  133. sphinx/locale/eo/LC_MESSAGES/sphinx.js +4 -1
  134. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/eo/LC_MESSAGES/sphinx.po +2232 -2278
  136. sphinx/locale/es/LC_MESSAGES/sphinx.js +5 -1
  137. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/es/LC_MESSAGES/sphinx.po +2516 -2561
  139. sphinx/locale/es_CO/LC_MESSAGES/sphinx.js +5 -1
  140. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  141. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2114 -2159
  142. sphinx/locale/et/LC_MESSAGES/sphinx.js +4 -1
  143. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/et/LC_MESSAGES/sphinx.po +2317 -2363
  145. sphinx/locale/eu/LC_MESSAGES/sphinx.js +4 -1
  146. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  147. sphinx/locale/eu/LC_MESSAGES/sphinx.po +2218 -2264
  148. sphinx/locale/fa/LC_MESSAGES/sphinx.js +4 -1
  149. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/fa/LC_MESSAGES/sphinx.po +2505 -2551
  151. sphinx/locale/fi/LC_MESSAGES/sphinx.js +4 -1
  152. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  153. sphinx/locale/fi/LC_MESSAGES/sphinx.po +2303 -2349
  154. sphinx/locale/fr/LC_MESSAGES/sphinx.js +6 -2
  155. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/fr/LC_MESSAGES/sphinx.po +2863 -2908
  157. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.js +5 -1
  158. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  159. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +2114 -2159
  160. sphinx/locale/gl/LC_MESSAGES/sphinx.js +4 -1
  161. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/gl/LC_MESSAGES/sphinx.po +2571 -2617
  163. sphinx/locale/he/LC_MESSAGES/sphinx.js +5 -1
  164. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  165. sphinx/locale/he/LC_MESSAGES/sphinx.po +2307 -2352
  166. sphinx/locale/hi/LC_MESSAGES/sphinx.js +4 -1
  167. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/hi/LC_MESSAGES/sphinx.po +2580 -2626
  169. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js +4 -1
  170. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  171. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +2113 -2159
  172. sphinx/locale/hr/LC_MESSAGES/sphinx.js +5 -1
  173. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/hr/LC_MESSAGES/sphinx.po +2238 -2283
  175. sphinx/locale/hu/LC_MESSAGES/sphinx.js +4 -1
  176. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  177. sphinx/locale/hu/LC_MESSAGES/sphinx.po +2228 -2274
  178. sphinx/locale/id/LC_MESSAGES/sphinx.js +3 -1
  179. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/id/LC_MESSAGES/sphinx.po +2787 -2834
  181. sphinx/locale/is/LC_MESSAGES/sphinx.js +4 -1
  182. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  183. sphinx/locale/is/LC_MESSAGES/sphinx.po +2224 -2270
  184. sphinx/locale/it/LC_MESSAGES/sphinx.js +5 -1
  185. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/it/LC_MESSAGES/sphinx.po +2231 -2276
  187. sphinx/locale/ja/LC_MESSAGES/sphinx.js +3 -1
  188. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  189. sphinx/locale/ja/LC_MESSAGES/sphinx.po +2507 -2554
  190. sphinx/locale/ka/LC_MESSAGES/sphinx.js +4 -1
  191. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  192. sphinx/locale/ka/LC_MESSAGES/sphinx.po +2428 -2474
  193. sphinx/locale/ko/LC_MESSAGES/sphinx.js +3 -1
  194. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/ko/LC_MESSAGES/sphinx.po +2516 -2563
  196. sphinx/locale/lt/LC_MESSAGES/sphinx.js +6 -1
  197. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  198. sphinx/locale/lt/LC_MESSAGES/sphinx.po +2425 -2469
  199. sphinx/locale/lv/LC_MESSAGES/sphinx.js +5 -1
  200. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/lv/LC_MESSAGES/sphinx.po +2362 -2407
  202. sphinx/locale/mk/LC_MESSAGES/sphinx.js +4 -1
  203. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  204. sphinx/locale/mk/LC_MESSAGES/sphinx.po +2121 -2167
  205. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +4 -1
  206. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2220 -2266
  208. sphinx/locale/ne/LC_MESSAGES/sphinx.js +4 -1
  209. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  210. sphinx/locale/ne/LC_MESSAGES/sphinx.po +2221 -2267
  211. sphinx/locale/nl/LC_MESSAGES/sphinx.js +4 -1
  212. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/nl/LC_MESSAGES/sphinx.po +2240 -2286
  214. sphinx/locale/pl/LC_MESSAGES/sphinx.js +6 -1
  215. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/pl/LC_MESSAGES/sphinx.po +2319 -2363
  217. sphinx/locale/pt/LC_MESSAGES/sphinx.js +5 -1
  218. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  219. sphinx/locale/pt/LC_MESSAGES/sphinx.po +2114 -2159
  220. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +5 -1
  221. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2854 -2899
  223. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js +5 -1
  224. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  225. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2224 -2269
  226. sphinx/locale/ro/LC_MESSAGES/sphinx.js +5 -1
  227. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  228. sphinx/locale/ro/LC_MESSAGES/sphinx.po +2226 -2271
  229. sphinx/locale/ru/LC_MESSAGES/sphinx.js +8 -3
  230. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  231. sphinx/locale/ru/LC_MESSAGES/sphinx.po +2841 -2885
  232. sphinx/locale/si/LC_MESSAGES/sphinx.js +4 -1
  233. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  234. sphinx/locale/si/LC_MESSAGES/sphinx.po +2294 -2340
  235. sphinx/locale/sk/LC_MESSAGES/sphinx.js +6 -1
  236. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/sk/LC_MESSAGES/sphinx.po +2497 -2541
  238. sphinx/locale/sl/LC_MESSAGES/sphinx.js +6 -1
  239. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  240. sphinx/locale/sl/LC_MESSAGES/sphinx.po +2331 -2375
  241. sphinx/locale/sphinx.pot +2121 -2167
  242. sphinx/locale/sq/LC_MESSAGES/sphinx.js +4 -1
  243. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  244. sphinx/locale/sq/LC_MESSAGES/sphinx.po +2855 -2901
  245. sphinx/locale/sr/LC_MESSAGES/sphinx.js +5 -1
  246. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  247. sphinx/locale/sr/LC_MESSAGES/sphinx.po +2203 -2248
  248. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  249. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  250. sphinx/locale/sv/LC_MESSAGES/sphinx.js +4 -1
  251. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  252. sphinx/locale/sv/LC_MESSAGES/sphinx.po +2423 -2469
  253. sphinx/locale/te/LC_MESSAGES/sphinx.js +4 -1
  254. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  255. sphinx/locale/te/LC_MESSAGES/sphinx.po +2113 -2159
  256. sphinx/locale/tr/LC_MESSAGES/sphinx.js +4 -1
  257. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  258. sphinx/locale/tr/LC_MESSAGES/sphinx.po +2443 -2489
  259. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js +6 -1
  260. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  261. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2329 -2373
  262. sphinx/locale/ur/LC_MESSAGES/sphinx.js +4 -1
  263. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  264. sphinx/locale/ur/LC_MESSAGES/sphinx.po +2113 -2159
  265. sphinx/locale/vi/LC_MESSAGES/sphinx.js +3 -1
  266. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  267. sphinx/locale/vi/LC_MESSAGES/sphinx.po +2199 -2246
  268. sphinx/locale/yue/LC_MESSAGES/sphinx.js +3 -1
  269. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  270. sphinx/locale/yue/LC_MESSAGES/sphinx.po +2112 -2159
  271. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.js +3 -1
  272. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  273. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2112 -2159
  274. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +3 -1
  275. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  276. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2845 -2892
  277. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.js +3 -1
  278. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  279. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2112 -2159
  280. sphinx/parsers.py +3 -1
  281. sphinx/project.py +6 -2
  282. sphinx/pycode/__init__.py +11 -4
  283. sphinx/pycode/ast.py +58 -58
  284. sphinx/pycode/parser.py +49 -28
  285. sphinx/pygments_styles.py +49 -49
  286. sphinx/registry.py +8 -3
  287. sphinx/roles.py +133 -13
  288. sphinx/search/__init__.py +146 -87
  289. sphinx/search/da.py +2 -4
  290. sphinx/search/de.py +2 -4
  291. sphinx/search/en.py +4 -4
  292. sphinx/search/es.py +2 -4
  293. sphinx/search/fi.py +2 -4
  294. sphinx/search/fr.py +2 -4
  295. sphinx/search/hu.py +2 -4
  296. sphinx/search/it.py +2 -4
  297. sphinx/search/ja.py +55 -32
  298. sphinx/search/nl.py +2 -4
  299. sphinx/search/no.py +2 -4
  300. sphinx/search/pt.py +2 -4
  301. sphinx/search/ro.py +0 -2
  302. sphinx/search/ru.py +2 -4
  303. sphinx/search/sv.py +2 -4
  304. sphinx/search/tr.py +0 -2
  305. sphinx/search/zh.py +18 -13
  306. sphinx/templates/graphviz/graphviz.css +0 -7
  307. sphinx/testing/fixtures.py +6 -5
  308. sphinx/testing/path.py +7 -5
  309. sphinx/testing/util.py +63 -29
  310. sphinx/texinputs/sphinx.sty +107 -39
  311. sphinx/texinputs/sphinxlatexadmonitions.sty +51 -35
  312. sphinx/texinputs/sphinxlatexcontainers.sty +1 -1
  313. sphinx/texinputs/sphinxlatexgraphics.sty +3 -2
  314. sphinx/texinputs/sphinxlatexindbibtoc.sty +1 -1
  315. sphinx/texinputs/sphinxlatexlists.sty +1 -1
  316. sphinx/texinputs/sphinxlatexliterals.sty +4 -1
  317. sphinx/texinputs/sphinxlatexnumfig.sty +22 -9
  318. sphinx/texinputs/sphinxlatexobjects.sty +1 -1
  319. sphinx/texinputs/sphinxlatexshadowbox.sty +72 -10
  320. sphinx/texinputs/sphinxlatexstyleheadings.sty +7 -2
  321. sphinx/texinputs/sphinxlatexstylepage.sty +2 -8
  322. sphinx/texinputs/sphinxlatexstyletext.sty +2 -4
  323. sphinx/texinputs/sphinxlatextables.sty +1 -1
  324. sphinx/texinputs/sphinxoptionsgeometry.sty +1 -1
  325. sphinx/texinputs/sphinxoptionshyperref.sty +1 -1
  326. sphinx/themes/agogo/layout.html +1 -10
  327. sphinx/themes/agogo/static/agogo.css.jinja +0 -7
  328. sphinx/themes/basic/defindex.html +1 -8
  329. sphinx/themes/basic/domainindex.html +1 -9
  330. sphinx/themes/basic/genindex-single.html +1 -9
  331. sphinx/themes/basic/genindex-split.html +1 -9
  332. sphinx/themes/basic/genindex.html +1 -9
  333. sphinx/themes/basic/globaltoc.html +1 -9
  334. sphinx/themes/basic/layout.html +1 -9
  335. sphinx/themes/basic/localtoc.html +1 -9
  336. sphinx/themes/basic/page.html +1 -9
  337. sphinx/themes/basic/relations.html +1 -9
  338. sphinx/themes/basic/search.html +1 -9
  339. sphinx/themes/basic/searchbox.html +1 -9
  340. sphinx/themes/basic/searchfield.html +4 -10
  341. sphinx/themes/basic/sourcelink.html +1 -9
  342. sphinx/themes/basic/static/basic.css.jinja +2 -13
  343. sphinx/themes/basic/static/doctools.js +0 -7
  344. sphinx/themes/basic/static/language_data.js.jinja +0 -7
  345. sphinx/themes/basic/static/searchtools.js +25 -13
  346. sphinx/themes/bizstyle/layout.html +1 -9
  347. sphinx/themes/bizstyle/static/bizstyle.css.jinja +0 -7
  348. sphinx/themes/bizstyle/static/bizstyle.js.jinja +5 -11
  349. sphinx/themes/classic/layout.html +1 -9
  350. sphinx/themes/classic/static/classic.css.jinja +0 -7
  351. sphinx/themes/classic/static/sidebar.js.jinja +0 -6
  352. sphinx/themes/epub/epub-cover.html +1 -9
  353. sphinx/themes/epub/layout.html +1 -9
  354. sphinx/themes/epub/static/epub.css.jinja +0 -7
  355. sphinx/themes/haiku/layout.html +1 -9
  356. sphinx/themes/haiku/static/haiku.css.jinja +0 -6
  357. sphinx/themes/nature/static/nature.css.jinja +0 -7
  358. sphinx/themes/nonav/layout.html +1 -9
  359. sphinx/themes/nonav/static/nonav.css.jinja +0 -7
  360. sphinx/themes/pyramid/static/epub.css.jinja +0 -7
  361. sphinx/themes/pyramid/static/pyramid.css.jinja +0 -7
  362. sphinx/themes/scrolls/layout.html +1 -10
  363. sphinx/themes/scrolls/static/scrolls.css.jinja +0 -7
  364. sphinx/themes/sphinxdoc/static/sphinxdoc.css.jinja +2 -7
  365. sphinx/themes/traditional/static/traditional.css.jinja +0 -7
  366. sphinx/theming.py +18 -6
  367. sphinx/transforms/__init__.py +56 -35
  368. sphinx/transforms/compact_bullet_list.py +3 -2
  369. sphinx/transforms/i18n.py +132 -50
  370. sphinx/transforms/post_transforms/__init__.py +94 -43
  371. sphinx/transforms/post_transforms/code.py +7 -6
  372. sphinx/transforms/post_transforms/images.py +71 -54
  373. sphinx/transforms/references.py +1 -2
  374. sphinx/util/__init__.py +23 -194
  375. sphinx/util/_files.py +80 -0
  376. sphinx/util/_importer.py +27 -0
  377. sphinx/util/_io.py +1 -2
  378. sphinx/util/_lines.py +26 -0
  379. sphinx/util/_pathlib.py +5 -2
  380. sphinx/util/_serialise.py +53 -0
  381. sphinx/util/_timestamps.py +2 -1
  382. sphinx/util/_uri.py +16 -0
  383. sphinx/util/cfamily.py +48 -25
  384. sphinx/util/console.py +1 -0
  385. sphinx/util/display.py +1 -1
  386. sphinx/util/docfields.py +125 -45
  387. sphinx/util/docstrings.py +1 -1
  388. sphinx/util/docutils.py +118 -44
  389. sphinx/util/exceptions.py +11 -5
  390. sphinx/util/fileutil.py +53 -32
  391. sphinx/util/http_date.py +9 -7
  392. sphinx/util/i18n.py +49 -16
  393. sphinx/util/images.py +7 -6
  394. sphinx/util/inspect.py +29 -12
  395. sphinx/util/inventory.py +47 -29
  396. sphinx/util/logging.py +58 -85
  397. sphinx/util/matching.py +3 -3
  398. sphinx/util/math.py +1 -1
  399. sphinx/util/nodes.py +176 -108
  400. sphinx/util/osutil.py +13 -10
  401. sphinx/util/parallel.py +5 -4
  402. sphinx/util/parsing.py +5 -3
  403. sphinx/util/png.py +3 -3
  404. sphinx/util/requests.py +8 -4
  405. sphinx/util/rst.py +5 -3
  406. sphinx/util/tags.py +5 -2
  407. sphinx/util/template.py +26 -11
  408. sphinx/util/texescape.py +2 -2
  409. sphinx/util/typing.py +89 -38
  410. sphinx/versioning.py +3 -1
  411. sphinx/writers/html.py +22 -7
  412. sphinx/writers/html5.py +113 -64
  413. sphinx/writers/latex.py +408 -221
  414. sphinx/writers/manpage.py +25 -15
  415. sphinx/writers/texinfo.py +94 -82
  416. sphinx/writers/text.py +87 -53
  417. sphinx/writers/xml.py +5 -4
  418. sphinx-8.1.0.dist-info/LICENSE.rst +31 -0
  419. {sphinx-8.0.2.dist-info → sphinx-8.1.0.dist-info}/METADATA +13 -11
  420. sphinx-8.1.0.dist-info/RECORD +598 -0
  421. sphinx-8.0.2.dist-info/LICENSE.rst +0 -67
  422. sphinx-8.0.2.dist-info/RECORD +0 -590
  423. {sphinx-8.0.2.dist-info → sphinx-8.1.0.dist-info}/WHEEL +0 -0
  424. {sphinx-8.0.2.dist-info → sphinx-8.1.0.dist-info}/entry_points.txt +0 -0
sphinx/writers/latex.py CHANGED
@@ -10,12 +10,11 @@ import re
10
10
  from collections import defaultdict
11
11
  from collections.abc import Iterable
12
12
  from os import path
13
- from typing import TYPE_CHECKING, Any, cast
13
+ from typing import TYPE_CHECKING, Any, ClassVar, cast
14
14
 
15
15
  from docutils import nodes, writers
16
16
 
17
17
  from sphinx import addnodes, highlighting
18
- from sphinx.domains.std import StandardDomain
19
18
  from sphinx.errors import SphinxError
20
19
  from sphinx.locale import _, __, admonitionlabels
21
20
  from sphinx.util import logging, texescape
@@ -42,16 +41,25 @@ if TYPE_CHECKING:
42
41
  logger = logging.getLogger(__name__)
43
42
 
44
43
  MAX_CITATION_LABEL_LENGTH = 8
45
- LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
46
- "subsubsection", "paragraph", "subparagraph"]
47
- ENUMERATE_LIST_STYLE = defaultdict(lambda: r'\arabic',
48
- {
49
- 'arabic': r'\arabic',
50
- 'loweralpha': r'\alph',
51
- 'upperalpha': r'\Alph',
52
- 'lowerroman': r'\roman',
53
- 'upperroman': r'\Roman',
54
- })
44
+ LATEXSECTIONNAMES = [
45
+ 'part',
46
+ 'chapter',
47
+ 'section',
48
+ 'subsection',
49
+ 'subsubsection',
50
+ 'paragraph',
51
+ 'subparagraph',
52
+ ]
53
+ ENUMERATE_LIST_STYLE = defaultdict(
54
+ lambda: r'\arabic',
55
+ {
56
+ 'arabic': r'\arabic',
57
+ 'loweralpha': r'\alph',
58
+ 'upperalpha': r'\Alph',
59
+ 'lowerroman': r'\roman',
60
+ 'upperroman': r'\Roman',
61
+ },
62
+ )
55
63
 
56
64
  CR = '\n'
57
65
  BLANKLINE = '\n\n'
@@ -66,16 +74,19 @@ class UnsupportedError(SphinxError):
66
74
  category = 'Markup is unsupported in LaTeX'
67
75
 
68
76
 
69
- class LaTeXWriter(writers.Writer): # type: ignore[misc]
70
-
77
+ class LaTeXWriter(writers.Writer): # type: ignore[type-arg]
71
78
  supported = ('sphinxlatex',)
72
79
 
73
- settings_spec = ('LaTeX writer options', '', (
74
- ('Document name', ['--docname'], {'default': ''}),
75
- ('Document class', ['--docclass'], {'default': 'manual'}),
76
- ('Author', ['--author'], {'default': ''}),
77
- ))
78
- settings_defaults: dict[str, Any] = {}
80
+ settings_spec = (
81
+ 'LaTeX writer options',
82
+ '',
83
+ (
84
+ ('Document name', ['--docname'], {'default': ''}),
85
+ ('Document class', ['--docclass'], {'default': 'manual'}),
86
+ ('Author', ['--author'], {'default': ''}),
87
+ ),
88
+ )
89
+ settings_defaults: ClassVar[dict[str, Any]] = {}
79
90
 
80
91
  theme: Theme
81
92
 
@@ -84,13 +95,17 @@ class LaTeXWriter(writers.Writer): # type: ignore[misc]
84
95
  self.builder = builder
85
96
 
86
97
  def translate(self) -> None:
87
- visitor = self.builder.create_translator(self.document, self.builder, self.theme)
98
+ assert isinstance(self.document, nodes.document)
99
+ visitor = self.builder.create_translator(
100
+ self.document, self.builder, self.theme
101
+ )
88
102
  self.document.walkabout(visitor)
89
103
  self.output = cast(LaTeXTranslator, visitor).astext()
90
104
 
91
105
 
92
106
  # Helper classes
93
107
 
108
+
94
109
  class Table:
95
110
  """A table data"""
96
111
 
@@ -152,7 +167,9 @@ class Table:
152
167
  return 'tabular'
153
168
  elif self.colspec:
154
169
  return 'tabulary'
155
- elif self.has_problematic or (self.colwidths and 'colwidths-given' in self.classes):
170
+ elif self.has_problematic or (
171
+ self.colwidths and 'colwidths-given' in self.classes
172
+ ):
156
173
  return 'tabular'
157
174
  else:
158
175
  return 'tabulary'
@@ -177,14 +194,20 @@ class Table:
177
194
  colspecs = [r'\X{%d}{%d}' % (width, total) for width in self.colwidths]
178
195
  return f'{{{_colsep}{_colsep.join(colspecs)}{_colsep}}}' + CR
179
196
  elif self.has_problematic:
180
- return r'{%s*{%d}{\X{1}{%d}%s}}' % (_colsep, self.colcount,
181
- self.colcount, _colsep) + CR
197
+ return (
198
+ r'{%s*{%d}{\X{1}{%d}%s}}'
199
+ % (_colsep, self.colcount, self.colcount, _colsep)
200
+ + CR
201
+ )
182
202
  elif self.get_table_type() == 'tabulary':
183
203
  # sphinx.sty sets T to be J by default.
184
204
  return '{' + _colsep + (('T' + _colsep) * self.colcount) + '}' + CR
185
205
  elif self.has_oldproblematic:
186
- return r'{%s*{%d}{\X{1}{%d}%s}}' % (_colsep, self.colcount,
187
- self.colcount, _colsep) + CR
206
+ return (
207
+ r'{%s*{%d}{\X{1}{%d}%s}}'
208
+ % (_colsep, self.colcount, self.colcount, _colsep)
209
+ + CR
210
+ )
188
211
  else:
189
212
  return '{' + _colsep + (('l' + _colsep) * self.colcount) + '}' + CR
190
213
 
@@ -200,7 +223,9 @@ class Table:
200
223
  self.cells[(self.row + row, self.col + col)] = self.cell_id
201
224
 
202
225
  def cell(
203
- self, row: int | None = None, col: int | None = None,
226
+ self,
227
+ row: int | None = None,
228
+ col: int | None = None,
204
229
  ) -> TableCell | None:
205
230
  """Returns a cell object (i.e. rectangular area) containing given position.
206
231
 
@@ -266,22 +291,22 @@ def rstdim_to_latexdim(width_str: str, scale: int = 100) -> str:
266
291
  amount, unit = match.groups()[:2]
267
292
  if scale == 100:
268
293
  float(amount) # validate amount is float
269
- if unit in ('', "px"):
270
- res = r"%s\sphinxpxdimen" % amount
294
+ if unit in ('', 'px'):
295
+ res = r'%s\sphinxpxdimen' % amount
271
296
  elif unit == 'pt':
272
297
  res = '%sbp' % amount # convert to 'bp'
273
- elif unit == "%":
274
- res = r"%.3f\linewidth" % (float(amount) / 100.0)
298
+ elif unit == '%':
299
+ res = r'%.3f\linewidth' % (float(amount) / 100.0)
275
300
  else:
276
301
  amount_float = float(amount) * scale / 100.0
277
- if unit in ('', "px"):
278
- res = r"%.5f\sphinxpxdimen" % amount_float
302
+ if unit in ('', 'px'):
303
+ res = r'%.5f\sphinxpxdimen' % amount_float
279
304
  elif unit == 'pt':
280
305
  res = '%.5fbp' % amount_float
281
- elif unit == "%":
282
- res = r"%.5f\linewidth" % (amount_float / 100.0)
306
+ elif unit == '%':
307
+ res = r'%.5f\linewidth' % (amount_float / 100.0)
283
308
  else:
284
- res = f"{amount_float:.5f}{unit}"
309
+ res = f'{amount_float:.5f}{unit}'
285
310
  return res
286
311
 
287
312
 
@@ -292,8 +317,9 @@ class LaTeXTranslator(SphinxTranslator):
292
317
  # default is originally 3. For book/report, 2 is already LaTeX default.
293
318
  ignore_missing_images = False
294
319
 
295
- def __init__(self, document: nodes.document, builder: LaTeXBuilder,
296
- theme: Theme) -> None:
320
+ def __init__(
321
+ self, document: nodes.document, builder: LaTeXBuilder, theme: Theme
322
+ ) -> None:
297
323
  super().__init__(document, builder)
298
324
  self.body: list[str] = []
299
325
  self.theme = theme
@@ -330,46 +356,63 @@ class LaTeXTranslator(SphinxTranslator):
330
356
  self.top_sectionlevel = 1
331
357
  if self.config.latex_toplevel_sectioning:
332
358
  try:
333
- self.top_sectionlevel = \
334
- self.sectionnames.index(self.config.latex_toplevel_sectioning)
359
+ self.top_sectionlevel = self.sectionnames.index(
360
+ self.config.latex_toplevel_sectioning
361
+ )
335
362
  except ValueError:
336
- logger.warning(__('unknown %r toplevel_sectioning for class %r'),
337
- self.config.latex_toplevel_sectioning, self.theme.docclass)
363
+ logger.warning(
364
+ __('unknown %r toplevel_sectioning for class %r'),
365
+ self.config.latex_toplevel_sectioning,
366
+ self.theme.docclass,
367
+ )
338
368
 
339
369
  if self.config.numfig:
340
370
  self.numfig_secnum_depth = self.config.numfig_secnum_depth
341
371
  if self.numfig_secnum_depth > 0: # default is 1
342
372
  # numfig_secnum_depth as passed to sphinx.sty indices same names as in
343
373
  # LATEXSECTIONNAMES but with -1 for part, 0 for chapter, 1 for section...
344
- if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \
345
- self.top_sectionlevel > 0:
374
+ if (
375
+ len(self.sectionnames) < len(LATEXSECTIONNAMES)
376
+ and self.top_sectionlevel > 0
377
+ ):
346
378
  self.numfig_secnum_depth += self.top_sectionlevel
347
379
  else:
348
380
  self.numfig_secnum_depth += self.top_sectionlevel - 1
349
381
  # this (minus one) will serve as minimum to LaTeX's secnumdepth
350
- self.numfig_secnum_depth = min(self.numfig_secnum_depth,
351
- len(LATEXSECTIONNAMES) - 1)
382
+ self.numfig_secnum_depth = min(
383
+ self.numfig_secnum_depth, len(LATEXSECTIONNAMES) - 1
384
+ )
352
385
  # if passed key value is < 1 LaTeX will act as if 0; see sphinx.sty
353
386
  sphinxpkgoptions.append('numfigreset=%s' % self.numfig_secnum_depth)
354
387
  else:
355
388
  sphinxpkgoptions.append('nonumfigreset')
356
389
 
357
390
  if self.config.numfig and self.config.math_numfig:
358
- sphinxpkgoptions.append('mathnumfig')
359
-
360
- if (self.config.language not in {'en', 'ja'} and
361
- 'fncychap' not in self.config.latex_elements):
391
+ sphinxpkgoptions.extend([
392
+ 'mathnumfig',
393
+ 'mathnumsep={%s}' % self.config.math_numsep,
394
+ ])
395
+
396
+ if (
397
+ self.config.language not in {'en', 'ja'}
398
+ and 'fncychap' not in self.config.latex_elements
399
+ ):
362
400
  # use Sonny style if any language specified (except English)
363
- self.elements['fncychap'] = (r'\usepackage[Sonny]{fncychap}' + CR +
364
- r'\ChNameVar{\Large\normalfont\sffamily}' + CR +
365
- r'\ChTitleVar{\Large\normalfont\sffamily}')
401
+ self.elements['fncychap'] = (
402
+ r'\usepackage[Sonny]{fncychap}'
403
+ + CR
404
+ + r'\ChNameVar{\Large\normalfont\sffamily}'
405
+ + CR
406
+ + r'\ChTitleVar{\Large\normalfont\sffamily}'
407
+ )
366
408
 
367
409
  self.babel = self.builder.babel
368
410
  if not self.babel.is_supported_language():
369
411
  # emit warning if specified language is invalid
370
412
  # (only emitting, nothing changed to processing)
371
- logger.warning(__('no Babel option known for language %r'),
372
- self.config.language)
413
+ logger.warning(
414
+ __('no Babel option known for language %r'), self.config.language
415
+ )
373
416
 
374
417
  minsecnumdepth = self.secnumdepth # 2 from legacy sphinx manual/howto
375
418
  if self.document.get('tocdepth'):
@@ -380,8 +423,10 @@ class LaTeXTranslator(SphinxTranslator):
380
423
  # tocdepth = 2: show parts, chapters, sections and subsections
381
424
  # ...
382
425
  tocdepth = self.document.get('tocdepth', 999) + self.top_sectionlevel - 2
383
- if len(self.sectionnames) < len(LATEXSECTIONNAMES) and \
384
- self.top_sectionlevel > 0:
426
+ if (
427
+ len(self.sectionnames) < len(LATEXSECTIONNAMES)
428
+ and self.top_sectionlevel > 0
429
+ ):
385
430
  tocdepth += 1 # because top_sectionlevel is shifted by -1
386
431
  if tocdepth > len(LATEXSECTIONNAMES) - 2: # default is 5 <-> subparagraph
387
432
  logger.warning(__('too large :maxdepth:, ignored.'))
@@ -394,26 +439,30 @@ class LaTeXTranslator(SphinxTranslator):
394
439
  minsecnumdepth = max(minsecnumdepth, self.numfig_secnum_depth - 1)
395
440
 
396
441
  if minsecnumdepth > self.secnumdepth:
397
- self.elements['secnumdepth'] = r'\setcounter{secnumdepth}{%d}' %\
398
- minsecnumdepth
442
+ self.elements['secnumdepth'] = (
443
+ r'\setcounter{secnumdepth}{%d}' % minsecnumdepth
444
+ )
399
445
 
400
446
  contentsname = document.get('contentsname')
401
447
  if contentsname:
402
- self.elements['contentsname'] = self.babel_renewcommand(r'\contentsname',
403
- contentsname)
448
+ self.elements['contentsname'] = self.babel_renewcommand(
449
+ r'\contentsname', contentsname
450
+ )
404
451
 
405
452
  if self.elements['maxlistdepth']:
406
453
  sphinxpkgoptions.append('maxlistdepth=%s' % self.elements['maxlistdepth'])
407
454
  if sphinxpkgoptions:
408
455
  self.elements['sphinxpkgoptions'] = '[,%s]' % ','.join(sphinxpkgoptions)
409
456
  if self.elements['sphinxsetup']:
410
- self.elements['sphinxsetup'] = (r'\sphinxsetup{%s}' % self.elements['sphinxsetup'])
457
+ self.elements['sphinxsetup'] = (
458
+ r'\sphinxsetup{%s}' % self.elements['sphinxsetup']
459
+ )
411
460
  if self.elements['extraclassoptions']:
412
- self.elements['classoptions'] += ',' + \
413
- self.elements['extraclassoptions']
461
+ self.elements['classoptions'] += ',' + self.elements['extraclassoptions']
414
462
 
415
- self.highlighter = highlighting.PygmentsBridge('latex', self.config.pygments_style,
416
- latex_engine=self.config.latex_engine)
463
+ self.highlighter = highlighting.PygmentsBridge(
464
+ 'latex', self.config.pygments_style, latex_engine=self.config.latex_engine
465
+ )
417
466
  self.context: list[Any] = []
418
467
  self.descstack: list[str] = []
419
468
  self.tables: list[Table] = []
@@ -443,10 +492,13 @@ class LaTeXTranslator(SphinxTranslator):
443
492
  def hypertarget(self, id: str, withdoc: bool = True, anchor: bool = True) -> str:
444
493
  if withdoc:
445
494
  id = self.curfilestack[-1] + ':' + id
446
- return (r'\phantomsection' if anchor else '') + r'\label{%s}' % self.idescape(id)
495
+ escaped_id = self.idescape(id)
496
+ return (r'\phantomsection' if anchor else '') + r'\label{%s}' % escaped_id
447
497
 
448
498
  def hypertarget_to(self, node: Element, anchor: bool = False) -> str:
449
- labels = ''.join(self.hypertarget(node_id, anchor=False) for node_id in node['ids'])
499
+ labels = ''.join(
500
+ self.hypertarget(node_id, anchor=False) for node_id in node['ids']
501
+ )
450
502
  if anchor:
451
503
  return r'\phantomsection' + labels
452
504
  else:
@@ -462,9 +514,9 @@ class LaTeXTranslator(SphinxTranslator):
462
514
  return texescape.escape(s, self.config.latex_engine)
463
515
 
464
516
  def idescape(self, id: str) -> str:
465
- return r'\detokenize{%s}' % str(id).translate(tex_replace_map).\
466
- encode('ascii', 'backslashreplace').decode('ascii').\
467
- replace('\\', '_')
517
+ id = str(id).translate(tex_replace_map)
518
+ id = id.encode('ascii', 'backslashreplace').decode('ascii')
519
+ return r'\detokenize{%s}' % id.replace('\\', '_')
468
520
 
469
521
  def babel_renewcommand(self, command: str, definition: str) -> str:
470
522
  if self.elements['multilingual']:
@@ -474,10 +526,12 @@ class LaTeXTranslator(SphinxTranslator):
474
526
  prefix = ''
475
527
  suffix = ''
476
528
 
477
- return fr'{prefix}\renewcommand{{{command}}}{{{definition}}}{suffix}' + CR
529
+ return rf'{prefix}\renewcommand{{{command}}}{{{definition}}}{suffix}' + CR
478
530
 
479
531
  def generate_indices(self) -> str:
480
- def generate(content: list[tuple[str, list[IndexEntry]]], collapsed: bool) -> None:
532
+ def generate(
533
+ content: list[tuple[str, list[IndexEntry]]], collapsed: bool
534
+ ) -> None:
481
535
  ret.append(r'\begin{sphinxtheindex}' + CR)
482
536
  ret.append(r'\let\bigletter\sphinxstyleindexlettergroup' + CR)
483
537
  for i, (letter, entries) in enumerate(content):
@@ -487,13 +541,19 @@ class LaTeXTranslator(SphinxTranslator):
487
541
  for entry in entries:
488
542
  if not entry[3]:
489
543
  continue
490
- ret.append(r'\item\relax\sphinxstyleindexentry{%s}' %
491
- self.encode(entry[0]))
544
+ ret.append(
545
+ r'\item\relax\sphinxstyleindexentry{%s}' % self.encode(entry[0])
546
+ )
492
547
  if entry[4]:
493
548
  # add "extra" info
494
- ret.append(r'\sphinxstyleindexextra{%s}' % self.encode(entry[4]))
495
- ret.append(r'\sphinxstyleindexpageref{%s:%s}' %
496
- (entry[2], self.idescape(entry[3])) + CR)
549
+ ret.append(
550
+ r'\sphinxstyleindexextra{%s}' % self.encode(entry[4])
551
+ )
552
+ ret.append(
553
+ r'\sphinxstyleindexpageref{%s:%s}'
554
+ % (entry[2], self.idescape(entry[3]))
555
+ + CR
556
+ )
497
557
  ret.append(r'\end{sphinxtheindex}' + CR)
498
558
 
499
559
  ret = []
@@ -504,16 +564,18 @@ class LaTeXTranslator(SphinxTranslator):
504
564
  indices_config = frozenset(indices_config)
505
565
  else:
506
566
  check_names = False
507
- for domain_name in sorted(self.builder.env.domains):
508
- domain = self.builder.env.domains[domain_name]
567
+ for domain in self.builder.env.domains.sorted():
509
568
  for index_cls in domain.indices:
510
569
  index_name = f'{domain.name}-{index_cls.name}'
511
570
  if check_names and index_name not in indices_config:
512
571
  continue
513
572
  content, collapsed = index_cls(domain).generate(
514
- self.builder.docnames)
573
+ self.builder.docnames
574
+ )
515
575
  if content:
516
- ret.append(r'\renewcommand{\indexname}{%s}' % index_cls.localname + CR)
576
+ ret.append(
577
+ r'\renewcommand{\indexname}{%s}' % index_cls.localname + CR
578
+ )
517
579
  generate(content, collapsed)
518
580
 
519
581
  return ''.join(ret)
@@ -521,15 +583,17 @@ class LaTeXTranslator(SphinxTranslator):
521
583
  def render(self, template_name: str, variables: dict[str, Any]) -> str:
522
584
  renderer = LaTeXRenderer(latex_engine=self.config.latex_engine)
523
585
  for template_dir in self.config.templates_path:
524
- template = path.join(self.builder.confdir, template_dir,
525
- template_name)
586
+ template = path.join(self.builder.confdir, template_dir, template_name)
526
587
  if path.exists(template):
527
588
  return renderer.render(template, variables)
528
589
  elif template.endswith('.jinja'):
529
590
  legacy_template = template.removesuffix('.jinja') + '_t'
530
591
  if path.exists(legacy_template):
531
- logger.warning(__('template %s not found; loading from legacy %s instead'),
532
- template_name, legacy_template)
592
+ logger.warning(
593
+ __('template %s not found; loading from legacy %s instead'),
594
+ template_name,
595
+ legacy_template,
596
+ )
533
597
  return renderer.render(legacy_template, variables)
534
598
 
535
599
  return renderer.render(template_name, variables)
@@ -572,8 +636,7 @@ class LaTeXTranslator(SphinxTranslator):
572
636
  self.body.append(BLANKLINE)
573
637
 
574
638
  def depart_section(self, node: Element) -> None:
575
- self.sectionlevel = max(self.sectionlevel - 1,
576
- self.top_sectionlevel - 1)
639
+ self.sectionlevel = max(self.sectionlevel - 1, self.top_sectionlevel - 1)
577
640
 
578
641
  def visit_problematic(self, node: Element) -> None:
579
642
  self.body.append(r'{\color{red}\bfseries{}')
@@ -582,13 +645,23 @@ class LaTeXTranslator(SphinxTranslator):
582
645
  self.body.append('}')
583
646
 
584
647
  def visit_topic(self, node: Element) -> None:
585
- self.in_minipage = 1
586
- self.body.append(CR + r'\begin{sphinxShadowBox}' + CR)
648
+ self.in_minipage += 1
649
+ if 'contents' in node.get('classes', []):
650
+ self.body.append(CR + r'\begin{sphinxcontents}' + CR)
651
+ self.context.append(r'\end{sphinxcontents}' + CR)
652
+ else:
653
+ self.body.append(CR + r'\begin{sphinxtopic}' + CR)
654
+ self.context.append(r'\end{sphinxtopic}' + CR)
587
655
 
588
656
  def depart_topic(self, node: Element) -> None:
589
- self.in_minipage = 0
590
- self.body.append(r'\end{sphinxShadowBox}' + CR)
591
- visit_sidebar = visit_topic
657
+ self.in_minipage -= 1
658
+ self.body.append(self.context.pop())
659
+
660
+ def visit_sidebar(self, node: Element) -> None:
661
+ self.in_minipage += 1
662
+ self.body.append(CR + r'\begin{sphinxsidebar}' + CR)
663
+ self.context.append(r'\end{sphinxsidebar}' + CR)
664
+
592
665
  depart_sidebar = depart_topic
593
666
 
594
667
  def visit_glossary(self, node: Element) -> None:
@@ -630,10 +703,13 @@ class LaTeXTranslator(SphinxTranslator):
630
703
  raise nodes.SkipNode
631
704
  if isinstance(parent, nodes.section):
632
705
  if self.this_is_the_title:
633
- if len(node.children) != 1 and not isinstance(node.children[0],
634
- nodes.Text):
635
- logger.warning(__('document title is not a single Text node'),
636
- location=node)
706
+ if (
707
+ len(node.children) != 1
708
+ and not isinstance(node.children[0], nodes.Text)
709
+ ): # fmt: skip
710
+ logger.warning(
711
+ __('document title is not a single Text node'), location=node
712
+ )
637
713
  if not self.elements['title']:
638
714
  # text needs to be escaped since it is inserted into
639
715
  # the output literally
@@ -642,16 +718,19 @@ class LaTeXTranslator(SphinxTranslator):
642
718
  raise nodes.SkipNode
643
719
  short = ''
644
720
  if any(node.findall(nodes.image)):
645
- short = ('[%s]' % self.escape(' '.join(clean_astext(node).split())))
721
+ short = '[%s]' % self.escape(' '.join(clean_astext(node).split()))
646
722
 
647
723
  try:
648
- self.body.append(fr'\{self.sectionnames[self.sectionlevel]}{short}{{')
724
+ self.body.append(rf'\{self.sectionnames[self.sectionlevel]}{short}{{')
649
725
  except IndexError:
650
726
  # just use "subparagraph", it's not numbered anyway
651
- self.body.append(fr'\{self.sectionnames[-1]}{short}{{')
727
+ self.body.append(rf'\{self.sectionnames[-1]}{short}{{')
652
728
  self.context.append('}' + CR + self.hypertarget_to(node.parent))
653
729
  elif isinstance(parent, nodes.topic):
654
- self.body.append(r'\sphinxstyletopictitle{')
730
+ if 'contents' in parent.get('classes', []):
731
+ self.body.append(r'\sphinxstylecontentstitle{')
732
+ else:
733
+ self.body.append(r'\sphinxstyletopictitle{')
655
734
  self.context.append('}' + CR)
656
735
  elif isinstance(parent, nodes.sidebar):
657
736
  self.body.append(r'\sphinxstylesidebartitle{')
@@ -663,9 +742,13 @@ class LaTeXTranslator(SphinxTranslator):
663
742
  # Redirect body output until title is finished.
664
743
  self.pushbody([])
665
744
  else:
666
- logger.warning(__('encountered title node not in section, topic, table, '
667
- 'admonition or sidebar'),
668
- location=node)
745
+ logger.warning(
746
+ __(
747
+ 'encountered title node not in section, topic, table, '
748
+ 'admonition or sidebar'
749
+ ),
750
+ location=node,
751
+ )
669
752
  self.body.append(r'\sphinxstyleothertitle{')
670
753
  self.context.append('}' + CR)
671
754
  self.in_title = 1
@@ -743,26 +826,37 @@ class LaTeXTranslator(SphinxTranslator):
743
826
 
744
827
  if multi_tp_list:
745
828
  if multi_arglist:
746
- self.body.append(CR + r'\pysigwithonelineperargwithonelinepertparg{')
829
+ self.body.append(
830
+ CR
831
+ + r'\pysigwithonelineperargwithonelinepertparg'
832
+ + CR
833
+ + '{'
834
+ )
747
835
  else:
748
- self.body.append(CR + r'\pysiglinewithargsretwithonelinepertparg{')
836
+ self.body.append(
837
+ CR + r'\pysiglinewithargsretwithonelinepertparg' + CR + '{'
838
+ )
749
839
  else:
750
840
  if multi_arglist:
751
- self.body.append(CR + r'\pysigwithonelineperargwithtypelist{')
841
+ self.body.append(
842
+ CR + r'\pysigwithonelineperargwithtypelist' + CR + '{'
843
+ )
752
844
  else:
753
- self.body.append(CR + r'\pysiglinewithargsretwithtypelist{')
845
+ self.body.append(
846
+ CR + r'\pysiglinewithargsretwithtypelist' + CR + '{'
847
+ )
754
848
  break
755
849
 
756
850
  if isinstance(child, addnodes.desc_parameterlist):
757
851
  # arglist only: \macro{name}{arglist}{retann}
758
852
  if has_multi_line(child):
759
- self.body.append(CR + r'\pysigwithonelineperarg{')
853
+ self.body.append(CR + r'\pysigwithonelineperarg' + CR + '{')
760
854
  else:
761
- self.body.append(CR + r'\pysiglinewithargsret{')
855
+ self.body.append(CR + r'\pysiglinewithargsret' + CR + '{')
762
856
  break
763
857
  else:
764
858
  # no tp_list, no arglist: \macro{name}
765
- self.body.append(CR + r'\pysigline{')
859
+ self.body.append(CR + r'\pysigline' + CR + '{')
766
860
 
767
861
  def _depart_signature_line(self, node: Element) -> None:
768
862
  self.body.append('}')
@@ -838,7 +932,9 @@ class LaTeXTranslator(SphinxTranslator):
838
932
  def depart_desc_returns(self, node: Element) -> None:
839
933
  self.body.append(r'}')
840
934
 
841
- def _visit_sig_parameter_list(self, node: Element, parameter_group: type[Element]) -> None:
935
+ def _visit_sig_parameter_list(
936
+ self, node: Element, parameter_group: type[Element]
937
+ ) -> None:
842
938
  """Visit a signature parameters or type parameters list.
843
939
 
844
940
  The *parameter_group* value is the type of a child node acting as a required parameter
@@ -853,7 +949,9 @@ class LaTeXTranslator(SphinxTranslator):
853
949
  self.param_group_index = 0
854
950
  # Counts as what we call a parameter group either a required parameter, or a
855
951
  # set of contiguous optional ones.
856
- self.list_is_required_param = [isinstance(c, parameter_group) for c in node.children]
952
+ self.list_is_required_param = [
953
+ isinstance(c, parameter_group) for c in node.children
954
+ ]
857
955
  # How many required parameters are left.
858
956
  self.required_params_left = sum(self.list_is_required_param)
859
957
  self.param_separator = r'\sphinxparamcomma '
@@ -863,26 +961,32 @@ class LaTeXTranslator(SphinxTranslator):
863
961
  if self.has_tp_list:
864
962
  if self.orphan_tp_list:
865
963
  # close type parameters list (#2)
866
- self.body.append('}{')
964
+ self.body.append('}' + CR + '{')
867
965
  # empty parameters list argument (#3)
868
966
  return
869
967
  else:
870
968
  # close name argument (#1), open parameters list argument (#2)
871
- self.body.append('}{')
969
+ self.body.append('}' + CR + '{')
872
970
  self._visit_sig_parameter_list(node, addnodes.desc_parameter)
873
971
 
874
972
  def depart_desc_parameterlist(self, node: Element) -> None:
875
973
  # close parameterlist, open return annotation
876
- self.body.append('}{')
974
+ assert not self.orphan_tp_list
975
+ self.body.append('}' + CR + '{')
877
976
 
878
977
  def visit_desc_type_parameter_list(self, node: Element) -> None:
879
978
  # close name argument (#1), open type parameters list argument (#2)
880
- self.body.append('}{')
979
+ self.body.append('}' + CR + '{')
881
980
  self._visit_sig_parameter_list(node, addnodes.desc_type_parameter)
882
981
 
883
982
  def depart_desc_type_parameter_list(self, node: Element) -> None:
884
- # close type parameters list, open parameters list argument (#3)
885
- self.body.append('}{')
983
+ if self.orphan_tp_list:
984
+ # this node next sibling isn't a desc_parameterlist, there are no parameters:
985
+ # close the type list, output an empty parameter list, open return annotation.
986
+ self.body.append('}' + CR + '{}' + CR + '{')
987
+ else:
988
+ # close type parameters list, open parameters list argument (#3)
989
+ self.body.append('}' + CR + '{')
886
990
 
887
991
  def _visit_sig_parameter(self, node: Element, parameter_macro: str) -> None:
888
992
  if self.is_first_param:
@@ -901,13 +1005,18 @@ class LaTeXTranslator(SphinxTranslator):
901
1005
  self.body.append('}')
902
1006
  is_required = self.list_is_required_param[self.param_group_index]
903
1007
  if self.multi_line_parameter_list:
904
- is_last_group = self.param_group_index + 1 == len(self.list_is_required_param)
1008
+ len_lirp = len(self.list_is_required_param)
1009
+ is_last_group = self.param_group_index + 1 == len_lirp
905
1010
  next_is_required = (
906
1011
  not is_last_group
907
1012
  and self.list_is_required_param[self.param_group_index + 1]
908
1013
  )
909
1014
  opt_param_left_at_level = self.params_left_at_level > 0
910
- if opt_param_left_at_level or is_required and (is_last_group or next_is_required):
1015
+ if (
1016
+ opt_param_left_at_level
1017
+ or is_required
1018
+ and (is_last_group or next_is_required)
1019
+ ):
911
1020
  self.body.append(self.param_separator)
912
1021
 
913
1022
  elif self.required_params_left:
@@ -929,8 +1038,9 @@ class LaTeXTranslator(SphinxTranslator):
929
1038
  self._depart_sig_parameter(node)
930
1039
 
931
1040
  def visit_desc_optional(self, node: Element) -> None:
932
- self.params_left_at_level = sum(isinstance(c, addnodes.desc_parameter)
933
- for c in node.children)
1041
+ self.params_left_at_level = sum(
1042
+ isinstance(c, addnodes.desc_parameter) for c in node.children
1043
+ )
934
1044
  self.optional_param_level += 1
935
1045
  self.max_optional_param_level = self.optional_param_level
936
1046
  if self.multi_line_parameter_list:
@@ -966,7 +1076,9 @@ class LaTeXTranslator(SphinxTranslator):
966
1076
 
967
1077
  def visit_seealso(self, node: Element) -> None:
968
1078
  self.body.append(BLANKLINE)
969
- self.body.append(r'\begin{sphinxseealso}{%s:}' % admonitionlabels['seealso'] + CR)
1079
+ self.body.append(
1080
+ r'\begin{sphinxseealso}{%s:}' % admonitionlabels['seealso'] + CR
1081
+ )
970
1082
  self.no_latex_floats += 1
971
1083
  if self.table:
972
1084
  self.table.has_problematic = True
@@ -990,7 +1102,7 @@ class LaTeXTranslator(SphinxTranslator):
990
1102
  __('unsupported rubric heading level: %s'),
991
1103
  level,
992
1104
  type='latex',
993
- location=node
1105
+ location=node,
994
1106
  )
995
1107
 
996
1108
  self.body.append(rf'\{tag}*{{')
@@ -1034,15 +1146,17 @@ class LaTeXTranslator(SphinxTranslator):
1034
1146
  assert self.table is not None
1035
1147
  if self.table.get_table_type() == 'longtable':
1036
1148
  raise UnsupportedError(
1037
- '%s:%s: longtable does not support nesting a table.' %
1038
- (self.curfilestack[-1], node.line or ''))
1149
+ '%s:%s: longtable does not support nesting a table.'
1150
+ % (self.curfilestack[-1], node.line or '')
1151
+ )
1039
1152
  # change type of parent table to tabular
1040
1153
  # see https://groups.google.com/d/msg/sphinx-users/7m3NeOBixeo/9LKP2B4WBQAJ
1041
1154
  self.table.has_problematic = True
1042
1155
  elif len(self.tables) > 2:
1043
1156
  raise UnsupportedError(
1044
- '%s:%s: deeply nested tables are not implemented.' %
1045
- (self.curfilestack[-1], node.line or ''))
1157
+ '%s:%s: deeply nested tables are not implemented.'
1158
+ % (self.curfilestack[-1], node.line or '')
1159
+ )
1046
1160
 
1047
1161
  table = Table(node)
1048
1162
  self.tables.append(table)
@@ -1060,16 +1174,22 @@ class LaTeXTranslator(SphinxTranslator):
1060
1174
  table.styles.append('novlines')
1061
1175
  table.colsep = ''
1062
1176
  if 'colwidths-given' in node.get('classes', []):
1063
- logger.info(__('both tabularcolumns and :widths: option are given. '
1064
- ':widths: is ignored.'), location=node)
1177
+ logger.info(
1178
+ __(
1179
+ 'both tabularcolumns and :widths: option are given. '
1180
+ ':widths: is ignored.'
1181
+ ),
1182
+ location=node,
1183
+ )
1065
1184
  self.next_table_colspec = None
1066
1185
 
1067
1186
  def depart_table(self, node: Element) -> None:
1068
1187
  assert self.table is not None
1069
1188
  labels = self.hypertarget_to(node)
1070
1189
  table_type = self.table.get_table_type()
1071
- table = self.render(table_type + '.tex.jinja',
1072
- {'table': self.table, 'labels': labels})
1190
+ table = self.render(
1191
+ table_type + '.tex.jinja', {'table': self.table, 'labels': labels}
1192
+ )
1073
1193
  self.body.append(BLANKLINE)
1074
1194
  self.body.append(table)
1075
1195
  self.body.append(CR)
@@ -1130,15 +1250,19 @@ class LaTeXTranslator(SphinxTranslator):
1130
1250
  # insert suitable strut for equalizing row heights in given multirow
1131
1251
  self.body.append(r'\sphinxtablestrut{%d}' % cell.cell_id)
1132
1252
  else: # use \multicolumn for wide multirow cell
1133
- self.body.append(r'\multicolumn{%d}{%sl%s}{\sphinxtablestrut{%d}}' %
1134
- (cell.width, _colsep, _colsep, cell.cell_id))
1253
+ self.body.append(
1254
+ r'\multicolumn{%d}{%sl%s}{\sphinxtablestrut{%d}}'
1255
+ % (cell.width, _colsep, _colsep, cell.cell_id)
1256
+ )
1135
1257
 
1136
1258
  def depart_row(self, node: Element) -> None:
1137
1259
  assert self.table is not None
1138
1260
  self.body.append(r'\\' + CR)
1139
1261
  cells = [self.table.cell(self.table.row, i) for i in range(self.table.colcount)]
1140
- underlined = [cell.row + cell.height == self.table.row + 1 # type: ignore[union-attr]
1141
- for cell in cells]
1262
+ underlined = [
1263
+ cell.row + cell.height == self.table.row + 1 # type: ignore[union-attr]
1264
+ for cell in cells
1265
+ ]
1142
1266
  if all(underlined):
1143
1267
  self.body.append(r'\sphinxhline')
1144
1268
  else:
@@ -1175,28 +1299,46 @@ class LaTeXTranslator(SphinxTranslator):
1175
1299
  if cell.width > 1:
1176
1300
  if self.config.latex_use_latex_multicolumn:
1177
1301
  if self.table.col == 0:
1178
- self.body.append(r'\multicolumn{%d}{%sl%s}{%%' %
1179
- (cell.width, _colsep, _colsep) + CR)
1302
+ self.body.append(
1303
+ r'\multicolumn{%d}{%sl%s}{%%' % (cell.width, _colsep, _colsep)
1304
+ + CR
1305
+ )
1180
1306
  else:
1181
- self.body.append(r'\multicolumn{%d}{l%s}{%%' % (cell.width, _colsep) + CR)
1307
+ self.body.append(
1308
+ r'\multicolumn{%d}{l%s}{%%' % (cell.width, _colsep) + CR
1309
+ )
1182
1310
  context = '}%' + CR
1183
1311
  else:
1184
1312
  self.body.append(r'\sphinxstartmulticolumn{%d}%%' % cell.width + CR)
1185
1313
  context = r'\sphinxstopmulticolumn' + CR
1186
1314
  if cell.height > 1:
1187
1315
  # \sphinxmultirow 2nd arg "cell_id" will serve as id for LaTeX macros as well
1188
- self.body.append(r'\sphinxmultirow{%d}{%d}{%%' % (cell.height, cell.cell_id) + CR)
1316
+ self.body.append(
1317
+ r'\sphinxmultirow{%d}{%d}{%%' % (cell.height, cell.cell_id) + CR
1318
+ )
1189
1319
  context = '}%' + CR + context
1190
1320
  if cell.width > 1 or cell.height > 1:
1191
- self.body.append(r'\begin{varwidth}[t]{\sphinxcolwidth{%d}{%d}}'
1192
- % (cell.width, self.table.colcount) + CR)
1193
- context = (r'\par' + CR + r'\vskip-\baselineskip'
1194
- r'\vbox{\hbox{\strut}}\end{varwidth}%' + CR + context)
1321
+ self.body.append(
1322
+ r'\begin{varwidth}[t]{\sphinxcolwidth{%d}{%d}}'
1323
+ % (cell.width, self.table.colcount)
1324
+ + CR
1325
+ )
1326
+ context = (
1327
+ r'\par' + CR + r'\vskip-\baselineskip'
1328
+ r'\vbox{\hbox{\strut}}\end{varwidth}%' + CR + context
1329
+ )
1195
1330
  self.needs_linetrimming = 1
1196
1331
  if len(list(node.findall(nodes.paragraph))) >= 2:
1197
1332
  self.table.has_oldproblematic = True
1198
- if isinstance(node.parent.parent, nodes.thead) or (cell.col in self.table.stubs):
1199
- if len(node) == 1 and isinstance(node[0], nodes.paragraph) and node.astext() == '':
1333
+ if (
1334
+ isinstance(node.parent.parent, nodes.thead)
1335
+ or (cell.col in self.table.stubs)
1336
+ ): # fmt: skip
1337
+ if (
1338
+ len(node) == 1
1339
+ and isinstance(node[0], nodes.paragraph)
1340
+ and node.astext() == ''
1341
+ ):
1200
1342
  pass
1201
1343
  else:
1202
1344
  self.body.append(r'\sphinxstyletheadfamily ')
@@ -1235,8 +1377,10 @@ class LaTeXTranslator(SphinxTranslator):
1235
1377
  self.body.append(r'\sphinxtablestrut{%d}' % nextcell.cell_id)
1236
1378
  else:
1237
1379
  # use \multicolumn for not first row of wide multirow cell
1238
- self.body.append(r'\multicolumn{%d}{l%s}{\sphinxtablestrut{%d}}' %
1239
- (nextcell.width, _colsep, nextcell.cell_id))
1380
+ self.body.append(
1381
+ r'\multicolumn{%d}{l%s}{\sphinxtablestrut{%d}}'
1382
+ % (nextcell.width, _colsep, nextcell.cell_id)
1383
+ )
1240
1384
  self.table.col += nextcell.width
1241
1385
 
1242
1386
  def visit_acks(self, node: Element) -> None:
@@ -1276,15 +1420,18 @@ class LaTeXTranslator(SphinxTranslator):
1276
1420
  else:
1277
1421
  return get_nested_level(node.parent)
1278
1422
 
1279
- enum = "enum%s" % toRoman(get_nested_level(node)).lower()
1280
- enumnext = "enum%s" % toRoman(get_nested_level(node) + 1).lower()
1423
+ enum = 'enum%s' % toRoman(get_nested_level(node)).lower()
1424
+ enumnext = 'enum%s' % toRoman(get_nested_level(node) + 1).lower()
1281
1425
  style = ENUMERATE_LIST_STYLE.get(get_enumtype(node))
1282
1426
  prefix = node.get('prefix', '')
1283
1427
  suffix = node.get('suffix', '.')
1284
1428
 
1285
1429
  self.body.append(r'\begin{enumerate}' + CR)
1286
- self.body.append(r'\sphinxsetlistlabels{%s}{%s}{%s}{%s}{%s}%%' %
1287
- (style, enum, enumnext, prefix, suffix) + CR)
1430
+ self.body.append(
1431
+ r'\sphinxsetlistlabels{%s}{%s}{%s}{%s}{%s}%%'
1432
+ % (style, enum, enumnext, prefix, suffix)
1433
+ + CR
1434
+ )
1288
1435
  if 'start' in node:
1289
1436
  self.body.append(r'\setcounter{%s}{%d}' % (enum, node['start'] - 1) + CR)
1290
1437
  if self.table:
@@ -1364,9 +1511,12 @@ class LaTeXTranslator(SphinxTranslator):
1364
1511
 
1365
1512
  def visit_paragraph(self, node: Element) -> None:
1366
1513
  index = node.parent.index(node)
1367
- if (index > 0 and isinstance(node.parent, nodes.compound) and
1368
- not isinstance(node.parent[index - 1], nodes.paragraph) and
1369
- not isinstance(node.parent[index - 1], nodes.compound)):
1514
+ if (
1515
+ index > 0
1516
+ and isinstance(node.parent, nodes.compound)
1517
+ and not isinstance(node.parent[index - 1], nodes.paragraph)
1518
+ and not isinstance(node.parent[index - 1], nodes.compound)
1519
+ ):
1370
1520
  # insert blank line, if the paragraph follows a non-paragraph node in a compound
1371
1521
  self.body.append(r'\noindent' + CR)
1372
1522
  elif index == 1 and isinstance(node.parent, nodes.footnote | footnotetext):
@@ -1396,8 +1546,10 @@ class LaTeXTranslator(SphinxTranslator):
1396
1546
  if self.compact_list > 1:
1397
1547
  self.body.append(r'\setlength{\multicolsep}{0pt}' + CR)
1398
1548
  self.body.append(r'\begin{multicols}{' + ncolumns + r'}\raggedright' + CR)
1399
- self.body.append(r'\begin{itemize}\setlength{\itemsep}{0pt}'
1400
- r'\setlength{\parskip}{0pt}' + CR)
1549
+ self.body.append(
1550
+ r'\begin{itemize}\setlength{\itemsep}{0pt}'
1551
+ r'\setlength{\parskip}{0pt}' + CR
1552
+ )
1401
1553
  if self.table:
1402
1554
  self.table.has_problematic = True
1403
1555
 
@@ -1454,8 +1606,9 @@ class LaTeXTranslator(SphinxTranslator):
1454
1606
  if not include_graphics_options:
1455
1607
  # if no "width" nor "height", \sphinxincludegraphics will fit
1456
1608
  # to the available text width if oversized after rescaling.
1457
- include_graphics_options.append('scale=%s'
1458
- % (float(node['scale']) / 100.0))
1609
+ include_graphics_options.append(
1610
+ 'scale=%s' % (float(node['scale']) / 100.0)
1611
+ )
1459
1612
  if 'align' in node:
1460
1613
  align_prepost = {
1461
1614
  # By default latex aligns the top of an image.
@@ -1500,9 +1653,9 @@ class LaTeXTranslator(SphinxTranslator):
1500
1653
  if self.in_title and base:
1501
1654
  # Lowercase tokens forcely because some fncychap themes capitalize
1502
1655
  # the options of \sphinxincludegraphics unexpectedly (ex. WIDTH=...).
1503
- cmd = fr'\lowercase{{\sphinxincludegraphics{options}}}{{{{{base}}}{ext}}}'
1656
+ cmd = rf'\lowercase{{\sphinxincludegraphics{options}}}{{{{{base}}}{ext}}}'
1504
1657
  else:
1505
- cmd = fr'\sphinxincludegraphics{options}{{{{{base}}}{ext}}}'
1658
+ cmd = rf'\sphinxincludegraphics{options}{{{{{base}}}{ext}}}'
1506
1659
  # escape filepath for includegraphics, https://tex.stackexchange.com/a/202714/41112
1507
1660
  if '#' in base:
1508
1661
  cmd = r'{\catcode`\#=12' + cmd + '}'
@@ -1515,7 +1668,7 @@ class LaTeXTranslator(SphinxTranslator):
1515
1668
  def visit_figure(self, node: Element) -> None:
1516
1669
  align = self.elements['figure_align']
1517
1670
  if self.no_latex_floats:
1518
- align = "H"
1671
+ align = 'H'
1519
1672
  if self.table:
1520
1673
  # Blank line is needed if text precedes
1521
1674
  self.body.append(BLANKLINE)
@@ -1540,13 +1693,18 @@ class LaTeXTranslator(SphinxTranslator):
1540
1693
  # Insert a blank line to prevent an infinite loop
1541
1694
  # https://github.com/sphinx-doc/sphinx/issues/7059
1542
1695
  self.body.append(BLANKLINE)
1543
- self.body.append(r'\begin{wrapfigure}{%s}{%s}' %
1544
- ('r' if node['align'] == 'right' else 'l', length or '0pt') + CR)
1696
+ self.body.append(
1697
+ r'\begin{wrapfigure}{%s}{%s}'
1698
+ % ('r' if node['align'] == 'right' else 'l', length or '0pt')
1699
+ + CR
1700
+ )
1545
1701
  self.body.append(r'\centering')
1546
- self.context.append(r'\end{wrapfigure}' +
1547
- BLANKLINE +
1548
- r'\mbox{}\par\vskip-\dimexpr\baselineskip+\parskip\relax' +
1549
- CR) # avoid disappearance if no text next issues/11079
1702
+ self.context.append(
1703
+ r'\end{wrapfigure}'
1704
+ + BLANKLINE
1705
+ + r'\mbox{}\par\vskip-\dimexpr\baselineskip+\parskip\relax'
1706
+ + CR
1707
+ ) # avoid disappearance if no text next issues/11079
1550
1708
  elif self.in_minipage:
1551
1709
  self.body.append(CR + r'\begin{center}')
1552
1710
  self.context.append(r'\end{center}' + CR)
@@ -1596,8 +1754,9 @@ class LaTeXTranslator(SphinxTranslator):
1596
1754
 
1597
1755
  def _visit_named_admonition(self, node: Element) -> None:
1598
1756
  label = admonitionlabels[node.tagname]
1599
- self.body.append(CR + r'\begin{sphinxadmonition}{%s}{%s:}' %
1600
- (node.tagname, label))
1757
+ self.body.append(
1758
+ CR + r'\begin{sphinxadmonition}{%s}{%s:}' % (node.tagname, label)
1759
+ )
1601
1760
  self.no_latex_floats += 1
1602
1761
  if self.table:
1603
1762
  self.table.has_problematic = True
@@ -1657,10 +1816,13 @@ class LaTeXTranslator(SphinxTranslator):
1657
1816
  while isinstance(next_node, nodes.target):
1658
1817
  next_node = next_node.next_node(ascend=True)
1659
1818
 
1660
- domain = cast(StandardDomain, self.builder.env.get_domain('std'))
1819
+ domain = self.builder.env.domains.standard_domain
1661
1820
  if isinstance(next_node, HYPERLINK_SUPPORT_NODES):
1662
1821
  return
1663
- if domain.get_enumerable_node_type(next_node) and domain.get_numfig_title(next_node):
1822
+ if (
1823
+ domain.get_enumerable_node_type(next_node)
1824
+ and domain.get_numfig_title(next_node)
1825
+ ): # fmt: skip
1664
1826
  return
1665
1827
 
1666
1828
  if 'refuri' in node:
@@ -1669,7 +1831,10 @@ class LaTeXTranslator(SphinxTranslator):
1669
1831
  return
1670
1832
  if node.get('refid'):
1671
1833
  prev_node = get_prev_node(node)
1672
- if isinstance(prev_node, nodes.reference) and node['refid'] == prev_node['refid']:
1834
+ if (
1835
+ isinstance(prev_node, nodes.reference)
1836
+ and node['refid'] == prev_node['refid']
1837
+ ):
1673
1838
  # a target for a hyperlink reference having alias
1674
1839
  pass
1675
1840
  else:
@@ -1738,27 +1903,30 @@ class LaTeXTranslator(SphinxTranslator):
1738
1903
  try:
1739
1904
  p1, p2 = parts
1740
1905
  P1, P2 = styled
1741
- self.body.append(fr'\index{{{p1}@{P1}!{p2}@{P2}{m}}}')
1906
+ self.body.append(rf'\index{{{p1}@{P1}!{p2}@{P2}{m}}}')
1742
1907
  except ValueError:
1743
- p, = parts
1744
- P, = styled
1745
- self.body.append(fr'\index{{{p}@{P}{m}}}')
1908
+ (p,) = parts
1909
+ (P,) = styled
1910
+ self.body.append(rf'\index{{{p}@{P}{m}}}')
1746
1911
  elif type == 'pair':
1747
1912
  p1, p2 = parts
1748
1913
  P1, P2 = styled
1749
- self.body.append(fr'\index{{{p1}@{P1}!{p2}@{P2}{m}}}'
1750
- fr'\index{{{p2}@{P2}!{p1}@{P1}{m}}}')
1914
+ self.body.append(
1915
+ rf'\index{{{p1}@{P1}!{p2}@{P2}{m}}}'
1916
+ rf'\index{{{p2}@{P2}!{p1}@{P1}{m}}}'
1917
+ )
1751
1918
  elif type == 'triple':
1752
1919
  p1, p2, p3 = parts
1753
1920
  P1, P2, P3 = styled
1754
1921
  self.body.append(
1755
- fr'\index{{{p1}@{P1}!{p2} {p3}@{P2} {P3}{m}}}'
1756
- fr'\index{{{p2}@{P2}!{p3}, {p1}@{P3}, {P1}{m}}}'
1757
- fr'\index{{{p3}@{P3}!{p1} {p2}@{P1} {P2}{m}}}')
1922
+ rf'\index{{{p1}@{P1}!{p2} {p3}@{P2} {P3}{m}}}'
1923
+ rf'\index{{{p2}@{P2}!{p3}, {p1}@{P3}, {P1}{m}}}'
1924
+ rf'\index{{{p3}@{P3}!{p1} {p2}@{P1} {P2}{m}}}'
1925
+ )
1758
1926
  elif type in {'see', 'seealso'}:
1759
1927
  p1, p2 = parts
1760
1928
  P1, _P2 = styled
1761
- self.body.append(fr'\index{{{p1}@{P1}|see{{{p2}}}}}')
1929
+ self.body.append(rf'\index{{{p1}@{P1}|see{{{p2}}}}}')
1762
1930
  else:
1763
1931
  logger.warning(__('unknown index entry type %s found'), type)
1764
1932
  except ValueError as err:
@@ -1793,8 +1961,7 @@ class LaTeXTranslator(SphinxTranslator):
1793
1961
  id = self.curfilestack[-1] + ':' + uri[1:]
1794
1962
  self.body.append(self.hyperlink(id))
1795
1963
  self.body.append(r'\sphinxsamedocref{')
1796
- if self.config.latex_show_pagerefs and not \
1797
- self.in_production_list:
1964
+ if self.config.latex_show_pagerefs and not self.in_production_list:
1798
1965
  self.context.append('}}} (%s)' % self.hyperpageref(id))
1799
1966
  else:
1800
1967
  self.context.append('}}}')
@@ -1808,9 +1975,11 @@ class LaTeXTranslator(SphinxTranslator):
1808
1975
  # reference to a label
1809
1976
  id = uri[1:].replace('#', ':')
1810
1977
  self.body.append(self.hyperlink(id))
1811
- if (len(node) and
1812
- isinstance(node[0], nodes.Element) and
1813
- 'std-term' in node[0].get('classes', [])):
1978
+ if (
1979
+ len(node)
1980
+ and isinstance(node[0], nodes.Element)
1981
+ and 'std-term' in node[0].get('classes', [])
1982
+ ):
1814
1983
  # don't add a pageref for glossary terms
1815
1984
  self.context.append('}}}')
1816
1985
  # mark up as termreference
@@ -1846,13 +2015,17 @@ class LaTeXTranslator(SphinxTranslator):
1846
2015
  title = self.escape(node.get('title', '%s')).replace(r'\%s', '%s')
1847
2016
  if r'\{name\}' in title or r'\{number\}' in title:
1848
2017
  # new style format (cf. "Fig.%{number}")
1849
- title = title.replace(r'\{name\}', '{name}').replace(r'\{number\}', '{number}')
1850
- text = escape_abbr(title).format(name=r'\nameref{%s}' % self.idescape(id),
1851
- number=r'\ref{%s}' % self.idescape(id))
2018
+ title = title.replace(r'\{name\}', '{name}').replace(
2019
+ r'\{number\}', '{number}'
2020
+ )
2021
+ text = escape_abbr(title).format(
2022
+ name=r'\nameref{%s}' % self.idescape(id),
2023
+ number=r'\ref{%s}' % self.idescape(id),
2024
+ )
1852
2025
  else:
1853
2026
  # old style format (cf. "Fig.%{number}")
1854
2027
  text = escape_abbr(title) % (r'\ref{%s}' % self.idescape(id))
1855
- hyperref = fr'\hyperref[{self.idescape(id)}]{{{text}}}'
2028
+ hyperref = rf'\hyperref[{self.idescape(id)}]{{{text}}}'
1856
2029
  self.body.append(hyperref)
1857
2030
 
1858
2031
  raise nodes.SkipNode
@@ -1926,16 +2099,19 @@ class LaTeXTranslator(SphinxTranslator):
1926
2099
  # adjust max width of citation labels not to break the layout
1927
2100
  longest_label = longest_label[:MAX_CITATION_LABEL_LENGTH]
1928
2101
 
1929
- self.body.append(CR + r'\begin{sphinxthebibliography}{%s}' %
1930
- self.encode(longest_label) + CR)
2102
+ self.body.append(
2103
+ CR + r'\begin{sphinxthebibliography}{%s}' % self.encode(longest_label) + CR
2104
+ )
1931
2105
 
1932
2106
  def depart_thebibliography(self, node: Element) -> None:
1933
2107
  self.body.append(r'\end{sphinxthebibliography}' + CR)
1934
2108
 
1935
2109
  def visit_citation(self, node: Element) -> None:
1936
2110
  label = cast(nodes.label, node[0])
1937
- self.body.append(fr'\bibitem[{self.encode(label.astext())}]'
1938
- fr'{{{node["docname"]}:{node["ids"][0]}}}')
2111
+ self.body.append(
2112
+ rf'\bibitem[{self.encode(label.astext())}]'
2113
+ rf'{{{node["docname"]}:{node["ids"][0]}}}'
2114
+ )
1939
2115
 
1940
2116
  def depart_citation(self, node: Element) -> None:
1941
2117
  pass
@@ -1944,7 +2120,7 @@ class LaTeXTranslator(SphinxTranslator):
1944
2120
  if self.in_title:
1945
2121
  pass
1946
2122
  else:
1947
- self.body.append(fr'\sphinxcite{{{node["docname"]}:{node["refname"]}}}')
2123
+ self.body.append(rf'\sphinxcite{{{node["docname"]}:{node["refname"]}}}')
1948
2124
  raise nodes.SkipNode
1949
2125
 
1950
2126
  def depart_citation_reference(self, node: Element) -> None:
@@ -1957,17 +2133,18 @@ class LaTeXTranslator(SphinxTranslator):
1957
2133
  elif 'kbd' in node['classes']:
1958
2134
  self.body.append(r'\sphinxkeyboard{\sphinxupquote{')
1959
2135
  return
1960
- lang = node.get("language", None)
2136
+ lang = node.get('language', None)
1961
2137
  if 'code' not in node['classes'] or not lang:
1962
2138
  self.body.append(r'\sphinxcode{\sphinxupquote{')
1963
2139
  return
1964
2140
 
1965
2141
  opts = self.config.highlight_options.get(lang, {})
1966
2142
  hlcode = self.highlighter.highlight_block(
1967
- node.astext(), lang, opts=opts, location=node, nowrap=True)
1968
- self.body.append(r'\sphinxcode{\sphinxupquote{%' + CR
1969
- + hlcode.rstrip() + '%' + CR
1970
- + '}}')
2143
+ node.astext(), lang, opts=opts, location=node, nowrap=True
2144
+ )
2145
+ self.body.append(
2146
+ r'\sphinxcode{\sphinxupquote{%' + CR + hlcode.rstrip() + '%' + CR + '}}'
2147
+ )
1971
2148
  raise nodes.SkipNode
1972
2149
 
1973
2150
  def depart_literal(self, node: Element) -> None:
@@ -2018,23 +2195,26 @@ class LaTeXTranslator(SphinxTranslator):
2018
2195
  opts = self.config.highlight_options.get(lang, {})
2019
2196
 
2020
2197
  hlcode = self.highlighter.highlight_block(
2021
- node.rawsource, lang, opts=opts, linenos=linenos,
2022
- location=node, **highlight_args,
2198
+ node.rawsource,
2199
+ lang,
2200
+ opts=opts,
2201
+ linenos=linenos,
2202
+ location=node,
2203
+ **highlight_args,
2023
2204
  )
2024
2205
  if self.in_footnote:
2025
2206
  self.body.append(CR + r'\sphinxSetupCodeBlockInFootnote')
2026
- hlcode = hlcode.replace(r'\begin{Verbatim}',
2027
- r'\begin{sphinxVerbatim}')
2207
+ hlcode = hlcode.replace(r'\begin{Verbatim}', r'\begin{sphinxVerbatim}')
2028
2208
  # if in table raise verbatim flag to avoid "tabulary" environment
2029
2209
  # and opt for sphinxVerbatimintable to handle caption & long lines
2030
2210
  elif self.table:
2031
2211
  self.table.has_problematic = True
2032
2212
  self.table.has_verbatim = True
2033
- hlcode = hlcode.replace(r'\begin{Verbatim}',
2034
- r'\begin{sphinxVerbatimintable}')
2213
+ hlcode = hlcode.replace(
2214
+ r'\begin{Verbatim}', r'\begin{sphinxVerbatimintable}'
2215
+ )
2035
2216
  else:
2036
- hlcode = hlcode.replace(r'\begin{Verbatim}',
2037
- r'\begin{sphinxVerbatim}')
2217
+ hlcode = hlcode.replace(r'\begin{Verbatim}', r'\begin{sphinxVerbatim}')
2038
2218
  # get consistent trailer
2039
2219
  hlcode = hlcode.rstrip()[:-14] # strip \end{Verbatim}
2040
2220
  if self.table and not self.in_footnote:
@@ -2053,6 +2233,7 @@ class LaTeXTranslator(SphinxTranslator):
2053
2233
  def depart_literal_block(self, node: Element) -> None:
2054
2234
  self.body.append(CR + r'\end{sphinxalltt}' + CR)
2055
2235
  self.in_parsed_literal -= 1
2236
+
2056
2237
  visit_doctest_block = visit_literal_block
2057
2238
  depart_doctest_block = depart_literal_block
2058
2239
 
@@ -2173,8 +2354,8 @@ class LaTeXTranslator(SphinxTranslator):
2173
2354
  self.body.append(r'\sphinxaccelerator{')
2174
2355
  self.context.append('}')
2175
2356
  elif classes and not self.in_title:
2176
- self.body.append(r'\DUrole{%s}{' % ','.join(classes))
2177
- self.context.append('}')
2357
+ self.body.append(r'\DUrole{' + r'}{\DUrole{'.join(classes) + '}{')
2358
+ self.context.append('}' * len(classes))
2178
2359
  else:
2179
2360
  self.context.append('')
2180
2361
 
@@ -2235,9 +2416,12 @@ class LaTeXTranslator(SphinxTranslator):
2235
2416
  # this must be checked against hyperref package exact dealings
2236
2417
  # mainly, %, #, {, } and \ need escaping via a \ escape
2237
2418
  # in \href, the tilde is allowed and must be represented literally
2238
- return self.encode(text).replace(r'\textasciitilde{}', '~').\
2239
- replace(r'\sphinxhyphen{}', '-').\
2240
- replace(r'\textquotesingle{}', "'")
2419
+ return (
2420
+ self.encode(text)
2421
+ .replace(r'\textasciitilde{}', '~')
2422
+ .replace(r'\sphinxhyphen{}', '-')
2423
+ .replace(r'\textquotesingle{}', "'")
2424
+ )
2241
2425
 
2242
2426
  def visit_Text(self, node: Text) -> None:
2243
2427
  text = self.encode(node.astext())
@@ -2278,8 +2462,10 @@ class LaTeXTranslator(SphinxTranslator):
2278
2462
  self.body.append(node.astext())
2279
2463
  else:
2280
2464
  from sphinx.util.math import wrap_displaymath
2281
- self.body.append(wrap_displaymath(node.astext(), label,
2282
- self.config.math_number_all))
2465
+
2466
+ self.body.append(
2467
+ wrap_displaymath(node.astext(), label, self.config.math_number_all)
2468
+ )
2283
2469
  raise nodes.SkipNode
2284
2470
 
2285
2471
  def visit_math_reference(self, node: Element) -> None:
@@ -2290,8 +2476,7 @@ class LaTeXTranslator(SphinxTranslator):
2290
2476
  ref = r'\ref{%s}' % label
2291
2477
  self.body.append(eqref_format.format(number=ref))
2292
2478
  except KeyError as exc:
2293
- logger.warning(__('Invalid math_eqref_format: %r'), exc,
2294
- location=node)
2479
+ logger.warning(__('Invalid math_eqref_format: %r'), exc, location=node)
2295
2480
  self.body.append(r'\eqref{%s}' % label)
2296
2481
  else:
2297
2482
  self.body.append(r'\eqref{%s}' % label)
@@ -2303,5 +2488,7 @@ class LaTeXTranslator(SphinxTranslator):
2303
2488
  # FIXME: Workaround to avoid circular import
2304
2489
  # refs: https://github.com/sphinx-doc/sphinx/issues/5433
2305
2490
  from sphinx.builders.latex.nodes import ( # NoQA: E402 # isort:skip
2306
- HYPERLINK_SUPPORT_NODES, captioned_literal_block, footnotetext,
2491
+ HYPERLINK_SUPPORT_NODES,
2492
+ captioned_literal_block,
2493
+ footnotetext,
2307
2494
  )