Sphinx 7.3.7__py3-none-any.whl → 7.4.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 (357) hide show
  1. sphinx/__init__.py +5 -6
  2. sphinx/_cli/__init__.py +296 -0
  3. sphinx/_cli/util/__init__.py +0 -0
  4. sphinx/_cli/util/colour.py +103 -0
  5. sphinx/_cli/util/errors.py +165 -0
  6. sphinx/application.py +78 -43
  7. sphinx/builders/__init__.py +59 -15
  8. sphinx/builders/_epub_base.py +11 -5
  9. sphinx/builders/changes.py +2 -2
  10. sphinx/builders/epub3.py +2 -2
  11. sphinx/builders/gettext.py +10 -10
  12. sphinx/builders/html/__init__.py +56 -54
  13. sphinx/builders/latex/__init__.py +5 -5
  14. sphinx/builders/latex/constants.py +5 -0
  15. sphinx/builders/linkcheck.py +73 -38
  16. sphinx/builders/texinfo.py +1 -1
  17. sphinx/cmd/build.py +1 -1
  18. sphinx/cmd/quickstart.py +11 -11
  19. sphinx/config.py +57 -38
  20. sphinx/directives/__init__.py +7 -9
  21. sphinx/directives/code.py +12 -15
  22. sphinx/directives/other.py +12 -15
  23. sphinx/directives/patches.py +26 -0
  24. sphinx/domains/__init__.py +1 -1
  25. sphinx/domains/c/__init__.py +5 -5
  26. sphinx/domains/c/_ast.py +436 -12
  27. sphinx/domains/c/_symbol.py +89 -134
  28. sphinx/domains/changeset.py +3 -4
  29. sphinx/domains/cpp/__init__.py +5 -6
  30. sphinx/domains/cpp/_ast.py +822 -25
  31. sphinx/domains/cpp/_symbol.py +3 -0
  32. sphinx/domains/javascript.py +3 -6
  33. sphinx/domains/math.py +3 -2
  34. sphinx/domains/python/__init__.py +44 -6
  35. sphinx/domains/python/_object.py +7 -5
  36. sphinx/domains/rst.py +2 -2
  37. sphinx/domains/std/__init__.py +95 -14
  38. sphinx/environment/__init__.py +35 -15
  39. sphinx/environment/adapters/indexentries.py +71 -24
  40. sphinx/environment/adapters/toctree.py +1 -1
  41. sphinx/environment/collectors/__init__.py +18 -4
  42. sphinx/environment/collectors/asset.py +4 -4
  43. sphinx/environment/collectors/toctree.py +27 -14
  44. sphinx/events.py +7 -6
  45. sphinx/ext/apidoc.py +377 -170
  46. sphinx/ext/autodoc/__init__.py +13 -13
  47. sphinx/ext/autodoc/directive.py +10 -13
  48. sphinx/ext/autodoc/mock.py +10 -7
  49. sphinx/ext/autodoc/preserve_defaults.py +1 -1
  50. sphinx/ext/autodoc/typehints.py +2 -2
  51. sphinx/ext/autosummary/__init__.py +15 -9
  52. sphinx/ext/autosummary/generate.py +270 -154
  53. sphinx/ext/coverage.py +108 -18
  54. sphinx/ext/duration.py +10 -3
  55. sphinx/ext/extlinks.py +3 -2
  56. sphinx/ext/graphviz.py +3 -3
  57. sphinx/ext/ifconfig.py +1 -2
  58. sphinx/ext/imgconverter.py +1 -0
  59. sphinx/ext/imgmath.py +7 -6
  60. sphinx/ext/inheritance_diagram.py +3 -3
  61. sphinx/ext/intersphinx/__init__.py +81 -0
  62. sphinx/ext/intersphinx/__main__.py +10 -0
  63. sphinx/ext/intersphinx/_cli.py +44 -0
  64. sphinx/ext/intersphinx/_load.py +253 -0
  65. sphinx/ext/{intersphinx.py → intersphinx/_resolve.py} +17 -368
  66. sphinx/ext/intersphinx/_shared.py +53 -0
  67. sphinx/ext/mathjax.py +1 -1
  68. sphinx/ext/todo.py +2 -2
  69. sphinx/io.py +2 -6
  70. sphinx/locale/__init__.py +1 -5
  71. sphinx/locale/ar/LC_MESSAGES/sphinx.js +1 -1
  72. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  73. sphinx/locale/ar/LC_MESSAGES/sphinx.po +678 -471
  74. sphinx/locale/bg/LC_MESSAGES/sphinx.js +1 -1
  75. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  76. sphinx/locale/bg/LC_MESSAGES/sphinx.po +684 -476
  77. sphinx/locale/bn/LC_MESSAGES/sphinx.js +1 -1
  78. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  79. sphinx/locale/bn/LC_MESSAGES/sphinx.po +679 -472
  80. sphinx/locale/ca/LC_MESSAGES/sphinx.js +1 -1
  81. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  82. sphinx/locale/ca/LC_MESSAGES/sphinx.po +681 -474
  83. sphinx/locale/cak/LC_MESSAGES/sphinx.js +1 -1
  84. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  85. sphinx/locale/cak/LC_MESSAGES/sphinx.po +678 -471
  86. sphinx/locale/cs/LC_MESSAGES/sphinx.js +1 -1
  87. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  88. sphinx/locale/cs/LC_MESSAGES/sphinx.po +679 -472
  89. sphinx/locale/cy/LC_MESSAGES/sphinx.js +1 -1
  90. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  91. sphinx/locale/cy/LC_MESSAGES/sphinx.po +679 -472
  92. sphinx/locale/da/LC_MESSAGES/sphinx.js +1 -1
  93. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  94. sphinx/locale/da/LC_MESSAGES/sphinx.po +679 -472
  95. sphinx/locale/de/LC_MESSAGES/sphinx.js +1 -1
  96. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  97. sphinx/locale/de/LC_MESSAGES/sphinx.po +679 -472
  98. sphinx/locale/de_DE/LC_MESSAGES/sphinx.js +1 -1
  99. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  100. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +678 -471
  101. sphinx/locale/el/LC_MESSAGES/sphinx.js +1 -1
  102. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/el/LC_MESSAGES/sphinx.po +701 -494
  104. sphinx/locale/en_DE/LC_MESSAGES/sphinx.js +1 -1
  105. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  106. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +700 -493
  107. sphinx/locale/en_FR/LC_MESSAGES/sphinx.js +1 -1
  108. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +700 -493
  110. sphinx/locale/en_GB/LC_MESSAGES/sphinx.js +1 -1
  111. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  112. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +701 -494
  113. sphinx/locale/en_HK/LC_MESSAGES/sphinx.js +1 -1
  114. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +700 -493
  116. sphinx/locale/eo/LC_MESSAGES/sphinx.js +1 -1
  117. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  118. sphinx/locale/eo/LC_MESSAGES/sphinx.po +701 -494
  119. sphinx/locale/es/LC_MESSAGES/sphinx.js +1 -1
  120. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/es/LC_MESSAGES/sphinx.po +701 -494
  122. sphinx/locale/es_CO/LC_MESSAGES/sphinx.js +1 -1
  123. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  124. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +700 -493
  125. sphinx/locale/et/LC_MESSAGES/sphinx.js +1 -1
  126. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/et/LC_MESSAGES/sphinx.po +701 -494
  128. sphinx/locale/eu/LC_MESSAGES/sphinx.js +1 -1
  129. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  130. sphinx/locale/eu/LC_MESSAGES/sphinx.po +701 -494
  131. sphinx/locale/fa/LC_MESSAGES/sphinx.js +1 -1
  132. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/fa/LC_MESSAGES/sphinx.po +701 -494
  134. sphinx/locale/fi/LC_MESSAGES/sphinx.js +1 -1
  135. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  136. sphinx/locale/fi/LC_MESSAGES/sphinx.po +700 -493
  137. sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
  138. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  139. sphinx/locale/fr/LC_MESSAGES/sphinx.po +725 -518
  140. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.js +1 -1
  141. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +700 -493
  143. sphinx/locale/gl/LC_MESSAGES/sphinx.js +1 -1
  144. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  145. sphinx/locale/gl/LC_MESSAGES/sphinx.po +701 -494
  146. sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
  147. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/he/LC_MESSAGES/sphinx.po +700 -493
  149. sphinx/locale/hi/LC_MESSAGES/sphinx.js +1 -1
  150. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  151. sphinx/locale/hi/LC_MESSAGES/sphinx.po +701 -494
  152. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.js +1 -1
  153. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +700 -493
  155. sphinx/locale/hr/LC_MESSAGES/sphinx.js +1 -1
  156. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  157. sphinx/locale/hr/LC_MESSAGES/sphinx.po +701 -494
  158. sphinx/locale/hu/LC_MESSAGES/sphinx.js +1 -1
  159. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/hu/LC_MESSAGES/sphinx.po +701 -494
  161. sphinx/locale/id/LC_MESSAGES/sphinx.js +1 -1
  162. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  163. sphinx/locale/id/LC_MESSAGES/sphinx.po +701 -494
  164. sphinx/locale/is/LC_MESSAGES/sphinx.js +1 -1
  165. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/is/LC_MESSAGES/sphinx.po +700 -493
  167. sphinx/locale/it/LC_MESSAGES/sphinx.js +1 -1
  168. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  169. sphinx/locale/it/LC_MESSAGES/sphinx.po +708 -500
  170. sphinx/locale/ja/LC_MESSAGES/sphinx.js +1 -1
  171. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/ja/LC_MESSAGES/sphinx.po +701 -494
  173. sphinx/locale/ka/LC_MESSAGES/sphinx.js +1 -1
  174. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  175. sphinx/locale/ka/LC_MESSAGES/sphinx.po +700 -493
  176. sphinx/locale/ko/LC_MESSAGES/sphinx.js +1 -1
  177. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/ko/LC_MESSAGES/sphinx.po +701 -494
  179. sphinx/locale/lt/LC_MESSAGES/sphinx.js +1 -1
  180. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  181. sphinx/locale/lt/LC_MESSAGES/sphinx.po +701 -494
  182. sphinx/locale/lv/LC_MESSAGES/sphinx.js +1 -1
  183. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/lv/LC_MESSAGES/sphinx.po +701 -494
  185. sphinx/locale/mk/LC_MESSAGES/sphinx.js +1 -1
  186. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  187. sphinx/locale/mk/LC_MESSAGES/sphinx.po +700 -493
  188. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +1 -1
  189. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +701 -494
  191. sphinx/locale/ne/LC_MESSAGES/sphinx.js +1 -1
  192. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/ne/LC_MESSAGES/sphinx.po +701 -494
  194. sphinx/locale/nl/LC_MESSAGES/sphinx.js +1 -1
  195. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  196. sphinx/locale/nl/LC_MESSAGES/sphinx.po +701 -494
  197. sphinx/locale/pl/LC_MESSAGES/sphinx.js +1 -1
  198. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/pl/LC_MESSAGES/sphinx.po +701 -494
  200. sphinx/locale/pt/LC_MESSAGES/sphinx.js +1 -1
  201. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  202. sphinx/locale/pt/LC_MESSAGES/sphinx.po +700 -493
  203. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.js +1 -1
  204. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +705 -498
  206. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.js +1 -1
  207. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  208. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +701 -494
  209. sphinx/locale/ro/LC_MESSAGES/sphinx.js +1 -1
  210. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/ro/LC_MESSAGES/sphinx.po +701 -494
  212. sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
  213. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  214. sphinx/locale/ru/LC_MESSAGES/sphinx.po +890 -680
  215. sphinx/locale/si/LC_MESSAGES/sphinx.js +1 -1
  216. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  217. sphinx/locale/si/LC_MESSAGES/sphinx.po +700 -493
  218. sphinx/locale/sk/LC_MESSAGES/sphinx.js +1 -1
  219. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/sk/LC_MESSAGES/sphinx.po +701 -494
  221. sphinx/locale/sl/LC_MESSAGES/sphinx.js +1 -1
  222. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  223. sphinx/locale/sl/LC_MESSAGES/sphinx.po +701 -494
  224. sphinx/locale/sphinx.pot +702 -494
  225. sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
  226. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  227. sphinx/locale/sq/LC_MESSAGES/sphinx.po +704 -497
  228. sphinx/locale/sr/LC_MESSAGES/sphinx.js +1 -1
  229. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  230. sphinx/locale/sr/LC_MESSAGES/sphinx.po +700 -493
  231. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  232. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  233. sphinx/locale/sv/LC_MESSAGES/sphinx.js +1 -1
  234. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/sv/LC_MESSAGES/sphinx.po +701 -494
  236. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1016 -808
  237. sphinx/locale/te/LC_MESSAGES/sphinx.js +1 -1
  238. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  239. sphinx/locale/te/LC_MESSAGES/sphinx.po +700 -493
  240. sphinx/locale/tr/LC_MESSAGES/sphinx.js +1 -1
  241. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  242. sphinx/locale/tr/LC_MESSAGES/sphinx.po +701 -494
  243. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.js +1 -1
  244. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  245. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +701 -494
  246. sphinx/locale/ur/LC_MESSAGES/sphinx.js +1 -1
  247. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  248. sphinx/locale/ur/LC_MESSAGES/sphinx.po +700 -493
  249. sphinx/locale/vi/LC_MESSAGES/sphinx.js +1 -1
  250. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  251. sphinx/locale/vi/LC_MESSAGES/sphinx.po +701 -494
  252. sphinx/locale/yue/LC_MESSAGES/sphinx.js +1 -1
  253. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  254. sphinx/locale/yue/LC_MESSAGES/sphinx.po +700 -493
  255. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +704 -496
  256. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.js +1 -1
  257. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  258. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +700 -493
  259. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
  260. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  261. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +729 -522
  262. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.js +1 -1
  263. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  264. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +700 -493
  265. sphinx/roles.py +1 -1
  266. sphinx/search/__init__.py +17 -9
  267. sphinx/templates/quickstart/{root_doc.rst_t → root_doc.rst.jinja} +7 -10
  268. sphinx/testing/fixtures.py +22 -20
  269. sphinx/testing/path.py +6 -2
  270. sphinx/testing/util.py +8 -13
  271. sphinx/texinputs/sphinx.sty +449 -332
  272. sphinx/texinputs/sphinxlatexadmonitions.sty +209 -66
  273. sphinx/texinputs/sphinxlatexliterals.sty +9 -16
  274. sphinx/texinputs/sphinxlatexstyletext.sty +4 -38
  275. sphinx/texinputs/sphinxlatextables.sty +6 -14
  276. sphinx/texinputs/sphinxpackageboxes.sty +15 -42
  277. sphinx/texinputs/sphinxpackagefootnote.sty +4 -3
  278. sphinx/themes/agogo/layout.html +3 -3
  279. sphinx/themes/basic/genindex-single.html +2 -1
  280. sphinx/themes/basic/layout.html +3 -6
  281. sphinx/themes/basic/static/searchtools.js +4 -3
  282. sphinx/themes/haiku/layout.html +4 -4
  283. sphinx/themes/pyramid/layout.html +1 -1
  284. sphinx/themes/scrolls/layout.html +2 -2
  285. sphinx/theming.py +3 -3
  286. sphinx/transforms/__init__.py +34 -20
  287. sphinx/transforms/i18n.py +8 -7
  288. sphinx/transforms/post_transforms/__init__.py +1 -1
  289. sphinx/transforms/post_transforms/images.py +7 -10
  290. sphinx/util/_pathlib.py +2 -2
  291. sphinx/util/cfamily.py +52 -30
  292. sphinx/util/console.py +1 -1
  293. sphinx/util/display.py +16 -11
  294. sphinx/util/docutils.py +88 -40
  295. sphinx/util/fileutil.py +15 -3
  296. sphinx/util/images.py +1 -0
  297. sphinx/util/inspect.py +66 -22
  298. sphinx/util/inventory.py +15 -0
  299. sphinx/util/logging.py +14 -21
  300. sphinx/util/math.py +3 -1
  301. sphinx/util/nodes.py +9 -12
  302. sphinx/util/osutil.py +5 -5
  303. sphinx/util/parsing.py +93 -0
  304. sphinx/util/tags.py +71 -47
  305. sphinx/util/typing.py +265 -143
  306. sphinx/versioning.py +17 -17
  307. sphinx/writers/html5.py +26 -19
  308. sphinx/writers/latex.py +60 -30
  309. sphinx/writers/manpage.py +4 -3
  310. sphinx/writers/texinfo.py +19 -14
  311. {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/METADATA +21 -20
  312. sphinx-7.4.1.dist-info/RECORD +591 -0
  313. sphinx-7.3.7.dist-info/RECORD +0 -581
  314. /sphinx/templates/apidoc/{module.rst_t → module.rst.jinja} +0 -0
  315. /sphinx/templates/apidoc/{package.rst_t → package.rst.jinja} +0 -0
  316. /sphinx/templates/apidoc/{toc.rst_t → toc.rst.jinja} +0 -0
  317. /sphinx/templates/epub3/{content.opf_t → content.opf.jinja} +0 -0
  318. /sphinx/templates/epub3/{nav.xhtml_t → nav.xhtml.jinja} +0 -0
  319. /sphinx/templates/epub3/{toc.ncx_t → toc.ncx.jinja} +0 -0
  320. /sphinx/templates/gettext/{message.pot_t → message.pot.jinja} +0 -0
  321. /sphinx/templates/imgmath/{preview.tex_t → preview.tex.jinja} +0 -0
  322. /sphinx/templates/imgmath/{template.tex_t → template.tex.jinja} +0 -0
  323. /sphinx/templates/latex/{latex.tex_t → latex.tex.jinja} +0 -0
  324. /sphinx/templates/latex/{longtable.tex_t → longtable.tex.jinja} +0 -0
  325. /sphinx/templates/latex/{sphinxmessages.sty_t → sphinxmessages.sty.jinja} +0 -0
  326. /sphinx/templates/latex/{tabular.tex_t → tabular.tex.jinja} +0 -0
  327. /sphinx/templates/latex/{tabulary.tex_t → tabulary.tex.jinja} +0 -0
  328. /sphinx/templates/quickstart/{Makefile_t → Makefile.jinja} +0 -0
  329. /sphinx/templates/quickstart/{Makefile.new_t → Makefile.new.jinja} +0 -0
  330. /sphinx/templates/quickstart/{conf.py_t → conf.py.jinja} +0 -0
  331. /sphinx/templates/quickstart/{make.bat_t → make.bat.jinja} +0 -0
  332. /sphinx/templates/quickstart/{make.bat.new_t → make.bat.new.jinja} +0 -0
  333. /sphinx/texinputs/{Makefile_t → Makefile.jinja} +0 -0
  334. /sphinx/texinputs/{latexmkjarc_t → latexmkjarc.jinja} +0 -0
  335. /sphinx/texinputs/{latexmkrc_t → latexmkrc.jinja} +0 -0
  336. /sphinx/texinputs/{make.bat_t → make.bat.jinja} +0 -0
  337. /sphinx/texinputs_win/{Makefile_t → Makefile.jinja} +0 -0
  338. /sphinx/themes/agogo/static/{agogo.css_t → agogo.css.jinja} +0 -0
  339. /sphinx/themes/basic/static/{basic.css_t → basic.css.jinja} +0 -0
  340. /sphinx/themes/basic/static/{documentation_options.js_t → documentation_options.js.jinja} +0 -0
  341. /sphinx/themes/basic/static/{language_data.js_t → language_data.js.jinja} +0 -0
  342. /sphinx/themes/bizstyle/static/{bizstyle.css_t → bizstyle.css.jinja} +0 -0
  343. /sphinx/themes/bizstyle/static/{bizstyle.js_t → bizstyle.js.jinja} +0 -0
  344. /sphinx/themes/classic/static/{classic.css_t → classic.css.jinja} +0 -0
  345. /sphinx/themes/classic/static/{sidebar.js_t → sidebar.js.jinja} +0 -0
  346. /sphinx/themes/epub/static/{epub.css_t → epub.css.jinja} +0 -0
  347. /sphinx/themes/haiku/static/{haiku.css_t → haiku.css.jinja} +0 -0
  348. /sphinx/themes/nature/static/{nature.css_t → nature.css.jinja} +0 -0
  349. /sphinx/themes/nonav/static/{nonav.css_t → nonav.css.jinja} +0 -0
  350. /sphinx/themes/pyramid/static/{epub.css_t → epub.css.jinja} +0 -0
  351. /sphinx/themes/pyramid/static/{pyramid.css_t → pyramid.css.jinja} +0 -0
  352. /sphinx/themes/scrolls/static/{scrolls.css_t → scrolls.css.jinja} +0 -0
  353. /sphinx/themes/sphinxdoc/static/{sphinxdoc.css_t → sphinxdoc.css.jinja} +0 -0
  354. /sphinx/themes/traditional/static/{traditional.css_t → traditional.css.jinja} +0 -0
  355. {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/LICENSE.rst +0 -0
  356. {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/WHEEL +0 -0
  357. {sphinx-7.3.7.dist-info → sphinx-7.4.1.dist-info}/entry_points.txt +0 -0
@@ -115,7 +115,7 @@ class BuildInfo:
115
115
  """
116
116
 
117
117
  @classmethod
118
- def load(cls: type[BuildInfo], f: IO) -> BuildInfo:
118
+ def load(cls: type[BuildInfo], f: IO[str]) -> BuildInfo:
119
119
  try:
120
120
  lines = f.readlines()
121
121
  assert lines[0].rstrip() == '# Sphinx build info version 1'
@@ -149,7 +149,7 @@ class BuildInfo:
149
149
  return (self.config_hash == other.config_hash and
150
150
  self.tags_hash == other.tags_hash)
151
151
 
152
- def dump(self, f: IO) -> None:
152
+ def dump(self, f: IO[str]) -> None:
153
153
  f.write('# Sphinx build info version 1\n'
154
154
  '# This file hashes the configuration used when building these files.'
155
155
  ' When it is not found, a full rebuild will be done.\n'
@@ -201,7 +201,9 @@ class StandaloneHTMLBuilder(Builder):
201
201
  self._js_files: list[_JavaScript] = []
202
202
 
203
203
  # Cached Publisher for writing doctrees to HTML
204
- reader: Reader = docutils.readers.doctree.Reader(parser_name='restructuredtext')
204
+ reader: Reader[DocTreeInput] = docutils.readers.doctree.Reader(
205
+ parser_name='restructuredtext'
206
+ )
205
207
  pub = Publisher(
206
208
  reader=reader,
207
209
  parser=reader.parser,
@@ -209,11 +211,7 @@ class StandaloneHTMLBuilder(Builder):
209
211
  source_class=DocTreeInput,
210
212
  destination=StringOutput(encoding='unicode'),
211
213
  )
212
- if docutils.__version_info__[:2] >= (0, 19):
213
- pub.get_settings(output_encoding='unicode', traceback=True)
214
- else:
215
- op = pub.setup_option_parser(output_encoding='unicode', traceback=True)
216
- pub.settings = op.get_default_values()
214
+ pub.get_settings(output_encoding='unicode', traceback=True)
217
215
  self._publisher = pub
218
216
 
219
217
  def init(self) -> None:
@@ -269,7 +267,7 @@ class StandaloneHTMLBuilder(Builder):
269
267
  else:
270
268
  yield 'default.css'
271
269
 
272
- def get_theme_config(self) -> tuple[str, dict]:
270
+ def get_theme_config(self) -> tuple[str, dict[str, str | int | bool]]:
273
271
  return self.config.html_theme, self.config.html_theme_options
274
272
 
275
273
  def init_templates(self) -> None:
@@ -465,29 +463,31 @@ class StandaloneHTMLBuilder(Builder):
465
463
  # determine the additional indices to include
466
464
  self.domain_indices = []
467
465
  # html_domain_indices can be False/True or a list of index names
468
- indices_config = self.config.html_domain_indices
469
- if indices_config:
466
+ if indices_config := self.config.html_domain_indices:
467
+ if not isinstance(indices_config, bool):
468
+ check_names = True
469
+ indices_config = frozenset(indices_config)
470
+ else:
471
+ check_names = False
470
472
  for domain_name in sorted(self.env.domains):
471
473
  domain: Domain = self.env.domains[domain_name]
472
- for indexcls in domain.indices:
473
- indexname = f'{domain.name}-{indexcls.name}'
474
- if isinstance(indices_config, list):
475
- if indexname not in indices_config:
476
- continue
477
- content, collapse = indexcls(domain).generate()
474
+ for index_cls in domain.indices:
475
+ index_name = f'{domain.name}-{index_cls.name}'
476
+ if check_names and index_name not in indices_config:
477
+ continue
478
+ content, collapse = index_cls(domain).generate()
478
479
  if content:
479
480
  self.domain_indices.append(
480
- (indexname, indexcls, content, collapse))
481
+ (index_name, index_cls, content, collapse))
481
482
 
482
483
  # format the "last updated on" string, only once is enough since it
483
484
  # typically doesn't include the time of day
484
- self.last_updated: str | None
485
- lufmt = self.config.html_last_updated_fmt
486
- if lufmt is not None:
487
- self.last_updated = format_date(lufmt or _('%b %d, %Y'),
488
- language=self.config.language)
485
+ last_updated: str | None
486
+ if (lu_fmt := self.config.html_last_updated_fmt) is not None:
487
+ lu_fmt = lu_fmt or _('%b %d, %Y')
488
+ last_updated = format_date(lu_fmt, language=self.config.language)
489
489
  else:
490
- self.last_updated = None
490
+ last_updated = None
491
491
 
492
492
  # If the logo or favicon are urls, keep them as-is, otherwise
493
493
  # strip the relative path as the files will be copied into _static.
@@ -526,7 +526,7 @@ class StandaloneHTMLBuilder(Builder):
526
526
  'project': self.config.project,
527
527
  'release': return_codes_re.sub('', self.config.release),
528
528
  'version': self.config.version,
529
- 'last_updated': self.last_updated,
529
+ 'last_updated': last_updated,
530
530
  'copyright': self.config.copyright,
531
531
  'master_doc': self.config.root_doc,
532
532
  'root_doc': self.config.root_doc,
@@ -552,6 +552,7 @@ class StandaloneHTMLBuilder(Builder):
552
552
  'builder': self.name,
553
553
  'parents': [],
554
554
  'logo_url': logo,
555
+ 'logo_alt': _('Logo of %s') % self.config.project,
555
556
  'favicon_url': favicon,
556
557
  'html5_doctype': True,
557
558
  }
@@ -824,7 +825,7 @@ class StandaloneHTMLBuilder(Builder):
824
825
  excluded=DOTFILES, context=context,
825
826
  renderer=self.templates, onerror=onerror)
826
827
 
827
- def copy_html_static_files(self, context: dict) -> None:
828
+ def copy_html_static_files(self, context: dict[str, Any]) -> None:
828
829
  def onerror(filename: str, error: Exception) -> None:
829
830
  logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
830
831
  filename, error)
@@ -890,7 +891,7 @@ class StandaloneHTMLBuilder(Builder):
890
891
 
891
892
  def post_process_images(self, doctree: Node) -> None:
892
893
  """Pick the best candidate for an image and link down-scaled images to
893
- their high res version.
894
+ their high resolution version.
894
895
  """
895
896
  super().post_process_images(doctree)
896
897
 
@@ -957,47 +958,48 @@ class StandaloneHTMLBuilder(Builder):
957
958
  def get_outfilename(self, pagename: str) -> str:
958
959
  return path.join(self.outdir, os_path(pagename) + self.out_suffix)
959
960
 
960
- def add_sidebars(self, pagename: str, ctx: dict) -> None:
961
+ def add_sidebars(self, pagename: str, ctx: dict[str, Any]) -> None:
961
962
  def has_wildcard(pattern: str) -> bool:
962
963
  return any(char in pattern for char in '*?[')
963
964
 
964
965
  matched = None
965
- customsidebar = None
966
966
 
967
967
  # default sidebars settings for selected theme
968
968
  sidebars = list(self.theme.sidebar_templates)
969
969
 
970
970
  # user sidebar settings
971
971
  html_sidebars = self.get_builder_config('sidebars', 'html')
972
- for pattern, patsidebars in html_sidebars.items():
972
+ msg = __('page %s matches two patterns in html_sidebars: %r and %r')
973
+ for pattern, pat_sidebars in html_sidebars.items():
973
974
  if patmatch(pagename, pattern):
974
- if matched:
975
- if has_wildcard(pattern):
976
- # warn if both patterns contain wildcards
977
- if has_wildcard(matched):
978
- logger.warning(__('page %s matches two patterns in '
979
- 'html_sidebars: %r and %r'),
980
- pagename, matched, pattern)
981
- # else the already matched pattern is more specific
982
- # than the present one, because it contains no wildcard
983
- continue
975
+ if matched and has_wildcard(pattern):
976
+ # warn if both patterns contain wildcards
977
+ if has_wildcard(matched):
978
+ logger.warning(msg, pagename, matched)
979
+ # else the already matched pattern is more specific
980
+ # than the present one, because it contains no wildcard
981
+ continue
984
982
  matched = pattern
985
- sidebars = patsidebars
983
+ sidebars = pat_sidebars
986
984
 
987
985
  if len(sidebars) == 0:
988
986
  # keep defaults
989
987
  pass
990
988
 
991
- ctx['sidebars'] = sidebars
992
- ctx['customsidebar'] = customsidebar
989
+ ctx['sidebars'] = list(sidebars)
993
990
 
994
991
  # --------- these are overwritten by the serialization builder
995
992
 
996
993
  def get_target_uri(self, docname: str, typ: str | None = None) -> str:
997
994
  return quote(docname) + self.link_suffix
998
995
 
999
- def handle_page(self, pagename: str, addctx: dict, templatename: str = 'page.html',
1000
- outfilename: str | None = None, event_arg: Any = None) -> None:
996
+ def handle_page(
997
+ self, pagename: str,
998
+ addctx: dict[str, Any],
999
+ templatename: str = 'page.html',
1000
+ outfilename: str | None = None,
1001
+ event_arg: Any = None,
1002
+ ) -> None:
1001
1003
  ctx = self.globalcontext.copy()
1002
1004
  # current_page_name is backwards compatibility
1003
1005
  ctx['pagename'] = ctx['current_page_name'] = pagename
@@ -1144,7 +1146,7 @@ class StandaloneHTMLBuilder(Builder):
1144
1146
  copyfile(self.env.doc2path(pagename), source_name)
1145
1147
 
1146
1148
  def update_page_context(self, pagename: str, templatename: str,
1147
- ctx: dict, event_arg: Any) -> None:
1149
+ ctx: dict[str, Any], event_arg: Any) -> None:
1148
1150
  pass
1149
1151
 
1150
1152
  def handle_finish(self) -> None:
@@ -1175,7 +1177,7 @@ class StandaloneHTMLBuilder(Builder):
1175
1177
 
1176
1178
  def convert_html_css_files(app: Sphinx, config: Config) -> None:
1177
1179
  """Convert string styled html_css_files to tuple styled one."""
1178
- html_css_files: list[tuple[str, dict]] = []
1180
+ html_css_files: list[tuple[str, dict[str, str]]] = []
1179
1181
  for entry in config.html_css_files:
1180
1182
  if isinstance(entry, str):
1181
1183
  html_css_files.append((entry, {}))
@@ -1187,7 +1189,7 @@ def convert_html_css_files(app: Sphinx, config: Config) -> None:
1187
1189
  logger.warning(__('invalid css_file: %r, ignored'), entry)
1188
1190
  continue
1189
1191
 
1190
- config.html_css_files = html_css_files # type: ignore[attr-defined]
1192
+ config.html_css_files = html_css_files
1191
1193
 
1192
1194
 
1193
1195
  def _format_modified_time(timestamp: float) -> str:
@@ -1198,7 +1200,7 @@ def _format_modified_time(timestamp: float) -> str:
1198
1200
 
1199
1201
  def convert_html_js_files(app: Sphinx, config: Config) -> None:
1200
1202
  """Convert string styled html_js_files to tuple styled one."""
1201
- html_js_files: list[tuple[str, dict]] = []
1203
+ html_js_files: list[tuple[str, dict[str, str]]] = []
1202
1204
  for entry in config.html_js_files:
1203
1205
  if isinstance(entry, str):
1204
1206
  html_js_files.append((entry, {}))
@@ -1210,11 +1212,11 @@ def convert_html_js_files(app: Sphinx, config: Config) -> None:
1210
1212
  logger.warning(__('invalid js_file: %r, ignored'), entry)
1211
1213
  continue
1212
1214
 
1213
- config.html_js_files = html_js_files # type: ignore[attr-defined]
1215
+ config.html_js_files = html_js_files
1214
1216
 
1215
1217
 
1216
1218
  def setup_resource_paths(app: Sphinx, pagename: str, templatename: str,
1217
- context: dict, doctree: Node) -> None:
1219
+ context: dict[str, Any], doctree: Node) -> None:
1218
1220
  """Set up relative resource paths."""
1219
1221
  pathto = context['pathto']
1220
1222
 
@@ -1273,7 +1275,7 @@ def validate_html_logo(app: Sphinx, config: Config) -> None:
1273
1275
  not path.isfile(path.join(app.confdir, config.html_logo)) and
1274
1276
  not isurl(config.html_logo)):
1275
1277
  logger.warning(__('logo file %r does not exist'), config.html_logo)
1276
- config.html_logo = None # type: ignore[attr-defined]
1278
+ config.html_logo = None
1277
1279
 
1278
1280
 
1279
1281
  def validate_html_favicon(app: Sphinx, config: Config) -> None:
@@ -1282,7 +1284,7 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None:
1282
1284
  not path.isfile(path.join(app.confdir, config.html_favicon)) and
1283
1285
  not isurl(config.html_favicon)):
1284
1286
  logger.warning(__('favicon file %r does not exist'), config.html_favicon)
1285
- config.html_favicon = None # type: ignore[attr-defined]
1287
+ config.html_favicon = None
1286
1288
 
1287
1289
 
1288
1290
  def error_on_html_4(_app: Sphinx, config: Config) -> None:
@@ -1315,7 +1317,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
1315
1317
  app.add_config_value('html_last_updated_fmt', None, 'html', str)
1316
1318
  app.add_config_value('html_sidebars', {}, 'html')
1317
1319
  app.add_config_value('html_additional_pages', {}, 'html')
1318
- app.add_config_value('html_domain_indices', True, 'html', list)
1320
+ app.add_config_value('html_domain_indices', True, 'html', types={set, list})
1319
1321
  app.add_config_value('html_permalinks', True, 'html')
1320
1322
  app.add_config_value('html_permalinks_icon', '¶', 'html')
1321
1323
  app.add_config_value('html_use_index', True, 'html')
@@ -417,7 +417,7 @@ class LaTeXBuilder(Builder):
417
417
  # use pre-1.6.x Makefile for make latexpdf on Windows
418
418
  if os.name == 'nt':
419
419
  staticdirname = path.join(package_dir, 'texinputs_win')
420
- copy_asset_file(path.join(staticdirname, 'Makefile_t'),
420
+ copy_asset_file(path.join(staticdirname, 'Makefile.jinja'),
421
421
  self.outdir, context=context)
422
422
 
423
423
  @progress_message(__('copying additional files'))
@@ -456,7 +456,7 @@ class LaTeXBuilder(Builder):
456
456
  if self.context['babel'] or self.context['polyglossia']:
457
457
  context['addtocaptions'] = r'\addto\captions%s' % self.babel.get_language()
458
458
 
459
- filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t')
459
+ filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty.jinja')
460
460
  copy_asset_file(filename, self.outdir, context=context, renderer=LaTeXRenderer())
461
461
 
462
462
 
@@ -464,7 +464,7 @@ def validate_config_values(app: Sphinx, config: Config) -> None:
464
464
  for key in list(config.latex_elements):
465
465
  if key not in DEFAULT_SETTINGS:
466
466
  msg = __("Unknown configure key: latex_elements[%r], ignored.")
467
- logger.warning(msg % (key,))
467
+ logger.warning(msg, key)
468
468
  config.latex_elements.pop(key)
469
469
 
470
470
 
@@ -472,7 +472,7 @@ def validate_latex_theme_options(app: Sphinx, config: Config) -> None:
472
472
  for key in list(config.latex_theme_options):
473
473
  if key not in Theme.UPDATABLE_KEYS:
474
474
  msg = __("Unknown theme option: latex_theme_options[%r], ignored.")
475
- logger.warning(msg % (key,))
475
+ logger.warning(msg, key)
476
476
  config.latex_theme_options.pop(key)
477
477
 
478
478
 
@@ -539,7 +539,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
539
539
  app.add_config_value('latex_use_xindy', default_latex_use_xindy, '', bool)
540
540
  app.add_config_value('latex_toplevel_sectioning', None, '',
541
541
  ENUM(None, 'part', 'chapter', 'section'))
542
- app.add_config_value('latex_domain_indices', True, '', list)
542
+ app.add_config_value('latex_domain_indices', True, '', types={set, list})
543
543
  app.add_config_value('latex_show_urls', 'no', '')
544
544
  app.add_config_value('latex_show_pagerefs', False, '')
545
545
  app.add_config_value('latex_elements', {}, '')
@@ -183,6 +183,11 @@ ADDITIONAL_SETTINGS: dict[Any, dict[str, Any]] = {
183
183
  },
184
184
 
185
185
  # special settings for latex_engine + language_code
186
+ ('lualatex', 'fr'): {
187
+ # use babel instead of polyglossia by default
188
+ 'polyglossia': '',
189
+ 'babel': '\\usepackage{babel}',
190
+ },
186
191
  ('xelatex', 'fr'): {
187
192
  # use babel instead of polyglossia by default
188
193
  'polyglossia': '',
@@ -13,7 +13,7 @@ from os import path
13
13
  from queue import PriorityQueue, Queue
14
14
  from threading import Thread
15
15
  from typing import TYPE_CHECKING, NamedTuple, cast
16
- from urllib.parse import unquote, urlparse, urlsplit, urlunparse
16
+ from urllib.parse import quote, unquote, urlparse, urlsplit, urlunparse
17
17
 
18
18
  from docutils import nodes
19
19
  from requests.exceptions import ConnectionError, HTTPError, SSLError, TooManyRedirects
@@ -102,9 +102,11 @@ class CheckExternalLinksBuilder(DummyBuilder):
102
102
  def process_result(self, result: CheckResult) -> None:
103
103
  filename = self.env.doc2path(result.docname, False)
104
104
 
105
- linkstat = {'filename': filename, 'lineno': result.lineno,
106
- 'status': result.status, 'code': result.code, 'uri': result.uri,
107
- 'info': result.message}
105
+ linkstat: dict[str, str | int] = {
106
+ 'filename': filename, 'lineno': result.lineno,
107
+ 'status': result.status, 'code': result.code,
108
+ 'uri': result.uri, 'info': result.message,
109
+ }
108
110
  self.write_linkstat(linkstat)
109
111
 
110
112
  if result.status == 'unchecked':
@@ -164,7 +166,7 @@ class CheckExternalLinksBuilder(DummyBuilder):
164
166
  else:
165
167
  raise ValueError('Unknown status %s.' % result.status)
166
168
 
167
- def write_linkstat(self, data: dict) -> None:
169
+ def write_linkstat(self, data: dict[str, str | int]) -> None:
168
170
  self.json_outfile.write(json.dumps(data))
169
171
  self.json_outfile.write('\n')
170
172
 
@@ -178,41 +180,67 @@ class HyperlinkCollector(SphinxPostTransform):
178
180
  default_priority = 800
179
181
 
180
182
  def run(self, **kwargs: Any) -> None:
181
- builder = cast(CheckExternalLinksBuilder, self.app.builder)
182
- hyperlinks = builder.hyperlinks
183
- docname = self.env.docname
183
+ for node in self.document.findall():
184
+ if uri := self.find_uri(node):
185
+ self._add_uri(uri, node)
186
+
187
+ def find_uri(self, node: nodes.Element) -> str | None:
188
+ """Find a URI for a given node.
184
189
 
190
+ This call can be used to retrieve a URI from a provided node. If no
191
+ URI exists for a provided node, this call will return ``None``.
192
+
193
+ This method can be useful for extension developers who wish to
194
+ easily inject hyperlinks into a builder by only needing to override
195
+ this method.
196
+
197
+ :param node: A node class
198
+ :returns: URI of the node
199
+ """
185
200
  # reference nodes
186
- for refnode in self.document.findall(nodes.reference):
187
- if 'refuri' in refnode:
188
- uri = refnode['refuri']
189
- _add_uri(self.app, uri, refnode, hyperlinks, docname)
201
+ if isinstance(node, nodes.reference):
202
+ if 'refuri' in node:
203
+ return node['refuri']
190
204
 
191
205
  # image nodes
192
- for imgnode in self.document.findall(nodes.image):
193
- uri = imgnode['candidates'].get('?')
206
+ if isinstance(node, nodes.image):
207
+ uri = node['candidates'].get('?')
194
208
  if uri and '://' in uri:
195
- _add_uri(self.app, uri, imgnode, hyperlinks, docname)
209
+ return uri
196
210
 
197
211
  # raw nodes
198
- for rawnode in self.document.findall(nodes.raw):
199
- uri = rawnode.get('source')
212
+ if isinstance(node, nodes.raw):
213
+ uri = node.get('source')
200
214
  if uri and '://' in uri:
201
- _add_uri(self.app, uri, rawnode, hyperlinks, docname)
215
+ return uri
216
+
217
+ return None
202
218
 
219
+ def _add_uri(self, uri: str, node: nodes.Element) -> None:
220
+ """Registers a node's URI into a builder's collection of hyperlinks.
203
221
 
204
- def _add_uri(app: Sphinx, uri: str, node: nodes.Element,
205
- hyperlinks: dict[str, Hyperlink], docname: str) -> None:
206
- if newuri := app.emit_firstresult('linkcheck-process-uri', uri):
207
- uri = newuri
222
+ Provides the ability to register a URI value determined from a node
223
+ into the linkcheck's builder. URI's processed through this call can
224
+ be manipulated through a ``linkcheck-process-uri`` event before the
225
+ builder attempts to validate.
208
226
 
209
- try:
210
- lineno = get_node_line(node)
211
- except ValueError:
212
- lineno = -1
227
+ :param uri: URI to add
228
+ :param node: A node class where the URI was found
229
+ """
230
+ builder = cast(CheckExternalLinksBuilder, self.app.builder)
231
+ hyperlinks = builder.hyperlinks
232
+ docname = self.env.docname
233
+
234
+ if newuri := self.app.emit_firstresult('linkcheck-process-uri', uri):
235
+ uri = newuri
236
+
237
+ try:
238
+ lineno = get_node_line(node)
239
+ except ValueError:
240
+ lineno = -1
213
241
 
214
- if uri not in hyperlinks:
215
- hyperlinks[uri] = Hyperlink(uri, docname, app.env.doc2path(docname), lineno)
242
+ if uri not in hyperlinks:
243
+ hyperlinks[uri] = Hyperlink(uri, docname, self.env.doc2path(docname), lineno)
216
244
 
217
245
 
218
246
  class Hyperlink(NamedTuple):
@@ -390,9 +418,11 @@ class HyperlinkAvailabilityCheckWorker(Thread):
390
418
 
391
419
  return status, info, code
392
420
 
393
- def _retrieval_methods(self,
394
- check_anchors: bool,
395
- anchor: str) -> Iterator[tuple[Callable, dict]]:
421
+ def _retrieval_methods(
422
+ self,
423
+ check_anchors: bool,
424
+ anchor: str,
425
+ ) -> Iterator[tuple[Callable[..., Response], dict[str, bool]]]:
396
426
  if not check_anchors or not anchor:
397
427
  yield self._session.head, {'allow_redirects': True}
398
428
  yield self._session.get, {'stream': True}
@@ -409,6 +439,7 @@ class HyperlinkAvailabilityCheckWorker(Thread):
409
439
  if rex.match(req_url):
410
440
  anchor = ''
411
441
  break
442
+ anchor = unquote(anchor)
412
443
 
413
444
  # handle non-ASCII URIs
414
445
  try:
@@ -444,14 +475,18 @@ class HyperlinkAvailabilityCheckWorker(Thread):
444
475
  _user_agent=self.user_agent,
445
476
  _tls_info=(self.tls_verify, self.tls_cacerts),
446
477
  ) as response:
447
- if (self.check_anchors and response.ok and anchor
448
- and not contains_anchor(response, anchor)):
449
- raise Exception(__(f'Anchor {anchor!r} not found'))
478
+ if anchor and self.check_anchors and response.ok:
479
+ try:
480
+ found = contains_anchor(response, anchor)
481
+ except UnicodeDecodeError:
482
+ return 'ignored', 'unable to decode response content', 0
483
+ if not found:
484
+ return 'broken', __("Anchor '%s' not found") % quote(anchor), 0
450
485
 
451
486
  # Copy data we need from the (closed) response
452
487
  status_code = response.status_code
453
488
  redirect_status_code = response.history[-1].status_code if response.history else None # NoQA: E501
454
- retry_after = response.headers.get('Retry-After')
489
+ retry_after = response.headers.get('Retry-After', '')
455
490
  response_url = f'{response.url}'
456
491
  response.raise_for_status()
457
492
  del response
@@ -536,7 +571,7 @@ class HyperlinkAvailabilityCheckWorker(Thread):
536
571
  else:
537
572
  return 'redirected', response_url, 0
538
573
 
539
- def limit_rate(self, response_url: str, retry_after: str) -> float | None:
574
+ def limit_rate(self, response_url: str, retry_after: str | None) -> float | None:
540
575
  delay = DEFAULT_DELAY
541
576
  next_check = None
542
577
  if retry_after:
@@ -592,7 +627,7 @@ def _get_request_headers(
592
627
 
593
628
  def contains_anchor(response: Response, anchor: str) -> bool:
594
629
  """Determine if an anchor is contained within an HTTP response."""
595
- parser = AnchorCheckParser(unquote(anchor))
630
+ parser = AnchorCheckParser(anchor)
596
631
  # Read file in chunks. If we find a matching anchor, we break
597
632
  # the loop early in hopes not to have to download the whole thing.
598
633
  for chunk in response.iter_content(chunk_size=4096, decode_unicode=True):
@@ -681,7 +716,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
681
716
  # commonly used for dynamic pages
682
717
  app.add_config_value('linkcheck_anchors_ignore', ['^!'], '')
683
718
  app.add_config_value('linkcheck_anchors_ignore_for_url', (), '', (tuple, list))
684
- app.add_config_value('linkcheck_rate_limit_timeout', 300.0, '')
719
+ app.add_config_value('linkcheck_rate_limit_timeout', 300.0, '', (int, float))
685
720
  app.add_config_value('linkcheck_allow_unauthorized', True, '')
686
721
  app.add_config_value('linkcheck_report_timeouts_as_broken', True, '', bool)
687
722
 
@@ -221,7 +221,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
221
221
  app.add_config_value('texinfo_documents', default_texinfo_documents, '')
222
222
  app.add_config_value('texinfo_appendices', [], '')
223
223
  app.add_config_value('texinfo_elements', {}, '')
224
- app.add_config_value('texinfo_domain_indices', True, '', list)
224
+ app.add_config_value('texinfo_domain_indices', True, '', types={set, list})
225
225
  app.add_config_value('texinfo_show_urls', 'footnote', '')
226
226
  app.add_config_value('texinfo_no_detailmenu', False, '')
227
227
  app.add_config_value('texinfo_cross_references', True, '')
sphinx/cmd/build.py CHANGED
@@ -179,7 +179,7 @@ files can be built by specifying individual filenames.
179
179
  dest='tags', default=[],
180
180
  help=__('define tag: include "only" blocks with TAG'))
181
181
  group.add_argument('--nitpicky', '-n', action='store_true', dest='nitpicky',
182
- help=__('nit-picky mode: warn about all missing references'))
182
+ help=__('nitpicky mode: warn about all missing references'))
183
183
 
184
184
  group = parser.add_argument_group(__('console output options'))
185
185
  group.add_argument('--verbose', '-v', action='count', dest='verbosity',
sphinx/cmd/quickstart.py CHANGED
@@ -372,32 +372,32 @@ def generate(
372
372
  if 'quiet' not in d:
373
373
  print(__('File %s already exists, skipping.') % fpath)
374
374
 
375
- conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None
375
+ conf_path = os.path.join(templatedir, 'conf.py.jinja') if templatedir else None
376
376
  if not conf_path or not path.isfile(conf_path):
377
- conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t')
377
+ conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py.jinja')
378
378
  with open(conf_path, encoding="utf-8") as f:
379
379
  conf_text = f.read()
380
380
 
381
381
  write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d))
382
382
 
383
383
  masterfile = path.join(srcdir, d['master'] + d['suffix'])
384
- if template._has_custom_template('quickstart/master_doc.rst_t'):
385
- msg = ('A custom template `master_doc.rst_t` found. It has been renamed to '
386
- '`root_doc.rst_t`. Please rename it on your project too.')
384
+ if template._has_custom_template('quickstart/master_doc.rst.jinja'):
385
+ msg = ('A custom template `master_doc.rst.jinja` found. It has been renamed to '
386
+ '`root_doc.rst.jinja`. Please rename it on your project too.')
387
387
  print(colorize('red', msg))
388
- write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))
388
+ write_file(masterfile, template.render('quickstart/master_doc.rst.jinja', d))
389
389
  else:
390
- write_file(masterfile, template.render('quickstart/root_doc.rst_t', d))
390
+ write_file(masterfile, template.render('quickstart/root_doc.rst.jinja', d))
391
391
 
392
392
  if d.get('make_mode'):
393
- makefile_template = 'quickstart/Makefile.new_t'
394
- batchfile_template = 'quickstart/make.bat.new_t'
393
+ makefile_template = 'quickstart/Makefile.new.jinja'
394
+ batchfile_template = 'quickstart/make.bat.new.jinja'
395
395
  else:
396
396
  # xref RemovedInSphinx80Warning
397
397
  msg = "Support for '--no-use-make-mode' will be removed in Sphinx 8."
398
398
  print(colorize('red', msg))
399
- makefile_template = 'quickstart/Makefile_t'
400
- batchfile_template = 'quickstart/make.bat_t'
399
+ makefile_template = 'quickstart/Makefile.jinja'
400
+ batchfile_template = 'quickstart/make.bat.jinja'
401
401
 
402
402
  if d['makefile'] is True:
403
403
  d['rsrcdir'] = 'source' if d['sep'] else '.'