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
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import concurrent.futures
6
- import functools
7
6
  import posixpath
8
7
  import time
9
8
  from operator import itemgetter
@@ -20,7 +19,8 @@ from sphinx.util.inventory import InventoryFile
20
19
 
21
20
  if TYPE_CHECKING:
22
21
  from pathlib import Path
23
- from typing import IO
22
+
23
+ from urllib3.response import HTTPResponse
24
24
 
25
25
  from sphinx.application import Sphinx
26
26
  from sphinx.config import Config
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
31
31
  InventoryName,
32
32
  InventoryURI,
33
33
  )
34
- from sphinx.util.typing import Inventory
34
+ from sphinx.util.typing import Inventory, _ReadableStream
35
35
 
36
36
 
37
37
  def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
@@ -89,8 +89,10 @@ def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
89
89
  # ensure target URIs are non-empty and unique
90
90
  if not uri or not isinstance(uri, str):
91
91
  errors += 1
92
- msg = __('Invalid target URI value `%r` in intersphinx_mapping[%r][0]. '
93
- 'Target URIs must be unique non-empty strings.')
92
+ msg = __(
93
+ 'Invalid target URI value `%r` in intersphinx_mapping[%r][0]. '
94
+ 'Target URIs must be unique non-empty strings.'
95
+ )
94
96
  LOGGER.error(msg, uri, name)
95
97
  del config.intersphinx_mapping[name]
96
98
  continue
@@ -105,9 +107,12 @@ def validate_intersphinx_mapping(app: Sphinx, config: Config) -> None:
105
107
  continue
106
108
  seen[uri] = name
107
109
 
110
+ if not isinstance(inv, tuple | list):
111
+ inv = (inv,)
112
+
108
113
  # ensure inventory locations are None or non-empty
109
114
  targets: list[InventoryLocation] = []
110
- for target in (inv if isinstance(inv, (tuple | list)) else (inv,)):
115
+ for target in inv:
111
116
  if target is None or target and isinstance(target, str):
112
117
  targets.append(target)
113
118
  else:
@@ -143,9 +148,13 @@ def load_mappings(app: Sphinx) -> None:
143
148
  projects = []
144
149
  for name, (uri, locations) in intersphinx_mapping.values():
145
150
  try:
146
- project = _IntersphinxProject(name=name, target_uri=uri, locations=locations)
151
+ project = _IntersphinxProject(
152
+ name=name, target_uri=uri, locations=locations
153
+ )
147
154
  except ValueError as err:
148
- msg = __('An invalid intersphinx_mapping entry was added after normalisation.')
155
+ msg = __(
156
+ 'An invalid intersphinx_mapping entry was added after normalisation.'
157
+ )
149
158
  raise ConfigError(msg) from err
150
159
  else:
151
160
  projects.append(project)
@@ -201,14 +210,24 @@ def _fetch_inventory_group(
201
210
  config: Config,
202
211
  srcdir: Path,
203
212
  ) -> bool:
204
- cache_time = now - config.intersphinx_cache_limit * 86400
213
+ if config.intersphinx_cache_limit >= 0:
214
+ # Positive value: cache is expired if its timestamp is below
215
+ # `now - X days`.
216
+ cache_time = now - config.intersphinx_cache_limit * 86400
217
+ else:
218
+ # Negative value: cache is expired if its timestamp is below
219
+ # zero, which is impossible.
220
+ cache_time = 0
205
221
 
206
222
  updated = False
207
223
  failures = []
208
224
 
209
225
  for location in project.locations:
210
226
  # location is either None or a non-empty string
211
- inv = f'{project.target_uri}/{INVENTORY_FILENAME}' if location is None else location
227
+ if location is None:
228
+ inv = posixpath.join(project.target_uri, INVENTORY_FILENAME)
229
+ else:
230
+ inv = location
212
231
 
213
232
  # decide whether the inventory must be read: always read local
214
233
  # files; remote ones only if the cache time is expired
@@ -217,8 +236,11 @@ def _fetch_inventory_group(
217
236
  or project.target_uri not in cache
218
237
  or cache[project.target_uri][1] < cache_time
219
238
  ):
220
- LOGGER.info(__("loading intersphinx inventory '%s' from %s ..."),
221
- project.name, _get_safe_url(inv))
239
+ LOGGER.info(
240
+ __("loading intersphinx inventory '%s' from %s ..."),
241
+ project.name,
242
+ _get_safe_url(inv),
243
+ )
222
244
 
223
245
  try:
224
246
  invdata = _fetch_inventory(
@@ -239,14 +261,21 @@ def _fetch_inventory_group(
239
261
  if not failures:
240
262
  pass
241
263
  elif len(failures) < len(project.locations):
242
- LOGGER.info(__('encountered some issues with some of the inventories,'
243
- ' but they had working alternatives:'))
264
+ LOGGER.info(
265
+ __(
266
+ 'encountered some issues with some of the inventories,'
267
+ ' but they had working alternatives:'
268
+ )
269
+ )
244
270
  for fail in failures:
245
271
  LOGGER.info(*fail)
246
272
  else:
247
273
  issues = '\n'.join(f[0] % f[1:] for f in failures)
248
- LOGGER.warning(__('failed to reach any of the inventories '
249
- 'with the following issues:') + '\n' + issues)
274
+ LOGGER.warning(
275
+ __('failed to reach any of the inventories ' 'with the following issues:')
276
+ + '\n'
277
+ + issues
278
+ )
250
279
  return updated
251
280
 
252
281
 
@@ -261,7 +290,7 @@ def fetch_inventory(app: Sphinx, uri: InventoryURI, inv: str) -> Inventory:
261
290
 
262
291
 
263
292
  def _fetch_inventory(
264
- *, target_uri: InventoryURI, inv_location: str, config: Config, srcdir: Path,
293
+ *, target_uri: InventoryURI, inv_location: str, config: Config, srcdir: Path
265
294
  ) -> Inventory:
266
295
  """Fetch, parse and return an intersphinx inventory file."""
267
296
  # both *target_uri* (base URI of the links to generate)
@@ -272,12 +301,16 @@ def _fetch_inventory(
272
301
  target_uri = _strip_basic_auth(target_uri)
273
302
  try:
274
303
  if '://' in inv_location:
275
- f = _read_from_url(inv_location, config=config)
304
+ f: _ReadableStream[bytes] = _read_from_url(inv_location, config=config)
276
305
  else:
277
306
  f = open(path.join(srcdir, inv_location), 'rb') # NoQA: SIM115
278
307
  except Exception as err:
279
- err.args = ('intersphinx inventory %r not fetchable due to %s: %s',
280
- inv_location, err.__class__, str(err))
308
+ err.args = (
309
+ 'intersphinx inventory %r not fetchable due to %s: %s',
310
+ inv_location,
311
+ err.__class__,
312
+ str(err),
313
+ )
281
314
  raise
282
315
  try:
283
316
  if hasattr(f, 'url'):
@@ -289,17 +322,22 @@ def _fetch_inventory(
289
322
  if target_uri in {
290
323
  inv_location,
291
324
  path.dirname(inv_location),
292
- path.dirname(inv_location) + '/'
325
+ path.dirname(inv_location) + '/',
293
326
  }:
294
327
  target_uri = path.dirname(new_inv_location)
295
328
  with f:
296
329
  try:
297
330
  invdata = InventoryFile.load(f, target_uri, posixpath.join)
298
331
  except ValueError as exc:
299
- raise ValueError('unknown or unsupported inventory version: %r' % exc) from exc
332
+ msg = f'unknown or unsupported inventory version: {exc!r}'
333
+ raise ValueError(msg) from exc
300
334
  except Exception as err:
301
- err.args = ('intersphinx inventory %r not readable due to %s: %s',
302
- inv_location, err.__class__.__name__, str(err))
335
+ err.args = (
336
+ 'intersphinx inventory %r not readable due to %s: %s',
337
+ inv_location,
338
+ err.__class__.__name__,
339
+ str(err),
340
+ )
303
341
  raise
304
342
  else:
305
343
  return invdata
@@ -351,7 +389,7 @@ def _strip_basic_auth(url: str) -> str:
351
389
  return urlunsplit(frags)
352
390
 
353
391
 
354
- def _read_from_url(url: str, *, config: Config) -> IO:
392
+ def _read_from_url(url: str, *, config: Config) -> HTTPResponse:
355
393
  """Reads data from *url* with an HTTP *GET*.
356
394
 
357
395
  This function supports fetching from resources which use basic HTTP auth as
@@ -367,12 +405,19 @@ def _read_from_url(url: str, *, config: Config) -> IO:
367
405
  :return: data read from resource described by *url*
368
406
  :rtype: ``file``-like object
369
407
  """
370
- r = requests.get(url, stream=True, timeout=config.intersphinx_timeout,
371
- _user_agent=config.user_agent,
372
- _tls_info=(config.tls_verify, config.tls_cacerts))
408
+ r = requests.get(
409
+ url,
410
+ stream=True,
411
+ timeout=config.intersphinx_timeout,
412
+ _user_agent=config.user_agent,
413
+ _tls_info=(config.tls_verify, config.tls_cacerts),
414
+ )
373
415
  r.raise_for_status()
374
- r.raw.url = r.url
375
- # decode content-body based on the header.
376
- # ref: https://github.com/psf/requests/issues/2155
377
- r.raw.read = functools.partial(r.raw.read, decode_content=True)
416
+
417
+ # For inv_location / new_inv_location
418
+ r.raw.url = r.url # type: ignore[union-attr]
419
+
420
+ # Decode content-body based on the header.
421
+ # xref: https://github.com/psf/requests/issues/2155
422
+ r.raw.decode_content = True
378
423
  return r.raw
@@ -32,9 +32,13 @@ if TYPE_CHECKING:
32
32
  from sphinx.util.typing import Inventory, InventoryItem, RoleFunction
33
33
 
34
34
 
35
- def _create_element_from_result(domain: Domain, inv_name: InventoryName | None,
36
- data: InventoryItem,
37
- node: pending_xref, contnode: TextElement) -> nodes.reference:
35
+ def _create_element_from_result(
36
+ domain: Domain,
37
+ inv_name: InventoryName | None,
38
+ data: InventoryItem,
39
+ node: pending_xref,
40
+ contnode: TextElement,
41
+ ) -> nodes.reference:
38
42
  proj, version, uri, dispname = data
39
43
  if '://' not in uri and node.get('refdoc'):
40
44
  # get correct path in case of subdirectories
@@ -51,8 +55,11 @@ def _create_element_from_result(domain: Domain, inv_name: InventoryName | None,
51
55
  # use whatever title was given, but strip prefix
52
56
  title = contnode.astext()
53
57
  if inv_name is not None and title.startswith(inv_name + ':'):
54
- newnode.append(contnode.__class__(title[len(inv_name) + 1:],
55
- title[len(inv_name) + 1:]))
58
+ newnode.append(
59
+ contnode.__class__(
60
+ title[len(inv_name) + 1 :], title[len(inv_name) + 1 :]
61
+ )
62
+ )
56
63
  else:
57
64
  newnode.append(contnode)
58
65
  else:
@@ -62,10 +69,14 @@ def _create_element_from_result(domain: Domain, inv_name: InventoryName | None,
62
69
 
63
70
 
64
71
  def _resolve_reference_in_domain_by_target(
65
- inv_name: InventoryName | None, inventory: Inventory,
66
- domain: Domain, objtypes: Iterable[str],
67
- target: str,
68
- node: pending_xref, contnode: TextElement) -> nodes.reference | None:
72
+ inv_name: InventoryName | None,
73
+ inventory: Inventory,
74
+ domain: Domain,
75
+ objtypes: Iterable[str],
76
+ target: str,
77
+ node: pending_xref,
78
+ contnode: TextElement,
79
+ ) -> nodes.reference | None:
69
80
  for objtype in objtypes:
70
81
  if objtype not in inventory:
71
82
  # Continue if there's nothing of this kind in the inventory
@@ -79,13 +90,34 @@ def _resolve_reference_in_domain_by_target(
79
90
  # * 'term': https://github.com/sphinx-doc/sphinx/issues/9291
80
91
  # * 'label': https://github.com/sphinx-doc/sphinx/issues/12008
81
92
  target_lower = target.lower()
82
- insensitive_matches = list(filter(lambda k: k.lower() == target_lower,
83
- inventory[objtype].keys()))
93
+ insensitive_matches = list(
94
+ filter(lambda k: k.lower() == target_lower, inventory[objtype].keys())
95
+ )
84
96
  if len(insensitive_matches) > 1:
97
+ data_items = {
98
+ inventory[objtype][match] for match in insensitive_matches
99
+ }
85
100
  inv_descriptor = inv_name or 'main_inventory'
86
- LOGGER.warning(__("inventory '%s': multiple matches found for %s:%s"),
87
- inv_descriptor, objtype, target,
88
- type='intersphinx', subtype='external', location=node)
101
+ if len(data_items) == 1: # these are duplicates; relatively innocuous
102
+ LOGGER.debug(
103
+ __("inventory '%s': duplicate matches found for %s:%s"),
104
+ inv_descriptor,
105
+ objtype,
106
+ target,
107
+ type='intersphinx',
108
+ subtype='external',
109
+ location=node,
110
+ )
111
+ else:
112
+ LOGGER.warning(
113
+ __("inventory '%s': multiple matches found for %s:%s"),
114
+ inv_descriptor,
115
+ objtype,
116
+ target,
117
+ type='intersphinx',
118
+ subtype='external',
119
+ location=node,
120
+ )
89
121
  if insensitive_matches:
90
122
  data = inventory[objtype][insensitive_matches[0]]
91
123
  else:
@@ -100,12 +132,16 @@ def _resolve_reference_in_domain_by_target(
100
132
  return None
101
133
 
102
134
 
103
- def _resolve_reference_in_domain(env: BuildEnvironment,
104
- inv_name: InventoryName | None, inventory: Inventory,
105
- honor_disabled_refs: bool,
106
- domain: Domain, objtypes: Iterable[str],
107
- node: pending_xref, contnode: TextElement,
108
- ) -> nodes.reference | None:
135
+ def _resolve_reference_in_domain(
136
+ env: BuildEnvironment,
137
+ inv_name: InventoryName | None,
138
+ inventory: Inventory,
139
+ honor_disabled_refs: bool,
140
+ domain: Domain,
141
+ objtypes: Iterable[str],
142
+ node: pending_xref,
143
+ contnode: TextElement,
144
+ ) -> nodes.reference | None:
109
145
  obj_types: dict[str, None] = {}.fromkeys(objtypes)
110
146
 
111
147
  # we adjust the object types for backwards compatibility
@@ -123,15 +159,16 @@ def _resolve_reference_in_domain(env: BuildEnvironment,
123
159
  # now that the objtypes list is complete we can remove the disabled ones
124
160
  if honor_disabled_refs:
125
161
  disabled = set(env.config.intersphinx_disabled_reftypes)
126
- obj_types = {obj_type: None
127
- for obj_type in obj_types
128
- if obj_type not in disabled}
162
+ obj_types = {
163
+ obj_type: None for obj_type in obj_types if obj_type not in disabled
164
+ }
129
165
 
130
166
  objtypes = [*obj_types.keys()]
131
167
 
132
168
  # without qualification
133
- res = _resolve_reference_in_domain_by_target(inv_name, inventory, domain, objtypes,
134
- node['reftarget'], node, contnode)
169
+ res = _resolve_reference_in_domain_by_target(
170
+ inv_name, inventory, domain, objtypes, node['reftarget'], node, contnode
171
+ )
135
172
  if res is not None:
136
173
  return res
137
174
 
@@ -139,14 +176,19 @@ def _resolve_reference_in_domain(env: BuildEnvironment,
139
176
  full_qualified_name = domain.get_full_qualified_name(node)
140
177
  if full_qualified_name is None:
141
178
  return None
142
- return _resolve_reference_in_domain_by_target(inv_name, inventory, domain, objtypes,
143
- full_qualified_name, node, contnode)
144
-
145
-
146
- def _resolve_reference(env: BuildEnvironment,
147
- inv_name: InventoryName | None, inventory: Inventory,
148
- honor_disabled_refs: bool,
149
- node: pending_xref, contnode: TextElement) -> nodes.reference | None:
179
+ return _resolve_reference_in_domain_by_target(
180
+ inv_name, inventory, domain, objtypes, full_qualified_name, node, contnode
181
+ )
182
+
183
+
184
+ def _resolve_reference(
185
+ env: BuildEnvironment,
186
+ inv_name: InventoryName | None,
187
+ inventory: Inventory,
188
+ honor_disabled_refs: bool,
189
+ node: pending_xref,
190
+ contnode: TextElement,
191
+ ) -> nodes.reference | None:
150
192
  # disabling should only be done if no inventory is given
151
193
  honor_disabled_refs = honor_disabled_refs and inv_name is None
152
194
  intersphinx_disabled_reftypes = env.config.intersphinx_disabled_reftypes
@@ -156,14 +198,23 @@ def _resolve_reference(env: BuildEnvironment,
156
198
 
157
199
  typ = node['reftype']
158
200
  if typ == 'any':
159
- for domain_name, domain in env.domains.items():
160
- if honor_disabled_refs and f'{domain_name}:*' in intersphinx_disabled_reftypes:
201
+ for domain in env.domains.sorted():
202
+ if (
203
+ honor_disabled_refs
204
+ and f'{domain.name}:*' in intersphinx_disabled_reftypes
205
+ ):
161
206
  continue
162
207
  objtypes: Iterable[str] = domain.object_types.keys()
163
- res = _resolve_reference_in_domain(env, inv_name, inventory,
164
- honor_disabled_refs,
165
- domain, objtypes,
166
- node, contnode)
208
+ res = _resolve_reference_in_domain(
209
+ env,
210
+ inv_name,
211
+ inventory,
212
+ honor_disabled_refs,
213
+ domain,
214
+ objtypes,
215
+ node,
216
+ contnode,
217
+ )
167
218
  if res is not None:
168
219
  return res
169
220
  return None
@@ -178,20 +229,28 @@ def _resolve_reference(env: BuildEnvironment,
178
229
  objtypes = domain.objtypes_for_role(typ) or ()
179
230
  if not objtypes:
180
231
  return None
181
- return _resolve_reference_in_domain(env, inv_name, inventory,
182
- honor_disabled_refs,
183
- domain, objtypes,
184
- node, contnode)
232
+ return _resolve_reference_in_domain(
233
+ env,
234
+ inv_name,
235
+ inventory,
236
+ honor_disabled_refs,
237
+ domain,
238
+ objtypes,
239
+ node,
240
+ contnode,
241
+ )
185
242
 
186
243
 
187
244
  def inventory_exists(env: BuildEnvironment, inv_name: InventoryName) -> bool:
188
245
  return inv_name in InventoryAdapter(env).named_inventory
189
246
 
190
247
 
191
- def resolve_reference_in_inventory(env: BuildEnvironment,
192
- inv_name: InventoryName,
193
- node: pending_xref, contnode: TextElement,
194
- ) -> nodes.reference | None:
248
+ def resolve_reference_in_inventory(
249
+ env: BuildEnvironment,
250
+ inv_name: InventoryName,
251
+ node: pending_xref,
252
+ contnode: TextElement,
253
+ ) -> nodes.reference | None:
195
254
  """Attempt to resolve a missing reference via intersphinx references.
196
255
 
197
256
  Resolution is tried in the given inventory with the target as is.
@@ -199,26 +258,39 @@ def resolve_reference_in_inventory(env: BuildEnvironment,
199
258
  Requires ``inventory_exists(env, inv_name)``.
200
259
  """
201
260
  assert inventory_exists(env, inv_name)
202
- return _resolve_reference(env, inv_name, InventoryAdapter(env).named_inventory[inv_name],
203
- False, node, contnode)
204
-
205
-
206
- def resolve_reference_any_inventory(env: BuildEnvironment,
207
- honor_disabled_refs: bool,
208
- node: pending_xref, contnode: TextElement,
209
- ) -> nodes.reference | None:
261
+ return _resolve_reference(
262
+ env,
263
+ inv_name,
264
+ InventoryAdapter(env).named_inventory[inv_name],
265
+ False,
266
+ node,
267
+ contnode,
268
+ )
269
+
270
+
271
+ def resolve_reference_any_inventory(
272
+ env: BuildEnvironment,
273
+ honor_disabled_refs: bool,
274
+ node: pending_xref,
275
+ contnode: TextElement,
276
+ ) -> nodes.reference | None:
210
277
  """Attempt to resolve a missing reference via intersphinx references.
211
278
 
212
279
  Resolution is tried with the target as is in any inventory.
213
280
  """
214
- return _resolve_reference(env, None, InventoryAdapter(env).main_inventory,
215
- honor_disabled_refs,
216
- node, contnode)
217
-
218
-
219
- def resolve_reference_detect_inventory(env: BuildEnvironment,
220
- node: pending_xref, contnode: TextElement,
221
- ) -> nodes.reference | None:
281
+ return _resolve_reference(
282
+ env,
283
+ None,
284
+ InventoryAdapter(env).main_inventory,
285
+ honor_disabled_refs,
286
+ node,
287
+ contnode,
288
+ )
289
+
290
+
291
+ def resolve_reference_detect_inventory(
292
+ env: BuildEnvironment, node: pending_xref, contnode: TextElement
293
+ ) -> nodes.reference | None:
222
294
  """Attempt to resolve a missing reference via intersphinx references.
223
295
 
224
296
  Resolution is tried first with the target as is in any inventory.
@@ -244,8 +316,9 @@ def resolve_reference_detect_inventory(env: BuildEnvironment,
244
316
  return res_inv
245
317
 
246
318
 
247
- def missing_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref,
248
- contnode: TextElement) -> nodes.reference | None:
319
+ def missing_reference(
320
+ app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: TextElement
321
+ ) -> nodes.reference | None:
249
322
  """Attempt to resolve a missing reference via intersphinx references."""
250
323
  return resolve_reference_detect_inventory(env, node, contnode)
251
324
 
@@ -257,7 +330,11 @@ class IntersphinxDispatcher(CustomReSTDispatcher):
257
330
  """
258
331
 
259
332
  def role(
260
- self, role_name: str, language_module: ModuleType, lineno: int, reporter: Reporter,
333
+ self,
334
+ role_name: str,
335
+ language_module: ModuleType,
336
+ lineno: int,
337
+ reporter: Reporter,
261
338
  ) -> tuple[RoleFunction, list[system_message]]:
262
339
  if len(role_name) > 9 and role_name.startswith(('external:', 'external+')):
263
340
  return IntersphinxRole(role_name), []
@@ -296,16 +373,17 @@ class IntersphinxRole(SphinxRole):
296
373
 
297
374
  if domain_name is not None:
298
375
  # the user specified a domain, so we only check that
299
- if (domain := self.env.domains.get(domain_name)) is None:
376
+ if domain_name not in self.env.domains:
300
377
  self._emit_warning(
301
378
  __('domain for external cross-reference not found: %r'), domain_name
302
379
  )
303
380
  return [], []
304
- if (role_func := domain.roles.get(role_name)) is None:
381
+ domain = self.env.domains[domain_name]
382
+ role_func = domain.roles.get(role_name)
383
+ if role_func is None:
305
384
  msg = 'role for external cross-reference not found in domain %r: %r'
306
- if (
307
- object_types := domain.object_types.get(role_name)
308
- ) is not None and object_types.roles:
385
+ object_types = domain.object_types.get(role_name)
386
+ if object_types is not None and object_types.roles:
309
387
  self._emit_warning(
310
388
  __(f'{msg} (perhaps you meant one of: %s)'),
311
389
  domain_name,
@@ -323,7 +401,7 @@ class IntersphinxRole(SphinxRole):
323
401
  if default_domain := self.env.temp_data.get('default_domain'):
324
402
  domains.append(default_domain)
325
403
  if (
326
- std_domain := self.env.domains.get('std')
404
+ std_domain := self.env.domains.standard_domain
327
405
  ) is not None and std_domain not in domains:
328
406
  domains.append(std_domain)
329
407
 
@@ -454,7 +532,9 @@ class IntersphinxRole(SphinxRole):
454
532
  except ExtensionError:
455
533
  return False
456
534
 
457
- def invoke_role(self, role: tuple[str, str]) -> tuple[list[Node], list[system_message]]:
535
+ def invoke_role(
536
+ self, role: tuple[str, str]
537
+ ) -> tuple[list[Node], list[system_message]]:
458
538
  """Invoke the role described by a ``(domain, role name)`` pair."""
459
539
  _deprecation_warning(
460
540
  __name__, f'{self.__class__.__name__}.invoke_role', '', remove=(9, 0)
@@ -464,8 +544,15 @@ class IntersphinxRole(SphinxRole):
464
544
  role_func = domain.role(role[1])
465
545
  assert role_func is not None
466
546
 
467
- return role_func(':'.join(role), self.rawtext, self.text, self.lineno,
468
- self.inliner, self.options, self.content)
547
+ return role_func(
548
+ ':'.join(role),
549
+ self.rawtext,
550
+ self.text,
551
+ self.lineno,
552
+ self.inliner,
553
+ self.options,
554
+ self.content,
555
+ )
469
556
  else:
470
557
  return [], []
471
558
 
@@ -486,13 +573,20 @@ class IntersphinxRoleResolver(ReferencesResolver):
486
573
  inv_name = node['inventory']
487
574
  if inv_name is not None:
488
575
  assert inventory_exists(self.env, inv_name)
489
- newnode = resolve_reference_in_inventory(self.env, inv_name, node, contnode)
576
+ newnode = resolve_reference_in_inventory(
577
+ self.env, inv_name, node, contnode
578
+ )
490
579
  else:
491
- newnode = resolve_reference_any_inventory(self.env, False, node, contnode)
580
+ newnode = resolve_reference_any_inventory(
581
+ self.env, False, node, contnode
582
+ )
492
583
  if newnode is None:
493
584
  typ = node['reftype']
494
- msg = (__('external %s:%s reference target not found: %s') %
495
- (node['refdomain'], typ, node['reftarget']))
585
+ msg = __('external %s:%s reference target not found: %s') % (
586
+ node['refdomain'],
587
+ typ,
588
+ node['reftarget'],
589
+ )
496
590
  LOGGER.warning(msg, location=node, type='ref', subtype=typ)
497
591
  node.replace_self(contnode)
498
592
  else:
@@ -54,7 +54,7 @@ class _IntersphinxProject:
54
54
  'locations': 'A tuple of local or remote targets containing '
55
55
  'the inventory data to fetch. '
56
56
  'None indicates the default inventory file name.',
57
- }
57
+ } # fmt: skip
58
58
 
59
59
  def __init__(
60
60
  self,
@@ -83,10 +83,12 @@ class _IntersphinxProject:
83
83
  object.__setattr__(self, 'locations', tuple(locations))
84
84
 
85
85
  def __repr__(self) -> str:
86
- return (f'{self.__class__.__name__}('
87
- f'name={self.name!r}, '
88
- f'target_uri={self.target_uri!r}, '
89
- f'locations={self.locations!r})')
86
+ return (
87
+ f'{self.__class__.__name__}('
88
+ f'name={self.name!r}, '
89
+ f'target_uri={self.target_uri!r}, '
90
+ f'locations={self.locations!r})'
91
+ )
90
92
 
91
93
  def __eq__(self, other: object) -> bool:
92
94
  if not isinstance(other, _IntersphinxProject):
sphinx/ext/linkcode.py CHANGED
@@ -31,6 +31,12 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
31
31
  raise LinkcodeError(msg)
32
32
  assert resolve_target is not None # for mypy
33
33
 
34
+ # By default, the linkcode extension will only inject references
35
+ # for an ``html`` builder. If a builder wishes to support managing
36
+ # references generated by linkcode as well, it can define the
37
+ # ``supported_linkcode`` attribute.
38
+ node_only_expr = getattr(app.builder, 'supported_linkcode', 'html')
39
+
34
40
  domain_keys = {
35
41
  'py': ['module', 'fullname'],
36
42
  'c': ['names'],
@@ -67,7 +73,7 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
67
73
  uris.add(uri)
68
74
 
69
75
  inline = nodes.inline('', _('[source]'), classes=['viewcode-link'])
70
- onlynode = addnodes.only(expr='html')
76
+ onlynode = addnodes.only(expr=node_only_expr)
71
77
  onlynode += nodes.reference('', '', inline, internal=False, refuri=uri)
72
78
  signode += onlynode
73
79