Sphinx 8.1.3__py3-none-any.whl → 8.2.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 (328) hide show
  1. sphinx/__init__.py +8 -4
  2. sphinx/__main__.py +2 -0
  3. sphinx/_cli/__init__.py +2 -5
  4. sphinx/_cli/util/colour.py +34 -11
  5. sphinx/_cli/util/errors.py +128 -61
  6. sphinx/addnodes.py +51 -35
  7. sphinx/application.py +362 -230
  8. sphinx/builders/__init__.py +87 -64
  9. sphinx/builders/_epub_base.py +65 -56
  10. sphinx/builders/changes.py +17 -23
  11. sphinx/builders/dirhtml.py +8 -13
  12. sphinx/builders/epub3.py +70 -38
  13. sphinx/builders/gettext.py +93 -73
  14. sphinx/builders/html/__init__.py +240 -186
  15. sphinx/builders/html/_assets.py +9 -2
  16. sphinx/builders/html/_build_info.py +3 -0
  17. sphinx/builders/latex/__init__.py +64 -54
  18. sphinx/builders/latex/constants.py +14 -11
  19. sphinx/builders/latex/nodes.py +2 -0
  20. sphinx/builders/latex/theming.py +8 -9
  21. sphinx/builders/latex/transforms.py +7 -5
  22. sphinx/builders/linkcheck.py +193 -149
  23. sphinx/builders/manpage.py +17 -17
  24. sphinx/builders/singlehtml.py +28 -16
  25. sphinx/builders/texinfo.py +28 -21
  26. sphinx/builders/text.py +10 -15
  27. sphinx/builders/xml.py +10 -19
  28. sphinx/cmd/build.py +49 -119
  29. sphinx/cmd/make_mode.py +35 -31
  30. sphinx/cmd/quickstart.py +78 -62
  31. sphinx/config.py +265 -163
  32. sphinx/directives/__init__.py +51 -54
  33. sphinx/directives/admonitions.py +107 -0
  34. sphinx/directives/code.py +24 -19
  35. sphinx/directives/other.py +21 -42
  36. sphinx/directives/patches.py +28 -16
  37. sphinx/domains/__init__.py +54 -31
  38. sphinx/domains/_domains_container.py +22 -17
  39. sphinx/domains/_index.py +5 -8
  40. sphinx/domains/c/__init__.py +366 -245
  41. sphinx/domains/c/_ast.py +378 -256
  42. sphinx/domains/c/_ids.py +89 -31
  43. sphinx/domains/c/_parser.py +283 -214
  44. sphinx/domains/c/_symbol.py +269 -198
  45. sphinx/domains/changeset.py +39 -24
  46. sphinx/domains/citation.py +54 -24
  47. sphinx/domains/cpp/__init__.py +517 -362
  48. sphinx/domains/cpp/_ast.py +999 -682
  49. sphinx/domains/cpp/_ids.py +133 -65
  50. sphinx/domains/cpp/_parser.py +746 -588
  51. sphinx/domains/cpp/_symbol.py +692 -489
  52. sphinx/domains/index.py +10 -8
  53. sphinx/domains/javascript.py +152 -74
  54. sphinx/domains/math.py +50 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +134 -61
  57. sphinx/domains/python/_object.py +155 -68
  58. sphinx/domains/rst.py +94 -49
  59. sphinx/domains/std/__init__.py +510 -249
  60. sphinx/environment/__init__.py +345 -61
  61. sphinx/environment/adapters/asset.py +7 -1
  62. sphinx/environment/adapters/indexentries.py +15 -20
  63. sphinx/environment/adapters/toctree.py +19 -9
  64. sphinx/environment/collectors/__init__.py +3 -1
  65. sphinx/environment/collectors/asset.py +18 -15
  66. sphinx/environment/collectors/dependencies.py +8 -10
  67. sphinx/environment/collectors/metadata.py +6 -4
  68. sphinx/environment/collectors/title.py +3 -1
  69. sphinx/environment/collectors/toctree.py +4 -4
  70. sphinx/errors.py +1 -3
  71. sphinx/events.py +4 -4
  72. sphinx/ext/apidoc/__init__.py +66 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_extension.py +262 -0
  76. sphinx/ext/apidoc/_generate.py +356 -0
  77. sphinx/ext/apidoc/_shared.py +99 -0
  78. sphinx/ext/autodoc/__init__.py +829 -480
  79. sphinx/ext/autodoc/directive.py +57 -21
  80. sphinx/ext/autodoc/importer.py +184 -67
  81. sphinx/ext/autodoc/mock.py +25 -10
  82. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  83. sphinx/ext/autodoc/type_comment.py +56 -29
  84. sphinx/ext/autodoc/typehints.py +49 -26
  85. sphinx/ext/autosectionlabel.py +28 -11
  86. sphinx/ext/autosummary/__init__.py +281 -142
  87. sphinx/ext/autosummary/generate.py +121 -51
  88. sphinx/ext/coverage.py +152 -91
  89. sphinx/ext/doctest.py +169 -101
  90. sphinx/ext/duration.py +12 -6
  91. sphinx/ext/extlinks.py +33 -21
  92. sphinx/ext/githubpages.py +8 -8
  93. sphinx/ext/graphviz.py +175 -109
  94. sphinx/ext/ifconfig.py +11 -6
  95. sphinx/ext/imgconverter.py +48 -25
  96. sphinx/ext/imgmath.py +127 -97
  97. sphinx/ext/inheritance_diagram.py +177 -103
  98. sphinx/ext/intersphinx/__init__.py +22 -13
  99. sphinx/ext/intersphinx/__main__.py +3 -1
  100. sphinx/ext/intersphinx/_cli.py +18 -14
  101. sphinx/ext/intersphinx/_load.py +91 -82
  102. sphinx/ext/intersphinx/_resolve.py +108 -74
  103. sphinx/ext/intersphinx/_shared.py +2 -2
  104. sphinx/ext/linkcode.py +28 -12
  105. sphinx/ext/mathjax.py +60 -29
  106. sphinx/ext/napoleon/__init__.py +19 -7
  107. sphinx/ext/napoleon/docstring.py +229 -231
  108. sphinx/ext/todo.py +44 -49
  109. sphinx/ext/viewcode.py +105 -57
  110. sphinx/extension.py +3 -1
  111. sphinx/highlighting.py +13 -7
  112. sphinx/io.py +9 -13
  113. sphinx/jinja2glue.py +29 -26
  114. sphinx/locale/__init__.py +8 -9
  115. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  116. sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
  117. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  118. sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
  119. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  120. sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
  121. sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
  122. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
  124. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
  125. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
  126. sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
  127. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  128. sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
  129. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  130. sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
  131. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  132. sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
  133. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  134. sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
  135. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  136. sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
  137. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  138. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
  139. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  140. sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
  141. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  142. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
  143. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
  145. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
  147. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  148. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
  149. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  150. sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
  151. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
  153. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
  155. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
  157. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
  159. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
  161. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
  163. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
  165. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
  167. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
  169. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
  171. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
  173. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
  175. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
  177. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
  179. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  180. sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
  181. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  182. sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
  183. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  184. sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
  185. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  186. sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
  187. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  188. sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
  189. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  190. sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
  191. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  192. sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
  193. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  194. sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
  195. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  196. sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
  197. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  198. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
  199. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  200. sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
  201. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  202. sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
  203. sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
  204. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  205. sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
  206. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
  208. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
  210. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
  212. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
  214. sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
  215. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
  217. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
  219. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
  221. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
  223. sphinx/locale/sphinx.pot +2069 -1964
  224. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  225. sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
  226. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  227. sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
  228. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  229. sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
  230. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  231. sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
  232. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  233. sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
  234. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
  236. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
  238. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  239. sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
  240. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  241. sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
  242. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  243. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
  244. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  245. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
  246. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  247. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
  248. sphinx/parsers.py +8 -7
  249. sphinx/project.py +2 -2
  250. sphinx/pycode/__init__.py +31 -21
  251. sphinx/pycode/ast.py +6 -3
  252. sphinx/pycode/parser.py +14 -8
  253. sphinx/pygments_styles.py +4 -5
  254. sphinx/registry.py +192 -92
  255. sphinx/roles.py +58 -7
  256. sphinx/search/__init__.py +75 -54
  257. sphinx/search/en.py +11 -13
  258. sphinx/search/fi.py +1 -1
  259. sphinx/search/ja.py +8 -6
  260. sphinx/search/nl.py +1 -1
  261. sphinx/search/zh.py +19 -21
  262. sphinx/testing/fixtures.py +26 -29
  263. sphinx/testing/path.py +26 -62
  264. sphinx/testing/restructuredtext.py +14 -8
  265. sphinx/testing/util.py +21 -19
  266. sphinx/texinputs/make.bat.jinja +50 -50
  267. sphinx/texinputs/sphinx.sty +4 -3
  268. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  269. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  270. sphinx/themes/basic/static/searchtools.js +8 -5
  271. sphinx/theming.py +49 -61
  272. sphinx/transforms/__init__.py +17 -38
  273. sphinx/transforms/compact_bullet_list.py +5 -3
  274. sphinx/transforms/i18n.py +8 -21
  275. sphinx/transforms/post_transforms/__init__.py +142 -93
  276. sphinx/transforms/post_transforms/code.py +5 -5
  277. sphinx/transforms/post_transforms/images.py +28 -24
  278. sphinx/transforms/references.py +3 -1
  279. sphinx/util/__init__.py +109 -60
  280. sphinx/util/_files.py +39 -23
  281. sphinx/util/_importer.py +4 -1
  282. sphinx/util/_inventory_file_reader.py +76 -0
  283. sphinx/util/_io.py +2 -2
  284. sphinx/util/_lines.py +6 -3
  285. sphinx/util/_pathlib.py +40 -2
  286. sphinx/util/build_phase.py +2 -0
  287. sphinx/util/cfamily.py +19 -14
  288. sphinx/util/console.py +44 -179
  289. sphinx/util/display.py +9 -10
  290. sphinx/util/docfields.py +140 -122
  291. sphinx/util/docstrings.py +1 -1
  292. sphinx/util/docutils.py +118 -77
  293. sphinx/util/fileutil.py +25 -26
  294. sphinx/util/http_date.py +2 -0
  295. sphinx/util/i18n.py +77 -64
  296. sphinx/util/images.py +8 -6
  297. sphinx/util/inspect.py +147 -38
  298. sphinx/util/inventory.py +215 -116
  299. sphinx/util/logging.py +33 -33
  300. sphinx/util/matching.py +12 -4
  301. sphinx/util/nodes.py +18 -13
  302. sphinx/util/osutil.py +38 -39
  303. sphinx/util/parallel.py +22 -13
  304. sphinx/util/parsing.py +2 -1
  305. sphinx/util/png.py +6 -2
  306. sphinx/util/requests.py +33 -2
  307. sphinx/util/rst.py +3 -2
  308. sphinx/util/tags.py +1 -1
  309. sphinx/util/template.py +18 -10
  310. sphinx/util/texescape.py +8 -6
  311. sphinx/util/typing.py +148 -122
  312. sphinx/versioning.py +3 -3
  313. sphinx/writers/html.py +3 -1
  314. sphinx/writers/html5.py +63 -52
  315. sphinx/writers/latex.py +83 -67
  316. sphinx/writers/manpage.py +19 -38
  317. sphinx/writers/texinfo.py +47 -47
  318. sphinx/writers/text.py +50 -32
  319. sphinx/writers/xml.py +11 -8
  320. {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
  321. {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
  322. sphinx-8.2.0.dist-info/RECORD +606 -0
  323. {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
  324. sphinx/builders/html/transforms.py +0 -90
  325. sphinx/ext/apidoc.py +0 -721
  326. sphinx/util/exceptions.py +0 -74
  327. sphinx-8.1.3.dist-info/RECORD +0 -598
  328. {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
sphinx/writers/texinfo.py CHANGED
@@ -2,16 +2,14 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import os.path
5
6
  import re
6
7
  import textwrap
7
- from collections.abc import Iterable, Iterator
8
- from os import path
9
- from typing import TYPE_CHECKING, Any, ClassVar, cast
8
+ from typing import TYPE_CHECKING, cast
10
9
 
11
10
  from docutils import nodes, writers
12
11
 
13
12
  from sphinx import __display_version__, addnodes
14
- from sphinx.errors import ExtensionError
15
13
  from sphinx.locale import _, __, admonitionlabels
16
14
  from sphinx.util import logging
17
15
  from sphinx.util.docutils import SphinxTranslator
@@ -19,6 +17,9 @@ from sphinx.util.i18n import format_date
19
17
  from sphinx.writers.latex import collected_footnote
20
18
 
21
19
  if TYPE_CHECKING:
20
+ from collections.abc import Iterable, Iterator
21
+ from typing import Any, ClassVar
22
+
22
23
  from docutils.nodes import Element, Node, Text
23
24
 
24
25
  from sphinx.builders.texinfo import TexinfoBuilder
@@ -133,7 +134,7 @@ class TexinfoWriter(writers.Writer): # type: ignore[type-arg]
133
134
  def translate(self) -> None:
134
135
  assert isinstance(self.document, nodes.document)
135
136
  visitor = self.builder.create_translator(self.document, self.builder)
136
- self.visitor = cast(TexinfoTranslator, visitor)
137
+ self.visitor = cast('TexinfoTranslator', visitor)
137
138
  self.document.walkabout(visitor)
138
139
  self.visitor.finish()
139
140
  for attr in self.visitor_attributes:
@@ -188,6 +189,7 @@ class TexinfoTranslator(SphinxTranslator):
188
189
  self.escape_hyphens = 0
189
190
  self.curfilestack: list[str] = []
190
191
  self.footnotestack: list[dict[str, list[collected_footnote | bool]]] = []
192
+ self.in_production_list = False
191
193
  self.in_footnote = 0
192
194
  self.in_samp = 0
193
195
  self.handled_abbrs: set[str] = set()
@@ -240,7 +242,7 @@ class TexinfoTranslator(SphinxTranslator):
240
242
  # filename
241
243
  if not elements['filename']:
242
244
  elements['filename'] = self.document.get('source') or 'untitled'
243
- if elements['filename'][-4:] in ('.txt', '.rst'): # type: ignore[index]
245
+ if elements['filename'][-4:] in {'.txt', '.rst'}: # type: ignore[index]
244
246
  elements['filename'] = elements['filename'][:-4] # type: ignore[index]
245
247
  elements['filename'] += '.info' # type: ignore[operator]
246
248
  # direntry
@@ -250,9 +252,10 @@ class TexinfoTranslator(SphinxTranslator):
250
252
  '(%s)' % elements['filename'],
251
253
  self.escape_arg(self.settings.texinfo_dir_description),
252
254
  )
253
- elements['direntry'] = (
254
- '@dircategory %s\n' '@direntry\n' '%s' '@end direntry\n'
255
- ) % (self.escape_id(self.settings.texinfo_dir_category), entry)
255
+ elements['direntry'] = '@dircategory %s\n@direntry\n%s@end direntry\n' % (
256
+ self.escape_id(self.settings.texinfo_dir_category),
257
+ entry,
258
+ )
256
259
  elements['copying'] = COPYING % elements
257
260
  # allow the user to override them all
258
261
  elements.update(self.settings.texinfo_elements)
@@ -287,7 +290,7 @@ class TexinfoTranslator(SphinxTranslator):
287
290
  ]
288
291
  # each section is also a node
289
292
  for section in self.document.findall(nodes.section):
290
- title = cast(nodes.TextElement, section.next_node(nodes.Titular)) # type: ignore[type-var]
293
+ title = cast('nodes.TextElement', section.next_node(nodes.Titular)) # type: ignore[type-var]
291
294
  name = title.astext() if title else '<untitled>'
292
295
  section['node_name'] = add_node_name(name)
293
296
 
@@ -448,10 +451,10 @@ class TexinfoTranslator(SphinxTranslator):
448
451
  for subentry in entries:
449
452
  _add_detailed_menu(subentry)
450
453
 
451
- self.body.append('\n@detailmenu\n' ' --- The Detailed Node Listing ---\n')
454
+ self.body.append('\n@detailmenu\n --- The Detailed Node Listing ---\n')
452
455
  for entry in entries:
453
456
  _add_detailed_menu(entry)
454
- self.body.append('\n@end detailmenu\n' '@end menu\n')
457
+ self.body.append('\n@end detailmenu\n@end menu\n')
455
458
 
456
459
  def tex_image_length(self, width_str: str) -> str:
457
460
  match = re.match(r'(\d*\.?\d*)\s*(\S*)', width_str)
@@ -491,7 +494,7 @@ class TexinfoTranslator(SphinxTranslator):
491
494
  indices_config = frozenset(indices_config)
492
495
  else:
493
496
  check_names = False
494
- for domain in self.builder.env.domains.sorted():
497
+ for domain in self._domains.sorted():
495
498
  for index_cls in domain.indices:
496
499
  index_name = f'{domain.name}-{index_cls.name}'
497
500
  if check_names and index_name not in indices_config:
@@ -505,7 +508,7 @@ class TexinfoTranslator(SphinxTranslator):
505
508
  generate(content, collapsed),
506
509
  ))
507
510
  # only add the main Index if it's not empty
508
- domain = self.builder.env.domains.index_domain
511
+ domain = self._domains.index_domain
509
512
  for docname in self.builder.docnames:
510
513
  if domain.entries[docname]:
511
514
  self.indices.append((_('Index'), '\n@printindex ge\n'))
@@ -529,7 +532,7 @@ class TexinfoTranslator(SphinxTranslator):
529
532
 
530
533
  fnotes: dict[str, list[collected_footnote | bool]] = {}
531
534
  for fn in footnotes_under(node):
532
- label = cast(nodes.label, fn[0])
535
+ label = cast('nodes.label', fn[0])
533
536
  num = label.astext().strip()
534
537
  fnotes[num] = [collected_footnote('', *fn.children), False]
535
538
  return fnotes
@@ -608,7 +611,7 @@ class TexinfoTranslator(SphinxTranslator):
608
611
  self.add_anchor(id, node)
609
612
 
610
613
  self.next_section_ids.clear()
611
- self.previous_section = cast(nodes.section, node)
614
+ self.previous_section = cast('nodes.section', node)
612
615
  self.section_level += 1
613
616
 
614
617
  def depart_section(self, node: Element) -> None:
@@ -657,7 +660,7 @@ class TexinfoTranslator(SphinxTranslator):
657
660
  self.body.append('\n\n')
658
661
 
659
662
  def visit_rubric(self, node: Element) -> None:
660
- if len(node) == 1 and node.astext() in ('Footnotes', _('Footnotes')):
663
+ if len(node) == 1 and node.astext() in {'Footnotes', _('Footnotes')}:
661
664
  raise nodes.SkipNode
662
665
  try:
663
666
  rubric = self.rubrics[self.section_level]
@@ -1109,7 +1112,7 @@ class TexinfoTranslator(SphinxTranslator):
1109
1112
 
1110
1113
  def visit_admonition(self, node: Element, name: str = '') -> None:
1111
1114
  if not name:
1112
- title = cast(nodes.title, node[0])
1115
+ title = cast('nodes.title', node[0])
1113
1116
  name = self.escape(title.astext())
1114
1117
  self.body.append('\n@cartouche\n@quotation %s ' % name)
1115
1118
 
@@ -1119,7 +1122,7 @@ class TexinfoTranslator(SphinxTranslator):
1119
1122
 
1120
1123
  def depart_admonition(self, node: Element) -> None:
1121
1124
  self.ensure_eol()
1122
- self.body.append('@end quotation\n' '@end cartouche\n')
1125
+ self.body.append('@end quotation\n@end cartouche\n')
1123
1126
 
1124
1127
  visit_attention = _visit_named_admonition
1125
1128
  depart_attention = depart_admonition
@@ -1170,9 +1173,9 @@ class TexinfoTranslator(SphinxTranslator):
1170
1173
 
1171
1174
  def visit_topic(self, node: Element) -> None:
1172
1175
  # ignore TOC's since we have to have a "menu" anyway
1173
- if 'contents' in node.get('classes', []):
1176
+ if 'contents' in node.get('classes', ()):
1174
1177
  raise nodes.SkipNode
1175
- title = cast(nodes.title, node[0])
1178
+ title = cast('nodes.title', node[0])
1176
1179
  self.visit_rubric(title)
1177
1180
  self.body.append('%s\n' % self.escape(title.astext()))
1178
1181
  self.depart_rubric(title)
@@ -1231,12 +1234,12 @@ class TexinfoTranslator(SphinxTranslator):
1231
1234
  if uri.find('://') != -1:
1232
1235
  # ignore remote images
1233
1236
  return
1234
- name, ext = path.splitext(uri)
1237
+ name, ext = os.path.splitext(uri)
1235
1238
  # width and height ignored in non-tex output
1236
1239
  width = self.tex_image_length(node.get('width', ''))
1237
1240
  height = self.tex_image_length(node.get('height', ''))
1238
1241
  alt = self.escape_arg(node.get('alt', ''))
1239
- filename = f"{self.elements['filename'][:-5]}-figures/{name}" # type: ignore[index]
1242
+ filename = f'{self.elements["filename"][:-5]}-figures/{name}' # type: ignore[index]
1240
1243
  self.body.append(f'\n@image{{{filename},{width},{height},{alt},{ext[1:]}}}\n')
1241
1244
 
1242
1245
  def depart_image(self, node: Element) -> None:
@@ -1280,7 +1283,7 @@ class TexinfoTranslator(SphinxTranslator):
1280
1283
 
1281
1284
  def visit_system_message(self, node: Element) -> None:
1282
1285
  self.body.append(
1283
- '\n@verbatim\n' '<SYSTEM MESSAGE: %s>\n' '@end verbatim\n' % node.astext()
1286
+ '\n@verbatim\n<SYSTEM MESSAGE: %s>\n@end verbatim\n' % node.astext()
1284
1287
  )
1285
1288
  raise nodes.SkipNode
1286
1289
 
@@ -1306,21 +1309,11 @@ class TexinfoTranslator(SphinxTranslator):
1306
1309
 
1307
1310
  def visit_productionlist(self, node: Element) -> None:
1308
1311
  self.visit_literal_block(None)
1309
- productionlist = cast(Iterable[addnodes.production], node)
1310
- names = (production['tokenname'] for production in productionlist)
1311
- maxlen = max(len(name) for name in names)
1312
-
1313
- for production in productionlist:
1314
- if production['tokenname']:
1315
- for id in production.get('ids'):
1316
- self.add_anchor(id, production)
1317
- s = production['tokenname'].ljust(maxlen) + ' ::='
1318
- else:
1319
- s = '%s ' % (' ' * maxlen)
1320
- self.body.append(self.escape(s))
1321
- self.body.append(self.escape(production.astext() + '\n'))
1312
+ self.in_production_list = True
1313
+
1314
+ def depart_productionlist(self, node: Element) -> None:
1315
+ self.in_production_list = False
1322
1316
  self.depart_literal_block(None)
1323
- raise nodes.SkipNode
1324
1317
 
1325
1318
  def visit_production(self, node: Element) -> None:
1326
1319
  pass
@@ -1335,9 +1328,15 @@ class TexinfoTranslator(SphinxTranslator):
1335
1328
  self.body.append('}')
1336
1329
 
1337
1330
  def visit_literal_strong(self, node: Element) -> None:
1331
+ if self.in_production_list:
1332
+ for id_ in node['ids']:
1333
+ self.add_anchor(id_, node)
1334
+ return
1338
1335
  self.body.append('@code{')
1339
1336
 
1340
1337
  def depart_literal_strong(self, node: Element) -> None:
1338
+ if self.in_production_list:
1339
+ return
1341
1340
  self.body.append('}')
1342
1341
 
1343
1342
  def visit_index(self, node: Element) -> None:
@@ -1387,8 +1386,8 @@ class TexinfoTranslator(SphinxTranslator):
1387
1386
  pass
1388
1387
 
1389
1388
  def visit_acks(self, node: Element) -> None:
1390
- bullet_list = cast(nodes.bullet_list, node[0])
1391
- list_items = cast(Iterable[nodes.list_item], bullet_list)
1389
+ bullet_list = cast('nodes.bullet_list', node[0])
1390
+ list_items = cast('Iterable[nodes.list_item]', bullet_list)
1392
1391
  self.body.append('\n\n')
1393
1392
  self.body.append(', '.join(n.astext() for n in list_items) + '.')
1394
1393
  self.body.append('\n\n')
@@ -1418,11 +1417,11 @@ class TexinfoTranslator(SphinxTranslator):
1418
1417
  self.add_anchor(id, node)
1419
1418
  # use the full name of the objtype for the category
1420
1419
  try:
1421
- domain = self.builder.env.get_domain(node.parent['domain'])
1420
+ domain = self._domains[node.parent['domain']]
1422
1421
  name = domain.get_type_name(
1423
1422
  domain.object_types[objtype], self.config.primary_domain == domain.name
1424
1423
  )
1425
- except (KeyError, ExtensionError):
1424
+ except KeyError:
1426
1425
  name = objtype
1427
1426
  # by convention, the deffn category should be capitalized like a title
1428
1427
  category = self.escape_arg(smart_capwords(name))
@@ -1501,7 +1500,7 @@ class TexinfoTranslator(SphinxTranslator):
1501
1500
  self.first_param = 0
1502
1501
  text = self.escape(node.astext())
1503
1502
  # replace no-break spaces with normal ones
1504
- text = text.replace(' ', '@w{ }')
1503
+ text = text.replace('\N{NO-BREAK SPACE}', '@w{ }')
1505
1504
  self.body.append(text)
1506
1505
  raise nodes.SkipNode
1507
1506
 
@@ -1538,10 +1537,11 @@ class TexinfoTranslator(SphinxTranslator):
1538
1537
  pass
1539
1538
 
1540
1539
  def visit_abbreviation(self, node: Element) -> None:
1540
+ explanation = node.get('explanation', '')
1541
1541
  abbr = node.astext()
1542
1542
  self.body.append('@abbr{')
1543
- if node.hasattr('explanation') and abbr not in self.handled_abbrs:
1544
- self.context.append(',%s}' % self.escape_arg(node['explanation']))
1543
+ if explanation and abbr not in self.handled_abbrs:
1544
+ self.context.append(',%s}' % self.escape_arg(explanation))
1545
1545
  self.handled_abbrs.add(abbr)
1546
1546
  else:
1547
1547
  self.context.append('}')
@@ -1579,11 +1579,11 @@ class TexinfoTranslator(SphinxTranslator):
1579
1579
  def depart_pending_xref(self, node: Element) -> None:
1580
1580
  pass
1581
1581
 
1582
- def visit_math(self, node: Element) -> None:
1582
+ def visit_math(self, node: nodes.math) -> None:
1583
1583
  self.body.append('@math{' + self.escape_arg(node.astext()) + '}')
1584
1584
  raise nodes.SkipNode
1585
1585
 
1586
- def visit_math_block(self, node: Element) -> None:
1586
+ def visit_math_block(self, node: nodes.math_block) -> None:
1587
1587
  if node.get('label'):
1588
1588
  self.add_anchor(node['label'], node)
1589
1589
  self.body.append(
sphinx/writers/text.py CHANGED
@@ -6,9 +6,8 @@ import math
6
6
  import os
7
7
  import re
8
8
  import textwrap
9
- from collections.abc import Iterable, Iterator, Sequence
10
9
  from itertools import chain, groupby, pairwise
11
- from typing import TYPE_CHECKING, Any, ClassVar, cast
10
+ from typing import TYPE_CHECKING, cast
12
11
 
13
12
  from docutils import nodes, writers
14
13
  from docutils.utils import column_width
@@ -18,6 +17,9 @@ from sphinx.locale import _, admonitionlabels
18
17
  from sphinx.util.docutils import SphinxTranslator
19
18
 
20
19
  if TYPE_CHECKING:
20
+ from collections.abc import Iterable, Iterator, Sequence
21
+ from typing import Any, ClassVar
22
+
21
23
  from docutils.nodes import Element, Text
22
24
 
23
25
  from sphinx.builders.text import TextBuilder
@@ -45,7 +47,7 @@ class Cell:
45
47
  return hash((self.col, self.row))
46
48
 
47
49
  def __bool__(self) -> bool:
48
- return self.text != '' and self.col is not None and self.row is not None
50
+ return bool(self.text) and self.col is not None and self.row is not None
49
51
 
50
52
  def wrap(self, width: int) -> None:
51
53
  self.wrapped = my_wrap(self.text, width)
@@ -292,7 +294,7 @@ class TextWrapper(textwrap.TextWrapper):
292
294
 
293
295
  width = self.width - column_width(indent)
294
296
 
295
- if self.drop_whitespace and chunks[-1].strip() == '' and lines:
297
+ if self.drop_whitespace and not chunks[-1].strip() and lines:
296
298
  del chunks[-1]
297
299
 
298
300
  while chunks:
@@ -308,7 +310,7 @@ class TextWrapper(textwrap.TextWrapper):
308
310
  if chunks and column_width(chunks[-1]) > width:
309
311
  self._handle_long_word(chunks, cur_line, cur_len, width)
310
312
 
311
- if self.drop_whitespace and cur_line and cur_line[-1].strip() == '':
313
+ if self.drop_whitespace and cur_line and not cur_line[-1].strip():
312
314
  del cur_line[-1]
313
315
 
314
316
  if cur_line:
@@ -381,7 +383,7 @@ class TextWriter(writers.Writer): # type: ignore[type-arg]
381
383
  assert isinstance(self.document, nodes.document)
382
384
  visitor = self.builder.create_translator(self.document, self.builder)
383
385
  self.document.walkabout(visitor)
384
- self.output = cast(TextTranslator, visitor).body
386
+ self.output = cast('TextTranslator', visitor).body
385
387
 
386
388
 
387
389
  class TextTranslator(SphinxTranslator):
@@ -406,6 +408,7 @@ class TextTranslator(SphinxTranslator):
406
408
  self.sectionlevel = 0
407
409
  self.lineblocklevel = 0
408
410
  self.table: Table
411
+ self.in_production_list = False
409
412
 
410
413
  self.context: list[str] = []
411
414
  """Heterogeneous stack.
@@ -646,6 +649,7 @@ class TextTranslator(SphinxTranslator):
646
649
  self.required_params_left = sum(self.list_is_required_param)
647
650
  self.param_separator = ', '
648
651
  self.multi_line_parameter_list = node.get('multi_line_parameter_list', False)
652
+ self.trailing_comma = node.get('multi_line_trailing_comma', False)
649
653
  if self.multi_line_parameter_list:
650
654
  self.param_separator = self.param_separator.rstrip()
651
655
  self.context.append(sig_close_paren)
@@ -697,7 +701,8 @@ class TextTranslator(SphinxTranslator):
697
701
  or is_required
698
702
  and (is_last_group or next_is_required)
699
703
  ):
700
- self.add_text(self.param_separator)
704
+ if not is_last_group or opt_param_left_at_level or self.trailing_comma:
705
+ self.add_text(self.param_separator)
701
706
  self.end_state(wrap=False, end=None)
702
707
 
703
708
  elif self.required_params_left:
@@ -738,20 +743,27 @@ class TextTranslator(SphinxTranslator):
738
743
 
739
744
  def depart_desc_optional(self, node: Element) -> None:
740
745
  self.optional_param_level -= 1
746
+ level = self.optional_param_level
741
747
  if self.multi_line_parameter_list:
748
+ max_level = self.max_optional_param_level
749
+ len_lirp = len(self.list_is_required_param)
750
+ is_last_group = self.param_group_index + 1 == len_lirp
742
751
  # If it's the first time we go down one level, add the separator before the
743
- # bracket.
744
- if self.optional_param_level == self.max_optional_param_level - 1:
752
+ # bracket, except if this is the last parameter and the parameter list
753
+ # should not feature a trailing comma.
754
+ if level == max_level - 1 and (
755
+ not is_last_group or level > 0 or self.trailing_comma
756
+ ):
745
757
  self.add_text(self.param_separator)
746
758
  self.add_text(']')
747
759
  # End the line if we have just closed the last bracket of this group of
748
760
  # optional parameters.
749
- if self.optional_param_level == 0:
761
+ if level == 0:
750
762
  self.end_state(wrap=False, end=None)
751
763
 
752
764
  else:
753
765
  self.add_text(']')
754
- if self.optional_param_level == 0:
766
+ if level == 0:
755
767
  self.param_group_index += 1
756
768
 
757
769
  def visit_desc_annotation(self, node: Element) -> None:
@@ -776,22 +788,20 @@ class TextTranslator(SphinxTranslator):
776
788
 
777
789
  def visit_productionlist(self, node: Element) -> None:
778
790
  self.new_state()
779
- productionlist = cast(Iterable[addnodes.production], node)
780
- names = (production['tokenname'] for production in productionlist)
781
- maxlen = max(len(name) for name in names)
782
- lastname = None
783
- for production in productionlist:
784
- if production['tokenname']:
785
- self.add_text(production['tokenname'].ljust(maxlen) + ' ::=')
786
- lastname = production['tokenname']
787
- elif lastname is not None:
788
- self.add_text('%s ' % (' ' * len(lastname)))
789
- self.add_text(production.astext() + self.nl)
791
+ self.in_production_list = True
792
+
793
+ def depart_productionlist(self, node: Element) -> None:
794
+ self.in_production_list = False
790
795
  self.end_state(wrap=False)
791
- raise nodes.SkipNode
796
+
797
+ def visit_production(self, node: Element) -> None:
798
+ pass
799
+
800
+ def depart_production(self, node: Element) -> None:
801
+ pass
792
802
 
793
803
  def visit_footnote(self, node: Element) -> None:
794
- label = cast(nodes.label, node[0])
804
+ label = cast('nodes.label', node[0])
795
805
  self._footnote = label.astext().strip()
796
806
  self.new_state(len(self._footnote) + 3)
797
807
 
@@ -923,8 +933,8 @@ class TextTranslator(SphinxTranslator):
923
933
  self.end_state(wrap=False)
924
934
 
925
935
  def visit_acks(self, node: Element) -> None:
926
- bullet_list = cast(nodes.bullet_list, node[0])
927
- list_items = cast(Iterable[nodes.list_item], bullet_list)
936
+ bullet_list = cast('nodes.bullet_list', node[0])
937
+ list_items = cast('Iterable[nodes.list_item]', bullet_list)
928
938
  self.new_state(0)
929
939
  self.add_text(', '.join(n.astext() for n in list_items) + '.')
930
940
  self.end_state()
@@ -1214,17 +1224,21 @@ class TextTranslator(SphinxTranslator):
1214
1224
  self.add_text('**')
1215
1225
 
1216
1226
  def visit_literal_strong(self, node: Element) -> None:
1227
+ if self.in_production_list:
1228
+ return
1217
1229
  self.add_text('**')
1218
1230
 
1219
1231
  def depart_literal_strong(self, node: Element) -> None:
1232
+ if self.in_production_list:
1233
+ return
1220
1234
  self.add_text('**')
1221
1235
 
1222
1236
  def visit_abbreviation(self, node: Element) -> None:
1223
1237
  self.add_text('')
1224
1238
 
1225
1239
  def depart_abbreviation(self, node: Element) -> None:
1226
- if node.hasattr('explanation'):
1227
- self.add_text(' (%s)' % node['explanation'])
1240
+ if explanation := node.get('explanation', ''):
1241
+ self.add_text(f' ({explanation})')
1228
1242
 
1229
1243
  def visit_manpage(self, node: Element) -> None:
1230
1244
  return self.visit_literal_emphasis(node)
@@ -1239,9 +1253,13 @@ class TextTranslator(SphinxTranslator):
1239
1253
  self.add_text('*')
1240
1254
 
1241
1255
  def visit_literal(self, node: Element) -> None:
1256
+ if self.in_production_list:
1257
+ return
1242
1258
  self.add_text('"')
1243
1259
 
1244
1260
  def depart_literal(self, node: Element) -> None:
1261
+ if self.in_production_list:
1262
+ return
1245
1263
  self.add_text('"')
1246
1264
 
1247
1265
  def visit_subscript(self, node: Element) -> None:
@@ -1316,14 +1334,14 @@ class TextTranslator(SphinxTranslator):
1316
1334
  self.end_state(wrap=False)
1317
1335
  raise nodes.SkipNode
1318
1336
 
1319
- def visit_math(self, node: Element) -> None:
1337
+ def visit_math(self, node: nodes.math) -> None:
1320
1338
  pass
1321
1339
 
1322
- def depart_math(self, node: Element) -> None:
1340
+ def depart_math(self, node: nodes.math) -> None:
1323
1341
  pass
1324
1342
 
1325
- def visit_math_block(self, node: Element) -> None:
1343
+ def visit_math_block(self, node: nodes.math_block) -> None:
1326
1344
  self.new_state()
1327
1345
 
1328
- def depart_math_block(self, node: Element) -> None:
1346
+ def depart_math_block(self, node: nodes.math_block) -> None:
1329
1347
  self.end_state()
sphinx/writers/xml.py CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from docutils.writers.docutils_xml import Writer as BaseXMLWriter
8
8
 
9
9
  if TYPE_CHECKING:
10
+ from typing import Any
11
+
10
12
  from sphinx.builders import Builder
11
13
 
12
14
 
@@ -16,19 +18,20 @@ class XMLWriter(BaseXMLWriter): # type: ignore[misc]
16
18
  def __init__(self, builder: Builder) -> None:
17
19
  super().__init__()
18
20
  self.builder = builder
19
-
20
- # A lambda function to generate translator lazily
21
- self.translator_class = lambda document: self.builder.create_translator(
22
- document
23
- )
21
+ self._config = builder.config
24
22
 
25
23
  def translate(self, *args: Any, **kwargs: Any) -> None:
26
24
  self.document.settings.newlines = self.document.settings.indents = (
27
- self.builder.env.config.xml_pretty
25
+ self._config.xml_pretty
28
26
  )
29
27
  self.document.settings.xml_declaration = True
30
28
  self.document.settings.doctype_declaration = True
31
- return super().translate()
29
+
30
+ # copied from docutils.writers.docutils_xml.Writer.translate()
31
+ # so that we can override the translator class
32
+ self.visitor = visitor = self.builder.create_translator(self.document)
33
+ self.document.walkabout(visitor)
34
+ self.output = ''.join(visitor.output) # type: ignore[attr-defined]
32
35
 
33
36
 
34
37
  class PseudoXMLWriter(BaseXMLWriter): # type: ignore[misc]
@@ -4,7 +4,7 @@ License for Sphinx
4
4
  Unless otherwise indicated, all code in the Sphinx project is licenced under the
5
5
  two clause BSD licence below.
6
6
 
7
- Copyright (c) 2007-2024 by the Sphinx team (see AUTHORS file).
7
+ Copyright (c) 2007-2025 by the Sphinx team (see AUTHORS file).
8
8
  All rights reserved.
9
9
 
10
10
  Redistribution and use in source and binary forms, with or without
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: Sphinx
3
- Version: 8.1.3
3
+ Version: 8.2.0
4
4
  Summary: Python documentation generator
5
- Author-email: Georg Brandl <georg@python.org>
6
- Requires-Python: >=3.10
5
+ Author-email: Adam Turner <aa-turner@users.noreply.github.com>, Georg Brandl <georg@python.org>
6
+ Requires-Python: >=3.11
7
7
  Description-Content-Type: text/x-rst
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Environment :: Console
@@ -11,6 +11,8 @@ Classifier: Environment :: Web Environment
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Intended Audience :: Education
13
13
  Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Intended Audience :: Other Audience
14
16
  Classifier: Intended Audience :: Science/Research
15
17
  Classifier: Intended Audience :: System Administrators
16
18
  Classifier: License :: OSI Approved :: BSD License
@@ -18,10 +20,10 @@ Classifier: Operating System :: OS Independent
18
20
  Classifier: Programming Language :: Python
19
21
  Classifier: Programming Language :: Python :: 3
20
22
  Classifier: Programming Language :: Python :: 3 :: Only
21
- Classifier: Programming Language :: Python :: 3.10
22
23
  Classifier: Programming Language :: Python :: 3.11
23
24
  Classifier: Programming Language :: Python :: 3.12
24
25
  Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
25
27
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
28
  Classifier: Programming Language :: Python :: Implementation :: PyPy
27
29
  Classifier: Framework :: Sphinx
@@ -30,17 +32,24 @@ Classifier: Framework :: Sphinx :: Extension
30
32
  Classifier: Framework :: Sphinx :: Theme
31
33
  Classifier: Topic :: Documentation
32
34
  Classifier: Topic :: Documentation :: Sphinx
35
+ Classifier: Topic :: Education
33
36
  Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
37
+ Classifier: Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking
34
38
  Classifier: Topic :: Printing
35
39
  Classifier: Topic :: Software Development
36
40
  Classifier: Topic :: Software Development :: Documentation
41
+ Classifier: Topic :: Text Editors :: Documentation
37
42
  Classifier: Topic :: Text Processing
38
43
  Classifier: Topic :: Text Processing :: General
39
44
  Classifier: Topic :: Text Processing :: Indexing
40
45
  Classifier: Topic :: Text Processing :: Markup
41
46
  Classifier: Topic :: Text Processing :: Markup :: HTML
42
47
  Classifier: Topic :: Text Processing :: Markup :: LaTeX
48
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
49
+ Classifier: Topic :: Text Processing :: Markup :: reStructuredText
50
+ Classifier: Topic :: Text Processing :: Markup :: XML
43
51
  Classifier: Topic :: Utilities
52
+ Classifier: Typing :: Typed
44
53
  Requires-Dist: sphinxcontrib-applehelp>=1.0.7
45
54
  Requires-Dist: sphinxcontrib-devhelp>=1.0.6
46
55
  Requires-Dist: sphinxcontrib-htmlhelp>=2.0.6
@@ -55,25 +64,26 @@ Requires-Dist: babel>=2.13
55
64
  Requires-Dist: alabaster>=0.7.14
56
65
  Requires-Dist: imagesize>=1.3
57
66
  Requires-Dist: requests>=2.30.0
67
+ Requires-Dist: roman-numerals-py>=1.0.0
58
68
  Requires-Dist: packaging>=23.0
59
- Requires-Dist: tomli>=2; python_version < '3.11'
60
69
  Requires-Dist: colorama>=0.4.6; sys_platform == 'win32'
61
70
  Requires-Dist: sphinxcontrib-websupport ; extra == "docs"
62
- Requires-Dist: flake8>=6.0 ; extra == "lint"
63
- Requires-Dist: ruff==0.6.9 ; extra == "lint"
64
- Requires-Dist: mypy==1.11.1 ; extra == "lint"
71
+ Requires-Dist: ruff==0.9.6 ; extra == "lint"
72
+ Requires-Dist: mypy==1.15.0 ; extra == "lint"
65
73
  Requires-Dist: sphinx-lint>=0.9 ; extra == "lint"
66
74
  Requires-Dist: types-colorama==0.4.15.20240311 ; extra == "lint"
67
75
  Requires-Dist: types-defusedxml==0.7.0.20240218 ; extra == "lint"
68
- Requires-Dist: types-docutils==0.21.0.20241005 ; extra == "lint"
76
+ Requires-Dist: types-docutils==0.21.0.20241128 ; extra == "lint"
69
77
  Requires-Dist: types-Pillow==10.2.0.20240822 ; extra == "lint"
70
- Requires-Dist: types-Pygments==2.18.0.20240506 ; extra == "lint"
71
- Requires-Dist: types-requests==2.32.0.20240914 ; extra == "lint"
78
+ Requires-Dist: types-Pygments==2.19.0.20250107 ; extra == "lint"
79
+ Requires-Dist: types-requests==2.32.0.20241016 ; extra == "lint"
72
80
  Requires-Dist: types-urllib3==1.26.25.14 ; extra == "lint"
73
- Requires-Dist: tomli>=2 ; extra == "lint"
74
- Requires-Dist: pyright==1.1.384 ; extra == "lint"
75
- Requires-Dist: pytest>=6.0 ; extra == "lint"
81
+ Requires-Dist: pyright==1.1.394 ; extra == "lint"
82
+ Requires-Dist: pytest>=8.0 ; extra == "lint"
83
+ Requires-Dist: pypi-attestations==0.0.21 ; extra == "lint"
84
+ Requires-Dist: betterproto==2.0.0b6 ; extra == "lint"
76
85
  Requires-Dist: pytest>=8.0 ; extra == "test"
86
+ Requires-Dist: pytest-xdist[psutil]>=3.4 ; extra == "test"
77
87
  Requires-Dist: defusedxml>=0.7.1 ; extra == "test"
78
88
  Requires-Dist: cython>=3.0 ; extra == "test"
79
89
  Requires-Dist: setuptools>=70.0 ; extra == "test"