Sphinx 8.0.2__py3-none-any.whl → 8.1.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (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 +202 -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 +136 -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 +115 -50
  311. sphinx/texinputs/sphinxlatexadmonitions.sty +56 -38
  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.1.dist-info/LICENSE.rst +31 -0
  419. {sphinx-8.0.2.dist-info → sphinx-8.1.1.dist-info}/METADATA +13 -11
  420. sphinx-8.1.1.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.1.dist-info}/WHEEL +0 -0
  424. {sphinx-8.0.2.dist-info → sphinx-8.1.1.dist-info}/entry_points.txt +0 -0
sphinx/util/images.py CHANGED
@@ -13,6 +13,7 @@ if TYPE_CHECKING:
13
13
 
14
14
  try:
15
15
  from PIL import Image
16
+
16
17
  PILLOW_AVAILABLE = True
17
18
  except ImportError:
18
19
  PILLOW_AVAILABLE = False
@@ -54,13 +55,13 @@ def get_image_size(filename: str) -> tuple[int, int] | None:
54
55
 
55
56
 
56
57
  @overload
57
- def guess_mimetype(filename: PathLike[str] | str, default: str) -> str:
58
- ...
58
+ def guess_mimetype(filename: PathLike[str] | str, default: str) -> str: ... # NoQA: E704
59
59
 
60
60
 
61
61
  @overload
62
- def guess_mimetype(filename: PathLike[str] | str, default: None = None) -> str | None:
63
- ...
62
+ def guess_mimetype( # NoQA: E704
63
+ filename: PathLike[str] | str, default: None = None
64
+ ) -> str | None: ...
64
65
 
65
66
 
66
67
  def guess_mimetype(
@@ -121,12 +122,12 @@ def _image_type_from_file(filename: PathLike[str] | str) -> str:
121
122
 
122
123
  # JPEG data
123
124
  # https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format#File_format_structure
124
- if header.startswith(b'\xFF\xD8'):
125
+ if header.startswith(b'\xff\xd8'):
125
126
  return 'jpeg'
126
127
 
127
128
  # Portable Network Graphics
128
129
  # https://en.wikipedia.org/wiki/PNG#File_header
129
- if header.startswith(b'\x89PNG\r\n\x1A\n'):
130
+ if header.startswith(b'\x89PNG\r\n\x1a\n'):
130
131
  return 'png'
131
132
 
132
133
  # Scalable Vector Graphics
sphinx/util/inspect.py CHANGED
@@ -52,11 +52,7 @@ if TYPE_CHECKING:
52
52
  | types.MethodDescriptorType
53
53
  | types.ClassMethodDescriptorType
54
54
  )
55
- _SignatureType: TypeAlias = (
56
- Callable[..., Any]
57
- | staticmethod
58
- | classmethod
59
- )
55
+ _SignatureType: TypeAlias = Callable[..., Any] | staticmethod | classmethod
60
56
 
61
57
  logger = logging.getLogger(__name__)
62
58
 
@@ -266,7 +262,8 @@ def isstaticmethod(
266
262
  def isdescriptor(x: Any) -> TypeIs[_SupportsGet | _SupportsSet | _SupportsDelete]:
267
263
  """Check if the object is a :external+python:term:`descriptor`."""
268
264
  return any(
269
- callable(safe_getattr(x, item, None)) for item in ('__get__', '__set__', '__delete__')
265
+ callable(safe_getattr(x, item, None))
266
+ for item in ('__get__', '__set__', '__delete__')
270
267
  )
271
268
 
272
269
 
@@ -392,6 +389,10 @@ def isgenericalias(obj: Any) -> TypeIs[types.GenericAlias]:
392
389
 
393
390
  def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any:
394
391
  """A getattr() that turns all exceptions into AttributeErrors."""
392
+ if len(defargs) > 1:
393
+ msg = f'safe_getattr expected at most 3 arguments, got {len(defargs)}'
394
+ raise TypeError(msg)
395
+
395
396
  try:
396
397
  return getattr(obj, name, *defargs)
397
398
  except Exception as exc:
@@ -429,7 +430,10 @@ def object_description(obj: Any, *, _seen: frozenset[int] = frozenset()) -> str:
429
430
  sorted_keys = sorted(obj, key=lambda k: object_description(k, _seen=seen))
430
431
 
431
432
  items = (
432
- (object_description(key, _seen=seen), object_description(obj[key], _seen=seen))
433
+ (
434
+ object_description(key, _seen=seen),
435
+ object_description(obj[key], _seen=seen),
436
+ )
433
437
  for key in sorted_keys
434
438
  )
435
439
  return '{%s}' % ', '.join(f'{key}: {value}' for (key, value) in items)
@@ -442,7 +446,9 @@ def object_description(obj: Any, *, _seen: frozenset[int] = frozenset()) -> str:
442
446
  except TypeError:
443
447
  # Cannot sort set values, fall back to using descriptions as a sort key
444
448
  sorted_values = sorted(obj, key=lambda x: object_description(x, _seen=seen))
445
- return '{%s}' % ', '.join(object_description(x, _seen=seen) for x in sorted_values)
449
+ return '{%s}' % ', '.join(
450
+ object_description(x, _seen=seen) for x in sorted_values
451
+ )
446
452
  elif isinstance(obj, frozenset):
447
453
  if id(obj) in seen:
448
454
  return 'frozenset(...)'
@@ -760,7 +766,10 @@ def stringify_signature(
760
766
  args = []
761
767
  last_kind = None
762
768
  for param in sig.parameters.values():
763
- if param.kind != Parameter.POSITIONAL_ONLY and last_kind == Parameter.POSITIONAL_ONLY:
769
+ if (
770
+ param.kind != Parameter.POSITIONAL_ONLY
771
+ and last_kind == Parameter.POSITIONAL_ONLY
772
+ ):
764
773
  # PEP-570: Separator for Positional Only Parameter: /
765
774
  args.append('/')
766
775
  if param.kind == Parameter.KEYWORD_ONLY and last_kind in (
@@ -797,7 +806,11 @@ def stringify_signature(
797
806
  args.append('/')
798
807
 
799
808
  concatenated_args = ', '.join(args)
800
- if sig.return_annotation is EMPTY or not show_annotation or not show_return_annotation:
809
+ if (
810
+ sig.return_annotation is EMPTY
811
+ or not show_annotation
812
+ or not show_return_annotation
813
+ ):
801
814
  return f'({concatenated_args})'
802
815
  else:
803
816
  retann = stringify_annotation(sig.return_annotation, mode) # type: ignore[arg-type]
@@ -842,11 +855,15 @@ def signature_from_ast(node: ast.FunctionDef, code: str = '') -> Signature:
842
855
 
843
856
  # normal arguments
844
857
  for arg, defexpr in zip(args.args, defaults[pos_only_offset:], strict=False):
845
- params.append(_define(Parameter.POSITIONAL_OR_KEYWORD, arg, code, defexpr=defexpr))
858
+ params.append(
859
+ _define(Parameter.POSITIONAL_OR_KEYWORD, arg, code, defexpr=defexpr)
860
+ )
846
861
 
847
862
  # variadic positional argument (no possible default expression)
848
863
  if args.vararg:
849
- params.append(_define(Parameter.VAR_POSITIONAL, args.vararg, code, defexpr=None))
864
+ params.append(
865
+ _define(Parameter.VAR_POSITIONAL, args.vararg, code, defexpr=None)
866
+ )
850
867
 
851
868
  # keyword-only arguments
852
869
  for arg, defexpr in zip(args.kwonlyargs, args.kw_defaults, strict=False):
sphinx/util/inventory.py CHANGED
@@ -1,10 +1,11 @@
1
1
  """Inventory utility functions for Sphinx."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import os
5
6
  import re
6
7
  import zlib
7
- from typing import IO, TYPE_CHECKING
8
+ from typing import TYPE_CHECKING
8
9
 
9
10
  from sphinx.locale import __
10
11
  from sphinx.util import logging
@@ -17,7 +18,7 @@ if TYPE_CHECKING:
17
18
 
18
19
  from sphinx.builders import Builder
19
20
  from sphinx.environment import BuildEnvironment
20
- from sphinx.util.typing import Inventory, InventoryItem
21
+ from sphinx.util.typing import Inventory, InventoryItem, _ReadableStream
21
22
 
22
23
 
23
24
  class InventoryFileReader:
@@ -26,7 +27,7 @@ class InventoryFileReader:
26
27
  This reader supports mixture of texts and compressed texts.
27
28
  """
28
29
 
29
- def __init__(self, stream: IO[bytes]) -> None:
30
+ def __init__(self, stream: _ReadableStream[bytes]) -> None:
30
31
  self.stream = stream
31
32
  self.buffer = b''
32
33
  self.eof = False
@@ -41,7 +42,7 @@ class InventoryFileReader:
41
42
  pos = self.buffer.find(b'\n')
42
43
  if pos != -1:
43
44
  line = self.buffer[:pos].decode()
44
- self.buffer = self.buffer[pos + 1:]
45
+ self.buffer = self.buffer[pos + 1 :]
45
46
  elif self.eof:
46
47
  line = self.buffer.decode()
47
48
  self.buffer = b''
@@ -72,7 +73,7 @@ class InventoryFileReader:
72
73
  pos = buf.find(b'\n')
73
74
  while pos != -1:
74
75
  yield buf[:pos].decode()
75
- buf = buf[pos + 1:]
76
+ buf = buf[pos + 1 :]
76
77
  pos = buf.find(b'\n')
77
78
 
78
79
 
@@ -80,7 +81,7 @@ class InventoryFile:
80
81
  @classmethod
81
82
  def load(
82
83
  cls: type[InventoryFile],
83
- stream: IO[bytes],
84
+ stream: _ReadableStream[bytes],
84
85
  uri: str,
85
86
  joinfunc: Callable[[str, str], str],
86
87
  ) -> Inventory:
@@ -135,8 +136,11 @@ class InventoryFile:
135
136
 
136
137
  for line in stream.read_compressed_lines():
137
138
  # be careful to handle names with embedded spaces correctly
138
- m = re.match(r'(.+?)\s+(\S+)\s+(-?\d+)\s+?(\S*)\s+(.*)',
139
- line.rstrip(), flags=re.VERBOSE)
139
+ m = re.match(
140
+ r'(.+?)\s+(\S+)\s+(-?\d+)\s+?(\S*)\s+(.*)',
141
+ line.rstrip(),
142
+ flags=re.VERBOSE,
143
+ )
140
144
  if not m:
141
145
  continue
142
146
  name, type, prio, location, dispname = m.groups()
@@ -155,15 +159,20 @@ class InventoryFile:
155
159
  # Some types require case insensitive matches:
156
160
  # * 'term': https://github.com/sphinx-doc/sphinx/issues/9291
157
161
  # * 'label': https://github.com/sphinx-doc/sphinx/issues/12008
158
- definition = f"{type}:{name}"
162
+ definition = f'{type}:{name}'
159
163
  content = prio, location, dispname
160
164
  lowercase_definition = definition.lower()
161
165
  if lowercase_definition in potential_ambiguities:
162
166
  if potential_ambiguities[lowercase_definition] != content:
163
167
  actual_ambiguities.add(definition)
164
168
  else:
165
- logger.debug(__("inventory <%s> contains duplicate definitions of %s"),
166
- uri, definition, type='intersphinx', subtype='external')
169
+ logger.debug(
170
+ __('inventory <%s> contains duplicate definitions of %s'),
171
+ uri,
172
+ definition,
173
+ type='intersphinx',
174
+ subtype='external',
175
+ )
167
176
  else:
168
177
  potential_ambiguities[lowercase_definition] = content
169
178
  if location.endswith('$'):
@@ -172,40 +181,49 @@ class InventoryFile:
172
181
  inv_item: InventoryItem = projname, version, location, dispname
173
182
  invdata.setdefault(type, {})[name] = inv_item
174
183
  for ambiguity in actual_ambiguities:
175
- logger.info(__("inventory <%s> contains multiple definitions for %s"),
176
- uri, ambiguity, type='intersphinx', subtype='external')
184
+ logger.info(
185
+ __('inventory <%s> contains multiple definitions for %s'),
186
+ uri,
187
+ ambiguity,
188
+ type='intersphinx',
189
+ subtype='external',
190
+ )
177
191
  return invdata
178
192
 
179
193
  @classmethod
180
194
  def dump(
181
- cls: type[InventoryFile], filename: str, env: BuildEnvironment, builder: Builder,
195
+ cls: type[InventoryFile],
196
+ filename: str,
197
+ env: BuildEnvironment,
198
+ builder: Builder,
182
199
  ) -> None:
183
200
  def escape(string: str) -> str:
184
- return re.sub("\\s+", " ", string)
201
+ return re.sub('\\s+', ' ', string)
185
202
 
186
203
  with open(os.path.join(filename), 'wb') as f:
187
204
  # header
188
- f.write(('# Sphinx inventory version 2\n'
189
- '# Project: %s\n'
190
- '# Version: %s\n'
191
- '# The remainder of this file is compressed using zlib.\n' %
192
- (escape(env.config.project),
193
- escape(env.config.version))).encode())
205
+ f.write(
206
+ (
207
+ '# Sphinx inventory version 2\n'
208
+ f'# Project: {escape(env.config.project)}\n'
209
+ f'# Version: {escape(env.config.version)}\n'
210
+ '# The remainder of this file is compressed using zlib.\n'
211
+ ).encode()
212
+ )
194
213
 
195
214
  # body
196
215
  compressor = zlib.compressobj(9)
197
- for domainname, domain in sorted(env.domains.items()):
198
- for name, dispname, typ, docname, anchor, prio in \
199
- sorted(domain.get_objects()):
200
- if anchor.endswith(name):
216
+ for domain in env.domains.sorted():
217
+ sorted_objects = sorted(domain.get_objects())
218
+ for fullname, dispname, type, docname, anchor, prio in sorted_objects:
219
+ if anchor.endswith(fullname):
201
220
  # this can shorten the inventory by as much as 25%
202
- anchor = anchor[:-len(name)] + '$'
221
+ anchor = anchor.removesuffix(fullname) + '$'
203
222
  uri = builder.get_target_uri(docname)
204
223
  if anchor:
205
224
  uri += '#' + anchor
206
- if dispname == name:
225
+ if dispname == fullname:
207
226
  dispname = '-'
208
- entry = ('%s %s:%s %s %s %s\n' %
209
- (name, domainname, typ, prio, uri, dispname))
227
+ entry = f'{fullname} {domain.name}:{type} {prio} {uri} {dispname}\n'
210
228
  f.write(compressor.compress(entry.encode()))
211
229
  f.write(compressor.flush())
sphinx/util/logging.py CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import logging
6
6
  import logging.handlers
7
7
  from collections import defaultdict
8
- from contextlib import contextmanager
8
+ from contextlib import contextmanager, nullcontext
9
9
  from typing import IO, TYPE_CHECKING, Any
10
10
 
11
11
  from docutils import nodes
@@ -17,6 +17,7 @@ from sphinx.util.osutil import abspath
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from collections.abc import Iterator, Sequence, Set
20
+ from typing import NoReturn
20
21
 
21
22
  from docutils.nodes import Node
22
23
 
@@ -26,27 +27,36 @@ if TYPE_CHECKING:
26
27
  NAMESPACE = 'sphinx'
27
28
  VERBOSE = 15
28
29
 
29
- LEVEL_NAMES: defaultdict[str, int] = defaultdict(lambda: logging.WARNING, {
30
- 'CRITICAL': logging.CRITICAL,
31
- 'SEVERE': logging.CRITICAL,
32
- 'ERROR': logging.ERROR,
33
- 'WARNING': logging.WARNING,
34
- 'INFO': logging.INFO,
35
- 'VERBOSE': VERBOSE,
36
- 'DEBUG': logging.DEBUG,
37
- })
38
-
39
- VERBOSITY_MAP: defaultdict[int, int] = defaultdict(lambda: logging.NOTSET, {
40
- 0: logging.INFO,
41
- 1: VERBOSE,
42
- 2: logging.DEBUG,
43
- })
44
-
45
- COLOR_MAP: defaultdict[int, str] = defaultdict(lambda: 'blue', {
46
- logging.ERROR: 'darkred',
47
- logging.WARNING: 'red',
48
- logging.DEBUG: 'darkgray',
49
- })
30
+ LEVEL_NAMES: defaultdict[str, int] = defaultdict(
31
+ lambda: logging.WARNING,
32
+ {
33
+ 'CRITICAL': logging.CRITICAL,
34
+ 'SEVERE': logging.CRITICAL,
35
+ 'ERROR': logging.ERROR,
36
+ 'WARNING': logging.WARNING,
37
+ 'INFO': logging.INFO,
38
+ 'VERBOSE': VERBOSE,
39
+ 'DEBUG': logging.DEBUG,
40
+ },
41
+ )
42
+
43
+ VERBOSITY_MAP: defaultdict[int, int] = defaultdict(
44
+ lambda: logging.NOTSET,
45
+ {
46
+ 0: logging.INFO,
47
+ 1: VERBOSE,
48
+ 2: logging.DEBUG,
49
+ },
50
+ )
51
+
52
+ COLOR_MAP: defaultdict[int, str] = defaultdict(
53
+ lambda: 'blue',
54
+ {
55
+ logging.ERROR: 'darkred',
56
+ logging.WARNING: 'red',
57
+ logging.DEBUG: 'darkgray',
58
+ },
59
+ )
50
60
 
51
61
 
52
62
  def getLogger(name: str) -> SphinxLoggerAdapter:
@@ -125,7 +135,7 @@ class SphinxLoggerAdapter(logging.LoggerAdapter):
125
135
  KEYWORDS = ['type', 'subtype', 'location', 'nonl', 'color', 'once']
126
136
 
127
137
  def log( # type: ignore[override]
128
- self, level: int | str, msg: str, *args: Any, **kwargs: Any,
138
+ self, level: int | str, msg: str, *args: Any, **kwargs: Any
129
139
  ) -> None:
130
140
  if isinstance(level, int):
131
141
  super().log(level, msg, *args, **kwargs)
@@ -322,24 +332,7 @@ def pending_logging() -> Iterator[MemoryHandler]:
322
332
  memhandler.flushTo(logger)
323
333
 
324
334
 
325
- @contextmanager
326
- def skip_warningiserror(skip: bool = True) -> Iterator[None]:
327
- """Context manager to skip WarningIsErrorFilter temporarily."""
328
- logger = logging.getLogger(NAMESPACE)
329
-
330
- if skip is False:
331
- yield
332
- else:
333
- try:
334
- disabler = DisableWarningIsErrorFilter()
335
- for handler in logger.handlers:
336
- # use internal method; filters.insert() directly to install disabler
337
- # before WarningIsErrorFilter
338
- handler.filters.insert(0, disabler)
339
- yield
340
- finally:
341
- for handler in logger.handlers:
342
- handler.removeFilter(disabler)
335
+ skip_warningiserror = nullcontext # Deprecate in Sphinx 10
343
336
 
344
337
 
345
338
  @contextmanager
@@ -407,8 +400,23 @@ class InfoFilter(logging.Filter):
407
400
  return record.levelno < logging.WARNING
408
401
 
409
402
 
403
+ class _RaiseOnWarningFilter(logging.Filter):
404
+ """Raise exception if a warning is emitted."""
405
+
406
+ def filter(self, record: logging.LogRecord) -> NoReturn:
407
+ try:
408
+ message = record.msg % record.args
409
+ except (TypeError, ValueError):
410
+ message = record.msg # use record.msg itself
411
+ if location := getattr(record, 'location', ''):
412
+ message = f'{location}:{message}'
413
+ if record.exc_info is not None:
414
+ raise SphinxWarning(message) from record.exc_info[1]
415
+ raise SphinxWarning(message)
416
+
417
+
410
418
  def is_suppressed_warning(
411
- warning_type: str, sub_type: str, suppress_warnings: Set[str] | Sequence[str],
419
+ warning_type: str, sub_type: str, suppress_warnings: Set[str] | Sequence[str]
412
420
  ) -> bool:
413
421
  """Check whether the warning is suppressed or not."""
414
422
  if warning_type is None or len(suppress_warnings) == 0:
@@ -445,44 +453,6 @@ class WarningSuppressor(logging.Filter):
445
453
  return True
446
454
 
447
455
 
448
- class WarningIsErrorFilter(logging.Filter):
449
- """Raise exception if warning emitted."""
450
-
451
- def __init__(self, app: Sphinx) -> None:
452
- self.app = app
453
- super().__init__()
454
-
455
- def filter(self, record: logging.LogRecord) -> bool:
456
- if getattr(record, 'skip_warningsiserror', False):
457
- # disabled by DisableWarningIsErrorFilter
458
- return True
459
- elif self.app.warningiserror:
460
- location = getattr(record, 'location', '')
461
- try:
462
- message = record.msg % record.args
463
- except (TypeError, ValueError):
464
- message = record.msg # use record.msg itself
465
-
466
- if location:
467
- exc = SphinxWarning(location + ":" + str(message))
468
- else:
469
- exc = SphinxWarning(message)
470
- if record.exc_info is not None:
471
- raise exc from record.exc_info[1]
472
- else:
473
- raise exc
474
- else:
475
- return True
476
-
477
-
478
- class DisableWarningIsErrorFilter(logging.Filter):
479
- """Disable WarningIsErrorFilter if this filter installed."""
480
-
481
- def filter(self, record: logging.LogRecord) -> bool:
482
- record.skip_warningsiserror = True
483
- return True
484
-
485
-
486
456
  class MessagePrefixFilter(logging.Filter):
487
457
  """Prepend prefix to all log records."""
488
458
 
@@ -585,11 +555,11 @@ class WarningLogRecordTranslator(SphinxLogRecordTranslator):
585
555
  def get_node_location(node: Node) -> str | None:
586
556
  source, line = get_source_line(node)
587
557
  if source and line:
588
- return f"{abspath(source)}:{line}"
558
+ return f'{abspath(source)}:{line}'
589
559
  if source:
590
- return f"{abspath(source)}:"
560
+ return f'{abspath(source)}:'
591
561
  if line:
592
- return f"<unknown>:{line}"
562
+ return f'<unknown>:{line}'
593
563
  return None
594
564
 
595
565
 
@@ -619,7 +589,9 @@ class SafeEncodingWriter:
619
589
  except UnicodeEncodeError:
620
590
  # stream accept only str, not bytes. So, we encode and replace
621
591
  # non-encodable characters, then decode them.
622
- self.stream.write(data.encode(self.encoding, 'replace').decode(self.encoding))
592
+ self.stream.write(
593
+ data.encode(self.encoding, 'replace').decode(self.encoding)
594
+ )
623
595
 
624
596
  def flush(self) -> None:
625
597
  if hasattr(self.stream, 'flush'):
@@ -653,9 +625,10 @@ def setup(app: Sphinx, status: IO, warning: IO) -> None:
653
625
  info_handler.setFormatter(ColorizeFormatter())
654
626
 
655
627
  warning_handler = WarningStreamHandler(SafeEncodingWriter(warning))
628
+ if app._exception_on_warning:
629
+ warning_handler.addFilter(_RaiseOnWarningFilter())
656
630
  warning_handler.addFilter(WarningSuppressor(app))
657
631
  warning_handler.addFilter(WarningLogRecordTranslator(app))
658
- warning_handler.addFilter(WarningIsErrorFilter(app))
659
632
  warning_handler.addFilter(OnceFilter())
660
633
  warning_handler.setLevel(logging.WARNING)
661
634
  warning_handler.setFormatter(ColorizeFormatter())
sphinx/util/matching.py CHANGED
@@ -112,7 +112,7 @@ def patfilter(names: Iterable[str], pat: str) -> list[str]:
112
112
 
113
113
  def get_matching_files(
114
114
  dirname: str | os.PathLike[str],
115
- include_patterns: Iterable[str] = ("**",),
115
+ include_patterns: Iterable[str] = ('**',),
116
116
  exclude_patterns: Iterable[str] = (),
117
117
  ) -> Iterator[str]:
118
118
  """Get all file names in a directory, recursively.
@@ -132,8 +132,8 @@ def get_matching_files(
132
132
 
133
133
  for root, dirs, files in os.walk(dirname, followlinks=True):
134
134
  relative_root = os.path.relpath(root, dirname)
135
- if relative_root == ".":
136
- relative_root = "" # suppress dirname for files on the target dir
135
+ if relative_root == '.':
136
+ relative_root = '' # suppress dirname for files on the target dir
137
137
 
138
138
  # Filter files
139
139
  included_files = []
sphinx/util/math.py CHANGED
@@ -14,7 +14,7 @@ def get_node_equation_number(writer: HTML5Translator, node: nodes.math_block) ->
14
14
  if writer.builder.config.math_numfig and writer.builder.config.numfig:
15
15
  figtype = 'displaymath'
16
16
  if writer.builder.name == 'singlehtml':
17
- key = f"{writer.docnames[-1]}/{figtype}" # type: ignore[has-type]
17
+ key = f'{writer.docnames[-1]}/{figtype}' # type: ignore[has-type]
18
18
  else:
19
19
  key = figtype
20
20