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

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

Potentially problematic release.


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

Files changed (388) hide show
  1. sphinx/__init__.py +8 -9
  2. sphinx/addnodes.py +31 -28
  3. sphinx/application.py +9 -15
  4. sphinx/builders/__init__.py +5 -6
  5. sphinx/builders/_epub_base.py +17 -9
  6. sphinx/builders/changes.py +10 -5
  7. sphinx/builders/dirhtml.py +4 -2
  8. sphinx/builders/dummy.py +3 -2
  9. sphinx/builders/epub3.py +5 -3
  10. sphinx/builders/gettext.py +24 -7
  11. sphinx/builders/html/__init__.py +88 -96
  12. sphinx/builders/html/_assets.py +16 -16
  13. sphinx/builders/html/transforms.py +4 -2
  14. sphinx/builders/latex/__init__.py +40 -33
  15. sphinx/builders/latex/nodes.py +6 -2
  16. sphinx/builders/latex/transforms.py +17 -8
  17. sphinx/builders/latex/util.py +1 -1
  18. sphinx/builders/linkcheck.py +86 -27
  19. sphinx/builders/manpage.py +8 -6
  20. sphinx/builders/singlehtml.py +5 -4
  21. sphinx/builders/texinfo.py +18 -14
  22. sphinx/builders/text.py +3 -2
  23. sphinx/builders/xml.py +5 -2
  24. sphinx/cmd/build.py +119 -76
  25. sphinx/cmd/make_mode.py +21 -20
  26. sphinx/cmd/quickstart.py +13 -16
  27. sphinx/config.py +432 -250
  28. sphinx/deprecation.py +23 -13
  29. sphinx/directives/__init__.py +8 -8
  30. sphinx/directives/code.py +7 -7
  31. sphinx/directives/other.py +23 -13
  32. sphinx/directives/patches.py +7 -6
  33. sphinx/domains/__init__.py +2 -2
  34. sphinx/domains/c/__init__.py +796 -0
  35. sphinx/domains/c/_ast.py +1421 -0
  36. sphinx/domains/c/_ids.py +65 -0
  37. sphinx/domains/c/_parser.py +1048 -0
  38. sphinx/domains/c/_symbol.py +700 -0
  39. sphinx/domains/changeset.py +11 -7
  40. sphinx/domains/citation.py +5 -2
  41. sphinx/domains/cpp/__init__.py +1089 -0
  42. sphinx/domains/cpp/_ast.py +3635 -0
  43. sphinx/domains/cpp/_ids.py +537 -0
  44. sphinx/domains/cpp/_parser.py +2117 -0
  45. sphinx/domains/cpp/_symbol.py +1092 -0
  46. sphinx/domains/index.py +6 -4
  47. sphinx/domains/javascript.py +16 -13
  48. sphinx/domains/math.py +9 -4
  49. sphinx/domains/python/__init__.py +890 -0
  50. sphinx/domains/python/_annotations.py +507 -0
  51. sphinx/domains/python/_object.py +426 -0
  52. sphinx/domains/rst.py +12 -7
  53. sphinx/domains/{std.py → std/__init__.py} +19 -16
  54. sphinx/environment/__init__.py +21 -19
  55. sphinx/environment/adapters/indexentries.py +2 -2
  56. sphinx/environment/adapters/toctree.py +10 -9
  57. sphinx/environment/collectors/__init__.py +6 -3
  58. sphinx/environment/collectors/asset.py +4 -3
  59. sphinx/environment/collectors/dependencies.py +3 -2
  60. sphinx/environment/collectors/metadata.py +6 -5
  61. sphinx/environment/collectors/title.py +3 -2
  62. sphinx/environment/collectors/toctree.py +5 -4
  63. sphinx/errors.py +13 -2
  64. sphinx/events.py +14 -9
  65. sphinx/ext/apidoc.py +9 -11
  66. sphinx/ext/autodoc/__init__.py +105 -71
  67. sphinx/ext/autodoc/directive.py +7 -6
  68. sphinx/ext/autodoc/importer.py +132 -52
  69. sphinx/ext/autodoc/mock.py +7 -5
  70. sphinx/ext/autodoc/preserve_defaults.py +4 -3
  71. sphinx/ext/autodoc/type_comment.py +2 -1
  72. sphinx/ext/autodoc/typehints.py +5 -4
  73. sphinx/ext/autosectionlabel.py +3 -2
  74. sphinx/ext/autosummary/__init__.py +21 -17
  75. sphinx/ext/autosummary/generate.py +9 -9
  76. sphinx/ext/coverage.py +26 -20
  77. sphinx/ext/doctest.py +38 -33
  78. sphinx/ext/duration.py +1 -0
  79. sphinx/ext/extlinks.py +4 -3
  80. sphinx/ext/githubpages.py +3 -2
  81. sphinx/ext/graphviz.py +10 -7
  82. sphinx/ext/ifconfig.py +5 -5
  83. sphinx/ext/imgconverter.py +6 -5
  84. sphinx/ext/imgmath.py +9 -8
  85. sphinx/ext/inheritance_diagram.py +31 -31
  86. sphinx/ext/intersphinx.py +140 -23
  87. sphinx/ext/linkcode.py +3 -2
  88. sphinx/ext/mathjax.py +2 -1
  89. sphinx/ext/napoleon/__init__.py +12 -7
  90. sphinx/ext/napoleon/docstring.py +34 -32
  91. sphinx/ext/todo.py +10 -7
  92. sphinx/ext/viewcode.py +12 -11
  93. sphinx/extension.py +18 -8
  94. sphinx/highlighting.py +39 -20
  95. sphinx/io.py +17 -8
  96. sphinx/jinja2glue.py +16 -15
  97. sphinx/locale/__init__.py +30 -23
  98. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
  100. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
  102. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
  104. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
  106. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
  108. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
  110. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
  112. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
  114. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
  116. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
  118. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
  120. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
  122. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
  124. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
  126. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
  128. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
  130. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
  132. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
  134. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
  136. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  137. sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
  138. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  139. sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
  140. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  141. sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
  142. sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
  143. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
  145. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
  147. sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
  148. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  149. sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
  150. sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
  151. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
  153. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
  155. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
  157. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
  159. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
  161. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
  163. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
  165. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
  167. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
  169. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
  171. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
  173. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
  175. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
  177. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
  179. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
  180. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  181. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
  182. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  183. sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
  184. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  185. sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
  186. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  187. sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
  188. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  189. sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
  190. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  191. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
  192. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
  194. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
  196. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
  198. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
  200. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
  202. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
  204. sphinx/locale/sphinx.pot +813 -755
  205. sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
  206. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
  208. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
  210. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  212. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
  214. sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
  215. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
  217. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
  219. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
  221. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
  223. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  224. sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
  225. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  226. sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
  227. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  228. sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
  229. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  230. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
  231. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  232. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
  233. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
  234. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
  236. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
  238. sphinx/parsers.py +7 -5
  239. sphinx/project.py +18 -11
  240. sphinx/pycode/__init__.py +6 -5
  241. sphinx/pycode/ast.py +23 -8
  242. sphinx/pycode/parser.py +6 -5
  243. sphinx/registry.py +12 -6
  244. sphinx/roles.py +103 -57
  245. sphinx/search/__init__.py +17 -18
  246. sphinx/search/da.py +2 -2
  247. sphinx/search/de.py +2 -2
  248. sphinx/search/en.py +1 -1
  249. sphinx/search/es.py +2 -2
  250. sphinx/search/fi.py +2 -2
  251. sphinx/search/fr.py +2 -2
  252. sphinx/search/hu.py +2 -2
  253. sphinx/search/it.py +2 -2
  254. sphinx/search/ja.py +13 -22
  255. sphinx/search/nl.py +2 -2
  256. sphinx/search/no.py +2 -2
  257. sphinx/search/pt.py +2 -2
  258. sphinx/search/ro.py +1 -1
  259. sphinx/search/ru.py +2 -2
  260. sphinx/search/sv.py +2 -2
  261. sphinx/search/tr.py +1 -1
  262. sphinx/search/zh.py +2 -3
  263. sphinx/templates/graphviz/graphviz.css +1 -1
  264. sphinx/testing/fixtures.py +41 -24
  265. sphinx/testing/path.py +1 -1
  266. sphinx/testing/util.py +142 -53
  267. sphinx/texinputs/sphinx.xdy +1 -1
  268. sphinx/texinputs/sphinxlatextables.sty +1 -1
  269. sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
  270. sphinx/themes/agogo/layout.html +4 -4
  271. sphinx/themes/agogo/static/agogo.css_t +1 -1
  272. sphinx/themes/agogo/theme.toml +22 -0
  273. sphinx/themes/basic/defindex.html +1 -1
  274. sphinx/themes/basic/domainindex.html +1 -1
  275. sphinx/themes/basic/genindex-single.html +1 -1
  276. sphinx/themes/basic/genindex-split.html +1 -1
  277. sphinx/themes/basic/genindex.html +1 -1
  278. sphinx/themes/basic/globaltoc.html +1 -1
  279. sphinx/themes/basic/layout.html +1 -1
  280. sphinx/themes/basic/localtoc.html +1 -1
  281. sphinx/themes/basic/page.html +1 -1
  282. sphinx/themes/basic/relations.html +1 -1
  283. sphinx/themes/basic/search.html +5 -20
  284. sphinx/themes/basic/searchbox.html +3 -3
  285. sphinx/themes/basic/searchfield.html +3 -3
  286. sphinx/themes/basic/sourcelink.html +1 -1
  287. sphinx/themes/basic/static/basic.css_t +1 -1
  288. sphinx/themes/basic/static/doctools.js +1 -1
  289. sphinx/themes/basic/static/language_data.js_t +2 -2
  290. sphinx/themes/basic/static/searchtools.js +105 -60
  291. sphinx/themes/basic/theme.toml +23 -0
  292. sphinx/themes/bizstyle/layout.html +1 -6
  293. sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
  294. sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
  295. sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
  296. sphinx/themes/bizstyle/theme.toml +12 -0
  297. sphinx/themes/classic/layout.html +1 -1
  298. sphinx/themes/classic/static/classic.css_t +1 -1
  299. sphinx/themes/classic/static/sidebar.js_t +1 -1
  300. sphinx/themes/classic/theme.toml +34 -0
  301. sphinx/themes/default/theme.toml +2 -0
  302. sphinx/themes/epub/epub-cover.html +1 -1
  303. sphinx/themes/epub/layout.html +1 -1
  304. sphinx/themes/epub/static/epub.css_t +1 -1
  305. sphinx/themes/epub/theme.toml +10 -0
  306. sphinx/themes/haiku/layout.html +3 -3
  307. sphinx/themes/haiku/static/haiku.css_t +2 -2
  308. sphinx/themes/haiku/theme.toml +16 -0
  309. sphinx/themes/nature/static/nature.css_t +1 -1
  310. sphinx/themes/nature/theme.toml +6 -0
  311. sphinx/themes/nonav/layout.html +1 -1
  312. sphinx/themes/nonav/static/nonav.css_t +1 -1
  313. sphinx/themes/nonav/theme.toml +10 -0
  314. sphinx/themes/pyramid/static/epub.css_t +1 -1
  315. sphinx/themes/pyramid/static/pyramid.css_t +1 -1
  316. sphinx/themes/pyramid/theme.toml +6 -0
  317. sphinx/themes/scrolls/artwork/logo.svg +1 -1
  318. sphinx/themes/scrolls/layout.html +2 -2
  319. sphinx/themes/scrolls/static/scrolls.css_t +1 -1
  320. sphinx/themes/scrolls/theme.toml +15 -0
  321. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
  322. sphinx/themes/sphinxdoc/theme.toml +6 -0
  323. sphinx/themes/traditional/static/traditional.css_t +1 -1
  324. sphinx/themes/traditional/theme.toml +9 -0
  325. sphinx/theming.py +427 -131
  326. sphinx/transforms/__init__.py +21 -24
  327. sphinx/transforms/compact_bullet_list.py +5 -5
  328. sphinx/transforms/i18n.py +30 -28
  329. sphinx/transforms/post_transforms/__init__.py +9 -7
  330. sphinx/transforms/post_transforms/code.py +4 -1
  331. sphinx/transforms/post_transforms/images.py +17 -13
  332. sphinx/transforms/references.py +3 -1
  333. sphinx/util/__init__.py +15 -11
  334. sphinx/util/_io.py +34 -0
  335. sphinx/util/_pathlib.py +23 -18
  336. sphinx/util/build_phase.py +1 -0
  337. sphinx/util/cfamily.py +19 -11
  338. sphinx/util/console.py +101 -21
  339. sphinx/util/display.py +3 -2
  340. sphinx/util/docfields.py +12 -8
  341. sphinx/util/docutils.py +21 -35
  342. sphinx/util/exceptions.py +3 -2
  343. sphinx/util/fileutil.py +5 -5
  344. sphinx/util/http_date.py +9 -2
  345. sphinx/util/i18n.py +40 -9
  346. sphinx/util/inspect.py +317 -245
  347. sphinx/util/inventory.py +22 -5
  348. sphinx/util/logging.py +81 -7
  349. sphinx/util/matching.py +2 -1
  350. sphinx/util/math.py +1 -2
  351. sphinx/util/nodes.py +39 -29
  352. sphinx/util/osutil.py +25 -6
  353. sphinx/util/parallel.py +6 -1
  354. sphinx/util/requests.py +8 -5
  355. sphinx/util/rst.py +8 -6
  356. sphinx/util/tags.py +3 -3
  357. sphinx/util/template.py +8 -3
  358. sphinx/util/typing.py +76 -42
  359. sphinx/versioning.py +6 -2
  360. sphinx/writers/html.py +1 -1
  361. sphinx/writers/html5.py +17 -13
  362. sphinx/writers/latex.py +12 -12
  363. sphinx/writers/manpage.py +13 -7
  364. sphinx/writers/texinfo.py +13 -10
  365. sphinx/writers/text.py +13 -23
  366. sphinx/writers/xml.py +1 -1
  367. sphinx-7.2.5.dist-info/LICENSE → sphinx-7.3.0.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/METADATA +13 -12
  369. sphinx-7.3.0.dist-info/RECORD +581 -0
  370. sphinx/domains/c.py +0 -3906
  371. sphinx/domains/cpp.py +0 -8233
  372. sphinx/domains/python.py +0 -1769
  373. sphinx/themes/agogo/theme.conf +0 -20
  374. sphinx/themes/basic/theme.conf +0 -16
  375. sphinx/themes/bizstyle/theme.conf +0 -10
  376. sphinx/themes/classic/theme.conf +0 -32
  377. sphinx/themes/default/theme.conf +0 -2
  378. sphinx/themes/epub/theme.conf +0 -8
  379. sphinx/themes/haiku/theme.conf +0 -14
  380. sphinx/themes/nature/theme.conf +0 -4
  381. sphinx/themes/nonav/theme.conf +0 -8
  382. sphinx/themes/pyramid/theme.conf +0 -4
  383. sphinx/themes/scrolls/theme.conf +0 -13
  384. sphinx/themes/sphinxdoc/theme.conf +0 -4
  385. sphinx/themes/traditional/theme.conf +0 -7
  386. sphinx-7.2.5.dist-info/RECORD +0 -569
  387. {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.5.dist-info → sphinx-7.3.0.dist-info}/entry_points.txt +0 -0
sphinx/util/__init__.py CHANGED
@@ -20,8 +20,8 @@ from sphinx.util import index_entries as _index_entries
20
20
  from sphinx.util import logging
21
21
  from sphinx.util import osutil as _osutil
22
22
  from sphinx.util.console import strip_colors # NoQA: F401
23
- from sphinx.util.matching import patfilter # noqa: F401
24
- from sphinx.util.nodes import ( # noqa: F401
23
+ from sphinx.util.matching import patfilter # NoQA: F401
24
+ from sphinx.util.nodes import ( # NoQA: F401
25
25
  caption_ref_re,
26
26
  explicit_title_re,
27
27
  nested_parse_with_titles,
@@ -30,7 +30,7 @@ from sphinx.util.nodes import ( # noqa: F401
30
30
 
31
31
  # import other utilities; partly for backwards compatibility, so don't
32
32
  # prune unused ones indiscriminately
33
- from sphinx.util.osutil import ( # noqa: F401
33
+ from sphinx.util.osutil import ( # NoQA: F401
34
34
  SEP,
35
35
  copyfile,
36
36
  copytimes,
@@ -68,6 +68,7 @@ class FilenameUniqDict(dict):
68
68
  interpreted as filenames, and keeps track of a set of docnames they
69
69
  appear in. Used for images and downloadable files in the environment.
70
70
  """
71
+
71
72
  def __init__(self) -> None:
72
73
  self._existing: set[str] = set()
73
74
 
@@ -104,7 +105,7 @@ class FilenameUniqDict(dict):
104
105
  self._existing = state
105
106
 
106
107
 
107
- def _md5(data=b'', **_kw):
108
+ def _md5(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
108
109
  """Deprecated wrapper around hashlib.md5
109
110
 
110
111
  To be removed in Sphinx 9.0
@@ -112,7 +113,7 @@ def _md5(data=b'', **_kw):
112
113
  return hashlib.md5(data, usedforsecurity=False)
113
114
 
114
115
 
115
- def _sha1(data=b'', **_kw):
116
+ def _sha1(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
116
117
  """Deprecated wrapper around hashlib.sha1
117
118
 
118
119
  To be removed in Sphinx 9.0
@@ -178,6 +179,7 @@ class Tee:
178
179
  """
179
180
  File-like object writing to two streams.
180
181
  """
182
+
181
183
  def __init__(self, stream1: IO, stream2: IO) -> None:
182
184
  self.stream1 = stream1
183
185
  self.stream2 = stream2
@@ -202,7 +204,7 @@ def parselinenos(spec: str, total: int) -> list[int]:
202
204
  for part in parts:
203
205
  try:
204
206
  begend = part.strip().split('-')
205
- if ['', ''] == begend:
207
+ if begend == ['', '']:
206
208
  raise ValueError
207
209
  if len(begend) == 1:
208
210
  items.append(int(begend[0]) - 1)
@@ -256,7 +258,7 @@ def isurl(url: str) -> bool:
256
258
  return bool(url) and '://' in url
257
259
 
258
260
 
259
- def _xml_name_checker():
261
+ def _xml_name_checker() -> re.Pattern[str]:
260
262
  # to prevent import cycles
261
263
  from sphinx.builders.epub3 import _XML_NAME_PATTERN
262
264
 
@@ -264,7 +266,7 @@ def _xml_name_checker():
264
266
 
265
267
 
266
268
  # deprecated name -> (object to return, canonical path or empty string)
267
- _DEPRECATED_OBJECTS = {
269
+ _DEPRECATED_OBJECTS: dict[str, tuple[Any, str] | tuple[Any, str, tuple[int, int]]] = {
268
270
  'path_stabilize': (_osutil.path_stabilize, 'sphinx.util.osutil.path_stabilize'),
269
271
  'display_chunk': (_display.display_chunk, 'sphinx.util.display.display_chunk'),
270
272
  'status_iterator': (_display.status_iterator, 'sphinx.util.display.status_iterator'),
@@ -285,13 +287,15 @@ _DEPRECATED_OBJECTS = {
285
287
  }
286
288
 
287
289
 
288
- def __getattr__(name):
290
+ def __getattr__(name: str) -> Any:
289
291
  if name not in _DEPRECATED_OBJECTS:
290
292
  msg = f'module {__name__!r} has no attribute {name!r}'
291
293
  raise AttributeError(msg)
292
294
 
293
295
  from sphinx.deprecation import _deprecation_warning
294
296
 
295
- deprecated_object, canonical_name = _DEPRECATED_OBJECTS[name]
296
- _deprecation_warning(__name__, name, canonical_name, remove=(8, 0))
297
+ info = _DEPRECATED_OBJECTS[name]
298
+ deprecated_object, canonical_name = info[:2]
299
+ remove = info[2] if len(info) == 3 else (8, 0)
300
+ _deprecation_warning(__name__, name, canonical_name, remove=remove)
297
301
  return deprecated_object
sphinx/util/_io.py ADDED
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from sphinx.util.console import strip_escape_sequences
6
+
7
+ if TYPE_CHECKING:
8
+ from typing import Protocol
9
+
10
+ class SupportsWrite(Protocol):
11
+ def write(self, text: str, /) -> int | None:
12
+ ...
13
+
14
+
15
+ class TeeStripANSI:
16
+ """File-like object writing to two streams."""
17
+
18
+ def __init__(
19
+ self,
20
+ stream_term: SupportsWrite,
21
+ stream_file: SupportsWrite,
22
+ ) -> None:
23
+ self.stream_term = stream_term
24
+ self.stream_file = stream_file
25
+
26
+ def write(self, text: str, /) -> None:
27
+ self.stream_term.write(text)
28
+ self.stream_file.write(strip_escape_sequences(text))
29
+
30
+ def flush(self) -> None:
31
+ if hasattr(self.stream_term, 'flush'):
32
+ self.stream_term.flush()
33
+ if hasattr(self.stream_file, 'flush'):
34
+ self.stream_file.flush()
sphinx/util/_pathlib.py CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import sys
6
6
  import warnings
7
7
  from pathlib import Path, PosixPath, PurePath, WindowsPath
8
+ from typing import Any
8
9
 
9
10
  from sphinx.deprecation import RemovedInSphinx80Warning
10
11
 
@@ -21,34 +22,36 @@ _MSG = (
21
22
 
22
23
  if sys.platform == 'win32':
23
24
  class _StrPath(WindowsPath):
24
- def replace(self, old, new, count=-1, /):
25
+ def replace( # type: ignore[override]
26
+ self, old: str, new: str, count: int = -1, /,
27
+ ) -> str:
25
28
  # replace exists in both Path and str;
26
29
  # in Path it makes filesystem changes, so we use the safer str version
27
30
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
28
31
  return self.__str__().replace(old, new, count)
29
32
 
30
- def __getattr__(self, item):
33
+ def __getattr__(self, item: str) -> Any:
31
34
  if item in _STR_METHODS:
32
35
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
33
36
  return getattr(self.__str__(), item)
34
37
  msg = f'{_PATH_NAME!r} has no attribute {item!r}'
35
38
  raise AttributeError(msg)
36
39
 
37
- def __add__(self, other):
40
+ def __add__(self, other: str) -> str:
38
41
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
39
42
  return self.__str__() + other
40
43
 
41
- def __bool__(self):
44
+ def __bool__(self) -> bool:
42
45
  if not self.__str__():
43
46
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
44
47
  return False
45
48
  return True
46
49
 
47
- def __contains__(self, item):
50
+ def __contains__(self, item: str) -> bool:
48
51
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
49
52
  return item in self.__str__()
50
53
 
51
- def __eq__(self, other):
54
+ def __eq__(self, other: object) -> bool:
52
55
  if isinstance(other, PurePath):
53
56
  return super().__eq__(other)
54
57
  if isinstance(other, str):
@@ -56,46 +59,48 @@ if sys.platform == 'win32':
56
59
  return self.__str__() == other
57
60
  return NotImplemented
58
61
 
59
- def __hash__(self):
62
+ def __hash__(self) -> int:
60
63
  return super().__hash__()
61
64
 
62
- def __getitem__(self, item):
65
+ def __getitem__(self, item: int | slice) -> str:
63
66
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
64
67
  return self.__str__()[item]
65
68
 
66
- def __len__(self):
69
+ def __len__(self) -> int:
67
70
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
68
71
  return len(self.__str__())
69
72
  else:
70
73
  class _StrPath(PosixPath):
71
- def replace(self, old, new, count=-1, /):
74
+ def replace( # type: ignore[override]
75
+ self, old: str, new: str, count: int = -1, /,
76
+ ) -> str:
72
77
  # replace exists in both Path and str;
73
78
  # in Path it makes filesystem changes, so we use the safer str version
74
79
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
75
80
  return self.__str__().replace(old, new, count)
76
81
 
77
- def __getattr__(self, item):
82
+ def __getattr__(self, item: str) -> Any:
78
83
  if item in _STR_METHODS:
79
84
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
80
85
  return getattr(self.__str__(), item)
81
86
  msg = f'{_PATH_NAME!r} has no attribute {item!r}'
82
87
  raise AttributeError(msg)
83
88
 
84
- def __add__(self, other):
89
+ def __add__(self, other: str) -> str:
85
90
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
86
91
  return self.__str__() + other
87
92
 
88
- def __bool__(self):
93
+ def __bool__(self) -> bool:
89
94
  if not self.__str__():
90
95
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
91
96
  return False
92
97
  return True
93
98
 
94
- def __contains__(self, item):
99
+ def __contains__(self, item: str) -> bool:
95
100
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
96
101
  return item in self.__str__()
97
102
 
98
- def __eq__(self, other):
103
+ def __eq__(self, other: object) -> bool:
99
104
  if isinstance(other, PurePath):
100
105
  return super().__eq__(other)
101
106
  if isinstance(other, str):
@@ -103,13 +108,13 @@ else:
103
108
  return self.__str__() == other
104
109
  return NotImplemented
105
110
 
106
- def __hash__(self):
111
+ def __hash__(self) -> int:
107
112
  return super().__hash__()
108
113
 
109
- def __getitem__(self, item):
114
+ def __getitem__(self, item: int | slice) -> str:
110
115
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
111
116
  return self.__str__()[item]
112
117
 
113
- def __len__(self):
118
+ def __len__(self) -> int:
114
119
  warnings.warn(_MSG, RemovedInSphinx80Warning, stacklevel=2)
115
120
  return len(self.__str__())
@@ -5,6 +5,7 @@ from enum import IntEnum
5
5
 
6
6
  class BuildPhase(IntEnum):
7
7
  """Build phase of Sphinx application."""
8
+
8
9
  INITIALIZATION = 1
9
10
  READING = 2
10
11
  CONSISTENCY_CHECK = 3
sphinx/util/cfamily.py CHANGED
@@ -12,6 +12,8 @@ from sphinx import addnodes
12
12
  from sphinx.util import logging
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from collections.abc import Sequence
16
+
15
17
  from docutils.nodes import TextElement
16
18
 
17
19
  from sphinx.config import Config
@@ -86,7 +88,7 @@ class NoOldIdError(Exception):
86
88
 
87
89
 
88
90
  class ASTBaseBase:
89
- def __eq__(self, other: Any) -> bool:
91
+ def __eq__(self, other: object) -> bool:
90
92
  if type(self) is not type(other):
91
93
  return False
92
94
  try:
@@ -107,7 +109,7 @@ class ASTBaseBase:
107
109
  raise NotImplementedError(repr(self))
108
110
 
109
111
  def __str__(self) -> str:
110
- return self._stringify(lambda ast: str(ast))
112
+ return self._stringify(str)
111
113
 
112
114
  def get_display_string(self) -> str:
113
115
  return self._stringify(lambda ast: ast.get_display_string())
@@ -143,6 +145,11 @@ class ASTGnuAttribute(ASTBaseBase):
143
145
  self.name = name
144
146
  self.args = args
145
147
 
148
+ def __eq__(self, other: object) -> bool:
149
+ if type(other) is not ASTGnuAttribute:
150
+ return NotImplemented
151
+ return self.name == other.name and self.args == other.args
152
+
146
153
  def _stringify(self, transform: StringifyTransform) -> str:
147
154
  res = [self.name]
148
155
  if self.args:
@@ -202,6 +209,11 @@ class ASTAttributeList(ASTBaseBase):
202
209
  def __init__(self, attrs: list[ASTAttribute]) -> None:
203
210
  self.attrs = attrs
204
211
 
212
+ def __eq__(self, other: object) -> bool:
213
+ if type(other) is not ASTAttributeList:
214
+ return NotImplemented
215
+ return self.attrs == other.attrs
216
+
205
217
  def __len__(self) -> int:
206
218
  return len(self.attrs)
207
219
 
@@ -265,14 +277,11 @@ class BaseParser:
265
277
  for e in errors:
266
278
  if len(e[1]) > 0:
267
279
  indent = ' '
268
- result.append(e[1])
269
- result.append(':\n')
280
+ result.extend((e[1], ':\n'))
270
281
  for line in str(e[0]).split('\n'):
271
282
  if len(line) == 0:
272
283
  continue
273
- result.append(indent)
274
- result.append(line)
275
- result.append('\n')
284
+ result.extend((indent, line, '\n'))
276
285
  else:
277
286
  result.append(str(e[0]))
278
287
  return DefinitionError(''.join(result))
@@ -293,8 +302,7 @@ class BaseParser:
293
302
  'Invalid %s declaration: %s [error at %d]\n %s\n %s' %
294
303
  (self.language, msg, self.pos, self.definition, indicator))
295
304
  errors.append((exMain, "Main error"))
296
- for err in self.otherErrors:
297
- errors.append((err, "Potential other error"))
305
+ errors.extend((err, "Potential other error") for err in self.otherErrors)
298
306
  self.otherErrors = []
299
307
  raise self._make_multi_error(errors, '')
300
308
 
@@ -369,11 +377,11 @@ class BaseParser:
369
377
  ################################################################################
370
378
 
371
379
  @property
372
- def id_attributes(self):
380
+ def id_attributes(self) -> Sequence[str]:
373
381
  raise NotImplementedError
374
382
 
375
383
  @property
376
- def paren_attributes(self):
384
+ def paren_attributes(self) -> Sequence[str]:
377
385
  raise NotImplementedError
378
386
 
379
387
  def _parse_balanced_token_seq(self, end: list[str]) -> str:
sphinx/util/console.py CHANGED
@@ -6,6 +6,37 @@ import os
6
6
  import re
7
7
  import shutil
8
8
  import sys
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from typing import Final
13
+
14
+ # fmt: off
15
+ def reset(text: str) -> str: ... # NoQA: E704
16
+ def bold(text: str) -> str: ... # NoQA: E704
17
+ def faint(text: str) -> str: ... # NoQA: E704
18
+ def standout(text: str) -> str: ... # NoQA: E704
19
+ def underline(text: str) -> str: ... # NoQA: E704
20
+ def blink(text: str) -> str: ... # NoQA: E704
21
+
22
+ def black(text: str) -> str: ... # NoQA: E704
23
+ def white(text: str) -> str: ... # NoQA: E704
24
+ def red(text: str) -> str: ... # NoQA: E704
25
+ def green(text: str) -> str: ... # NoQA: E704
26
+ def yellow(text: str) -> str: ... # NoQA: E704
27
+ def blue(text: str) -> str: ... # NoQA: E704
28
+ def fuchsia(text: str) -> str: ... # NoQA: E704
29
+ def teal(text: str) -> str: ... # NoQA: E704
30
+
31
+ def darkgray(text: str) -> str: ... # NoQA: E704
32
+ def lightgray(text: str) -> str: ... # NoQA: E704
33
+ def darkred(text: str) -> str: ... # NoQA: E704
34
+ def darkgreen(text: str) -> str: ... # NoQA: E704
35
+ def brown(text: str) -> str: ... # NoQA: E704
36
+ def darkblue(text: str) -> str: ... # NoQA: E704
37
+ def purple(text: str) -> str: ... # NoQA: E704
38
+ def turquoise(text: str) -> str: ... # NoQA: E704
39
+ # fmt: on
9
40
 
10
41
  try:
11
42
  # check if colorama is installed to support color on Windows
@@ -13,8 +44,26 @@ try:
13
44
  except ImportError:
14
45
  colorama = None
15
46
 
47
+ _CSI: Final[str] = re.escape('\x1b[') # 'ESC [': Control Sequence Introducer
48
+
49
+ # Pattern matching ANSI control sequences containing colors.
50
+ _ansi_color_re: Final[re.Pattern[str]] = re.compile(r'\x1b\[(?:\d+;){0,2}\d*m')
51
+
52
+ _ansi_re: Final[re.Pattern[str]] = re.compile(
53
+ _CSI
54
+ + r"""
55
+ (?:
56
+ (?:\d+;){0,2}\d*m # ANSI color code ('m' is equivalent to '0m')
57
+ |
58
+ [012]?K # ANSI Erase in Line ('K' is equivalent to '0K')
59
+ )""",
60
+ re.VERBOSE | re.ASCII,
61
+ )
62
+ """Pattern matching ANSI CSI colors (SGR) and erase line (EL) sequences.
63
+
64
+ See :func:`strip_escape_sequences` for details.
65
+ """
16
66
 
17
- _ansi_re: re.Pattern[str] = re.compile('\x1b\\[(\\d\\d;){0,2}\\d\\dm')
18
67
  codes: dict[str, str] = {}
19
68
 
20
69
 
@@ -37,7 +86,7 @@ def term_width_line(text: str) -> str:
37
86
  return text + '\n'
38
87
  else:
39
88
  # codes are not displayed, this must be taken into account
40
- return text.ljust(_tw + len(text) - len(_ansi_re.sub('', text))) + '\r'
89
+ return text.ljust(_tw + len(text) - len(strip_escape_sequences(text))) + '\r'
41
90
 
42
91
 
43
92
  def color_terminal() -> bool:
@@ -55,9 +104,7 @@ def color_terminal() -> bool:
55
104
  if 'COLORTERM' in os.environ:
56
105
  return True
57
106
  term = os.environ.get('TERM', 'dumb').lower()
58
- if term in ('xterm', 'linux') or 'color' in term:
59
- return True
60
- return False
107
+ return term in ('xterm', 'linux') or 'color' in term
61
108
 
62
109
 
63
110
  def nocolor() -> None:
@@ -87,41 +134,74 @@ def colorize(name: str, text: str, input_mode: bool = False) -> str:
87
134
 
88
135
 
89
136
  def strip_colors(s: str) -> str:
90
- return re.compile('\x1b.*?m').sub('', s)
137
+ """Remove the ANSI color codes in a string *s*.
138
+
139
+ .. caution::
140
+
141
+ This function is not meant to be used in production and should only
142
+ be used for testing Sphinx's output messages.
143
+
144
+ .. seealso:: :func:`strip_escape_sequences`
145
+ """
146
+ return _ansi_color_re.sub('', s)
147
+
148
+
149
+ def strip_escape_sequences(text: str, /) -> str:
150
+ r"""Remove the ANSI CSI colors and "erase in line" sequences.
151
+
152
+ Other `escape sequences `__ (e.g., VT100-specific functions) are not
153
+ supported and only control sequences *natively* known to Sphinx (i.e.,
154
+ colors declared in this module and "erase entire line" (``'\x1b[2K'``))
155
+ are eliminated by this function.
156
+
157
+ .. caution::
158
+
159
+ This function is not meant to be used in production and should only
160
+ be used for testing Sphinx's output messages that were not tempered
161
+ with by third-party extensions.
162
+
163
+ .. versionadded:: 7.3
164
+
165
+ This function is added as an *experimental* feature.
166
+
167
+ __ https://en.wikipedia.org/wiki/ANSI_escape_code
168
+ """
169
+ return _ansi_re.sub('', text)
91
170
 
92
171
 
93
172
  def create_color_func(name: str) -> None:
94
173
  def inner(text: str) -> str:
95
174
  return colorize(name, text)
175
+
96
176
  globals()[name] = inner
97
177
 
98
178
 
99
179
  _attrs = {
100
- 'reset': '39;49;00m',
101
- 'bold': '01m',
102
- 'faint': '02m',
103
- 'standout': '03m',
180
+ 'reset': '39;49;00m',
181
+ 'bold': '01m',
182
+ 'faint': '02m',
183
+ 'standout': '03m',
104
184
  'underline': '04m',
105
- 'blink': '05m',
185
+ 'blink': '05m',
106
186
  }
107
187
 
108
- for _name, _value in _attrs.items():
109
- codes[_name] = '\x1b[' + _value
188
+ for __name, __value in _attrs.items():
189
+ codes[__name] = '\x1b[' + __value
110
190
 
111
191
  _colors = [
112
- ('black', 'darkgray'),
113
- ('darkred', 'red'),
192
+ ('black', 'darkgray'),
193
+ ('darkred', 'red'),
114
194
  ('darkgreen', 'green'),
115
- ('brown', 'yellow'),
116
- ('darkblue', 'blue'),
117
- ('purple', 'fuchsia'),
195
+ ('brown', 'yellow'),
196
+ ('darkblue', 'blue'),
197
+ ('purple', 'fuchsia'),
118
198
  ('turquoise', 'teal'),
119
199
  ('lightgray', 'white'),
120
200
  ]
121
201
 
122
- for i, (dark, light) in enumerate(_colors, 30):
123
- codes[dark] = '\x1b[%im' % i
124
- codes[light] = '\x1b[%im' % (i + 60)
202
+ for __i, (__dark, __light) in enumerate(_colors, 30):
203
+ codes[__dark] = '\x1b[%im' % __i
204
+ codes[__light] = '\x1b[%im' % (__i + 60)
125
205
 
126
206
  _orig_codes = codes.copy()
127
207
 
sphinx/util/display.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any, Callable, TypeVar
5
5
 
6
6
  from sphinx.locale import __
7
7
  from sphinx.util import logging
8
- from sphinx.util.console import bold # type: ignore[attr-defined]
8
+ from sphinx.util.console import bold, color_terminal
9
9
 
10
10
  if False:
11
11
  from collections.abc import Iterable, Iterator
@@ -33,7 +33,8 @@ def status_iterator(
33
33
  verbosity: int = 0,
34
34
  stringify_func: Callable[[Any], str] = display_chunk,
35
35
  ) -> Iterator[T]:
36
- single_line = verbosity < 1
36
+ # printing on a single line requires ANSI control sequences
37
+ single_line = verbosity < 1 and color_terminal()
37
38
  bold_summary = bold(summary)
38
39
  if length == 0:
39
40
  logger.info(bold_summary, nonl=True)
sphinx/util/docfields.py CHANGED
@@ -34,9 +34,7 @@ def _is_single_paragraph(node: nodes.field_body) -> bool:
34
34
  for subnode in node[1:]: # type: Node
35
35
  if not isinstance(subnode, nodes.system_message):
36
36
  return False
37
- if isinstance(node[0], nodes.paragraph):
38
- return True
39
- return False
37
+ return isinstance(node[0], nodes.paragraph)
40
38
 
41
39
 
42
40
  class Field:
@@ -52,6 +50,7 @@ class Field:
52
50
  :returns: description of the return value
53
51
  :rtype: description of the return type
54
52
  """
53
+
55
54
  is_grouped = False
56
55
  is_typed = False
57
56
 
@@ -79,7 +78,7 @@ class Field:
79
78
  assert env is not None
80
79
  assert (inliner is None) == (location is None), (inliner, location)
81
80
  if not rolename:
82
- return contnode or innernode(target, target)
81
+ return contnode or innernode(target, target) # type: ignore[call-arg]
83
82
  # The domain is passed from DocFieldTransformer. So it surely exists.
84
83
  # So we don't need to take care the env.get_domain() raises an exception.
85
84
  role = env.get_domain(domain).role(rolename)
@@ -90,7 +89,7 @@ class Field:
90
89
  logger.warning(__(msg), domain, rolename, location=location)
91
90
  refnode = addnodes.pending_xref('', refdomain=domain, refexplicit=False,
92
91
  reftype=rolename, reftarget=target)
93
- refnode += contnode or innernode(target, target)
92
+ refnode += contnode or innernode(target, target) # type: ignore[call-arg]
94
93
  env.get_domain(domain).process_field_xref(refnode)
95
94
  return refnode
96
95
  lineno = -1
@@ -152,6 +151,7 @@ class GroupedField(Field):
152
151
 
153
152
  :raises ErrorClass: description when it is raised
154
153
  """
154
+
155
155
  is_grouped = True
156
156
  list_type = nodes.bullet_list
157
157
 
@@ -208,6 +208,7 @@ class TypedField(GroupedField):
208
208
 
209
209
  :param SomeClass foo: description of parameter foo
210
210
  """
211
+
211
212
  is_typed = True
212
213
 
213
214
  def __init__(
@@ -233,7 +234,7 @@ class TypedField(GroupedField):
233
234
  inliner: Inliner | None = None,
234
235
  location: Element | None = None,
235
236
  ) -> nodes.field:
236
- def handle_item(fieldarg: str, content: str) -> nodes.paragraph:
237
+ def handle_item(fieldarg: str, content: list[Node]) -> nodes.paragraph:
237
238
  par = nodes.paragraph()
238
239
  par.extend(self.make_xrefs(self.rolename, domain, fieldarg,
239
240
  addnodes.literal_strong, env=env))
@@ -251,8 +252,10 @@ class TypedField(GroupedField):
251
252
  else:
252
253
  par += fieldtype
253
254
  par += nodes.Text(')')
254
- par += nodes.Text(' -- ')
255
- par += content
255
+ has_content = any(c.astext().strip() for c in content)
256
+ if has_content:
257
+ par += nodes.Text(' -- ')
258
+ par += content
256
259
  return par
257
260
 
258
261
  fieldname = nodes.field_name('', self.label)
@@ -272,6 +275,7 @@ class DocFieldTransformer:
272
275
  Transforms field lists in "doc field" syntax into better-looking
273
276
  equivalents, using the field type definitions given on a domain.
274
277
  """
278
+
275
279
  typemap: dict[str, tuple[Field, bool]]
276
280
 
277
281
  def __init__(self, directive: ObjectDescription) -> None: