Sphinx 8.1.3__py3-none-any.whl → 8.2.0rc1__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 (193) 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 +48 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +114 -57
  57. sphinx/domains/python/_object.py +151 -67
  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 +21 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_generate.py +356 -0
  76. sphinx/ext/apidoc/_shared.py +66 -0
  77. sphinx/ext/autodoc/__init__.py +829 -480
  78. sphinx/ext/autodoc/directive.py +57 -21
  79. sphinx/ext/autodoc/importer.py +184 -67
  80. sphinx/ext/autodoc/mock.py +25 -10
  81. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  82. sphinx/ext/autodoc/type_comment.py +56 -29
  83. sphinx/ext/autodoc/typehints.py +49 -26
  84. sphinx/ext/autosectionlabel.py +28 -11
  85. sphinx/ext/autosummary/__init__.py +271 -143
  86. sphinx/ext/autosummary/generate.py +121 -51
  87. sphinx/ext/coverage.py +152 -91
  88. sphinx/ext/doctest.py +169 -101
  89. sphinx/ext/duration.py +12 -6
  90. sphinx/ext/extlinks.py +33 -21
  91. sphinx/ext/githubpages.py +8 -8
  92. sphinx/ext/graphviz.py +175 -109
  93. sphinx/ext/ifconfig.py +11 -6
  94. sphinx/ext/imgconverter.py +48 -25
  95. sphinx/ext/imgmath.py +127 -97
  96. sphinx/ext/inheritance_diagram.py +177 -103
  97. sphinx/ext/intersphinx/__init__.py +22 -13
  98. sphinx/ext/intersphinx/__main__.py +3 -1
  99. sphinx/ext/intersphinx/_cli.py +18 -14
  100. sphinx/ext/intersphinx/_load.py +91 -82
  101. sphinx/ext/intersphinx/_resolve.py +108 -74
  102. sphinx/ext/intersphinx/_shared.py +2 -2
  103. sphinx/ext/linkcode.py +28 -12
  104. sphinx/ext/mathjax.py +60 -29
  105. sphinx/ext/napoleon/__init__.py +19 -7
  106. sphinx/ext/napoleon/docstring.py +229 -231
  107. sphinx/ext/todo.py +44 -49
  108. sphinx/ext/viewcode.py +105 -57
  109. sphinx/extension.py +3 -1
  110. sphinx/highlighting.py +13 -7
  111. sphinx/io.py +9 -13
  112. sphinx/jinja2glue.py +29 -26
  113. sphinx/locale/__init__.py +8 -9
  114. sphinx/parsers.py +8 -7
  115. sphinx/project.py +2 -2
  116. sphinx/pycode/__init__.py +31 -21
  117. sphinx/pycode/ast.py +6 -3
  118. sphinx/pycode/parser.py +14 -8
  119. sphinx/pygments_styles.py +4 -5
  120. sphinx/registry.py +192 -92
  121. sphinx/roles.py +58 -7
  122. sphinx/search/__init__.py +75 -54
  123. sphinx/search/en.py +11 -13
  124. sphinx/search/fi.py +1 -1
  125. sphinx/search/ja.py +8 -6
  126. sphinx/search/nl.py +1 -1
  127. sphinx/search/zh.py +19 -21
  128. sphinx/testing/fixtures.py +26 -29
  129. sphinx/testing/path.py +26 -62
  130. sphinx/testing/restructuredtext.py +14 -8
  131. sphinx/testing/util.py +21 -19
  132. sphinx/texinputs/make.bat.jinja +50 -50
  133. sphinx/texinputs/sphinx.sty +4 -3
  134. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  135. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  136. sphinx/themes/basic/static/searchtools.js +8 -5
  137. sphinx/theming.py +49 -61
  138. sphinx/transforms/__init__.py +17 -38
  139. sphinx/transforms/compact_bullet_list.py +5 -3
  140. sphinx/transforms/i18n.py +8 -21
  141. sphinx/transforms/post_transforms/__init__.py +142 -93
  142. sphinx/transforms/post_transforms/code.py +5 -5
  143. sphinx/transforms/post_transforms/images.py +28 -24
  144. sphinx/transforms/references.py +3 -1
  145. sphinx/util/__init__.py +109 -60
  146. sphinx/util/_files.py +39 -23
  147. sphinx/util/_importer.py +4 -1
  148. sphinx/util/_inventory_file_reader.py +76 -0
  149. sphinx/util/_io.py +2 -2
  150. sphinx/util/_lines.py +6 -3
  151. sphinx/util/_pathlib.py +40 -2
  152. sphinx/util/build_phase.py +2 -0
  153. sphinx/util/cfamily.py +19 -14
  154. sphinx/util/console.py +44 -179
  155. sphinx/util/display.py +9 -10
  156. sphinx/util/docfields.py +140 -122
  157. sphinx/util/docstrings.py +1 -1
  158. sphinx/util/docutils.py +118 -77
  159. sphinx/util/fileutil.py +25 -26
  160. sphinx/util/http_date.py +2 -0
  161. sphinx/util/i18n.py +77 -64
  162. sphinx/util/images.py +8 -6
  163. sphinx/util/inspect.py +147 -38
  164. sphinx/util/inventory.py +215 -116
  165. sphinx/util/logging.py +33 -33
  166. sphinx/util/matching.py +12 -4
  167. sphinx/util/nodes.py +18 -13
  168. sphinx/util/osutil.py +38 -39
  169. sphinx/util/parallel.py +22 -13
  170. sphinx/util/parsing.py +2 -1
  171. sphinx/util/png.py +6 -2
  172. sphinx/util/requests.py +33 -2
  173. sphinx/util/rst.py +3 -2
  174. sphinx/util/tags.py +1 -1
  175. sphinx/util/template.py +18 -10
  176. sphinx/util/texescape.py +8 -6
  177. sphinx/util/typing.py +148 -122
  178. sphinx/versioning.py +3 -3
  179. sphinx/writers/html.py +3 -1
  180. sphinx/writers/html5.py +61 -50
  181. sphinx/writers/latex.py +80 -65
  182. sphinx/writers/manpage.py +19 -38
  183. sphinx/writers/texinfo.py +44 -45
  184. sphinx/writers/text.py +48 -30
  185. sphinx/writers/xml.py +11 -8
  186. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
  187. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
  188. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
  189. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
  190. sphinx/builders/html/transforms.py +0 -90
  191. sphinx/ext/apidoc.py +0 -721
  192. sphinx/util/exceptions.py +0 -74
  193. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/theming.py CHANGED
@@ -6,13 +6,13 @@ __all__ = ('Theme', 'HTMLThemeFactory')
6
6
 
7
7
  import configparser
8
8
  import contextlib
9
- import os
10
9
  import shutil
11
10
  import sys
12
11
  import tempfile
12
+ import tomllib
13
13
  from importlib.metadata import entry_points
14
- from os import path
15
- from typing import TYPE_CHECKING, Any
14
+ from pathlib import Path
15
+ from typing import TYPE_CHECKING
16
16
  from zipfile import ZipFile
17
17
 
18
18
  from sphinx import package_dir
@@ -20,19 +20,12 @@ from sphinx.config import check_confval_types as _config_post_init
20
20
  from sphinx.errors import ThemeError
21
21
  from sphinx.locale import __
22
22
  from sphinx.util import logging
23
+ from sphinx.util._pathlib import _StrPath
23
24
  from sphinx.util.osutil import ensuredir
24
25
 
25
- if sys.version_info >= (3, 11):
26
- import tomllib
27
- else:
28
- import tomli as tomllib
29
-
30
-
31
26
  if TYPE_CHECKING:
32
27
  from collections.abc import Callable
33
- from typing import TypedDict
34
-
35
- from typing_extensions import Required
28
+ from typing import Any, Required, TypedDict
36
29
 
37
30
  from sphinx.application import Sphinx
38
31
 
@@ -69,8 +62,8 @@ class Theme:
69
62
  name: str,
70
63
  *,
71
64
  configs: dict[str, _ConfigFile],
72
- paths: list[str],
73
- tmp_dirs: list[str],
65
+ paths: list[Path],
66
+ tmp_dirs: list[Path],
74
67
  ) -> None:
75
68
  self.name = name
76
69
  self._dirs = tuple(paths)
@@ -94,11 +87,11 @@ class Theme:
94
87
 
95
88
  self._options = options
96
89
 
97
- def get_theme_dirs(self) -> list[str]:
90
+ def get_theme_dirs(self) -> list[_StrPath]:
98
91
  """Return a list of theme directories, beginning with this theme's,
99
92
  then the base theme's, then that one's base theme's, etc.
100
93
  """
101
- return list(self._dirs)
94
+ return list(map(_StrPath, self._dirs))
102
95
 
103
96
  def get_config(self, section: str, name: str, default: Any = _NO_DEFAULT) -> Any:
104
97
  """Return the value for a theme configuration setting, searching the
@@ -166,17 +159,17 @@ class HTMLThemeFactory:
166
159
 
167
160
  def _load_builtin_themes(self) -> None:
168
161
  """Load built-in themes."""
169
- themes = self._find_themes(path.join(package_dir, 'themes'))
162
+ themes = self._find_themes(package_dir / 'themes')
170
163
  for name, theme in themes.items():
171
- self._themes[name] = theme
164
+ self._themes[name] = _StrPath(theme)
172
165
 
173
166
  def _load_additional_themes(self, theme_paths: list[str]) -> None:
174
167
  """Load additional themes placed at specified directories."""
175
168
  for theme_path in theme_paths:
176
- abs_theme_path = path.abspath(path.join(self._app.confdir, theme_path))
169
+ abs_theme_path = (self._app.confdir / theme_path).resolve()
177
170
  themes = self._find_themes(abs_theme_path)
178
171
  for name, theme in themes.items():
179
- self._themes[name] = theme
172
+ self._themes[name] = _StrPath(theme)
180
173
 
181
174
  def _load_entry_point_themes(self) -> None:
182
175
  """Try to load a theme with the specified name.
@@ -198,18 +191,17 @@ class HTMLThemeFactory:
198
191
  self._entry_point_themes[entry_point.name] = _load_theme_closure
199
192
 
200
193
  @staticmethod
201
- def _find_themes(theme_path: str) -> dict[str, str]:
194
+ def _find_themes(theme_path: Path) -> dict[str, Path]:
202
195
  """Search themes from specified directory."""
203
- themes: dict[str, str] = {}
204
- if not path.isdir(theme_path):
196
+ themes: dict[str, Path] = {}
197
+ if not theme_path.is_dir():
205
198
  return themes
206
199
 
207
- for entry in os.listdir(theme_path):
208
- pathname = path.join(theme_path, entry)
209
- if path.isfile(pathname) and entry.lower().endswith('.zip'):
200
+ for pathname in theme_path.iterdir():
201
+ entry = pathname.name
202
+ if pathname.is_file() and pathname.suffix.lower() == '.zip':
210
203
  if _is_archived_theme(pathname):
211
- name = entry[:-4]
212
- themes[name] = pathname
204
+ themes[pathname.stem] = pathname
213
205
  else:
214
206
  logger.warning(
215
207
  __(
@@ -219,9 +211,9 @@ class HTMLThemeFactory:
219
211
  entry,
220
212
  )
221
213
  else:
222
- toml_path = path.join(pathname, _THEME_TOML)
223
- conf_path = path.join(pathname, _THEME_CONF)
224
- if path.isfile(toml_path) or path.isfile(conf_path):
214
+ toml_path = pathname / _THEME_TOML
215
+ conf_path = pathname / _THEME_CONF
216
+ if toml_path.is_file() or conf_path.is_file():
225
217
  themes[entry] = pathname
226
218
 
227
219
  return themes
@@ -243,7 +235,7 @@ class HTMLThemeFactory:
243
235
  return Theme(name, configs=themes, paths=theme_dirs, tmp_dirs=tmp_dirs)
244
236
 
245
237
 
246
- def _is_archived_theme(filename: str, /) -> bool:
238
+ def _is_archived_theme(filename: Path, /) -> bool:
247
239
  """Check whether the specified file is an archived theme file or not."""
248
240
  try:
249
241
  with ZipFile(filename) as f:
@@ -255,13 +247,13 @@ def _is_archived_theme(filename: str, /) -> bool:
255
247
 
256
248
  def _load_theme_with_ancestors(
257
249
  name: str,
258
- theme_paths: dict[str, str],
250
+ theme_paths: dict[str, _StrPath],
259
251
  entry_point_themes: dict[str, Callable[[], None]],
260
252
  /,
261
- ) -> tuple[dict[str, _ConfigFile], list[str], list[str]]:
253
+ ) -> tuple[dict[str, _ConfigFile], list[Path], list[Path]]:
262
254
  themes: dict[str, _ConfigFile] = {}
263
- theme_dirs: list[str] = []
264
- tmp_dirs: list[str] = []
255
+ theme_dirs: list[Path] = []
256
+ tmp_dirs: list[Path] = []
265
257
 
266
258
  # having 10+ theme ancestors is ludicrous
267
259
  for _ in range(10):
@@ -294,23 +286,23 @@ def _load_theme_with_ancestors(
294
286
 
295
287
 
296
288
  def _load_theme(
297
- name: str, theme_path: str, /
298
- ) -> tuple[str, str, str | None, _ConfigFile]:
299
- if path.isdir(theme_path):
289
+ name: str, theme_path: Path, /
290
+ ) -> tuple[str, Path, Path | None, _ConfigFile]:
291
+ if theme_path.is_dir():
300
292
  # already a directory, do nothing
301
293
  tmp_dir = None
302
294
  theme_dir = theme_path
303
295
  else:
304
296
  # extract the theme to a temp directory
305
- tmp_dir = tempfile.mkdtemp('sxt')
306
- theme_dir = path.join(tmp_dir, name)
297
+ tmp_dir = Path(tempfile.mkdtemp('sxt'))
298
+ theme_dir = tmp_dir / name
307
299
  _extract_zip(theme_path, theme_dir)
308
300
 
309
- if path.isfile(toml_path := path.join(theme_dir, _THEME_TOML)):
301
+ if (toml_path := theme_dir / _THEME_TOML).is_file():
310
302
  _cfg_table = _load_theme_toml(toml_path)
311
303
  inherit = _validate_theme_toml(_cfg_table, name)
312
304
  config = _convert_theme_toml(_cfg_table)
313
- elif path.isfile(conf_path := path.join(theme_dir, _THEME_CONF)):
305
+ elif (conf_path := theme_dir / _THEME_CONF).is_file():
314
306
  _cfg_parser = _load_theme_conf(conf_path)
315
307
  inherit = _validate_theme_conf(_cfg_parser, name)
316
308
  config = _convert_theme_conf(_cfg_parser)
@@ -320,7 +312,7 @@ def _load_theme(
320
312
  return inherit, theme_dir, tmp_dir, config
321
313
 
322
314
 
323
- def _extract_zip(filename: str, target_dir: str, /) -> None:
315
+ def _extract_zip(filename: Path, target_dir: Path, /) -> None:
324
316
  """Extract zip file to target directory."""
325
317
  ensuredir(target_dir)
326
318
 
@@ -328,16 +320,13 @@ def _extract_zip(filename: str, target_dir: str, /) -> None:
328
320
  for name in archive.namelist():
329
321
  if name.endswith('/'):
330
322
  continue
331
- entry = path.join(target_dir, name)
332
- ensuredir(path.dirname(entry))
333
- with open(path.join(entry), 'wb') as fp:
334
- fp.write(archive.read(name))
323
+ entry = target_dir / name
324
+ ensuredir(entry.parent)
325
+ entry.write_bytes(archive.read(name))
335
326
 
336
327
 
337
- def _load_theme_toml(config_file_path: str, /) -> _ThemeToml:
338
- with open(config_file_path, encoding='utf-8') as f:
339
- config_text = f.read()
340
- c = tomllib.loads(config_text)
328
+ def _load_theme_toml(config_file_path: Path, /) -> _ThemeToml:
329
+ c = tomllib.loads(config_file_path.read_text(encoding='utf-8'))
341
330
  return {s: c[s] for s in ('theme', 'options') if s in c} # type: ignore[return-value]
342
331
 
343
332
 
@@ -388,7 +377,7 @@ def _convert_theme_toml(cfg: _ThemeToml, /) -> _ConfigFile:
388
377
  )
389
378
 
390
379
 
391
- def _load_theme_conf(config_file_path: str, /) -> configparser.RawConfigParser:
380
+ def _load_theme_conf(config_file_path: Path, /) -> configparser.RawConfigParser:
392
381
  c = configparser.RawConfigParser()
393
382
  c.read(config_file_path, encoding='utf-8')
394
383
  return c
@@ -494,9 +483,9 @@ def _migrate_conf_to_toml(argv: list[str]) -> int:
494
483
  if len(argv) != 1:
495
484
  print('Usage: python -m sphinx.theming conf_to_toml <theme path>') # NoQA: T201
496
485
  raise SystemExit(1)
497
- theme_dir = path.realpath(argv[0])
498
- conf_path = path.join(theme_dir, _THEME_CONF)
499
- if not path.isdir(theme_dir) or not path.isfile(conf_path):
486
+ theme_dir = Path(argv[0]).resolve()
487
+ conf_path = theme_dir / _THEME_CONF
488
+ if not theme_dir.is_dir() or not conf_path.is_file():
500
489
  print( # NoQA: T201
501
490
  f'{theme_dir!r} must be a path to a theme directory containing a "theme.conf" file'
502
491
  )
@@ -516,7 +505,7 @@ def _migrate_conf_to_toml(argv: list[str]) -> int:
516
505
  ]
517
506
 
518
507
  stylesheet = _cfg_parser.get('theme', 'stylesheet', fallback=...)
519
- if stylesheet == '':
508
+ if not stylesheet:
520
509
  toml_lines.append('stylesheets = []')
521
510
  elif stylesheet is not ...:
522
511
  toml_lines.append('stylesheets = [')
@@ -524,7 +513,7 @@ def _migrate_conf_to_toml(argv: list[str]) -> int:
524
513
  toml_lines.append(']')
525
514
 
526
515
  sidebar = _cfg_parser.get('theme', 'sidebars', fallback=...)
527
- if sidebar == '':
516
+ if not sidebar:
528
517
  toml_lines.append('sidebars = []')
529
518
  elif sidebar is not ...:
530
519
  toml_lines.append('sidebars = [')
@@ -550,9 +539,8 @@ def _migrate_conf_to_toml(argv: list[str]) -> int:
550
539
  if (d := default.replace('"', r'\"')) or True
551
540
  ]
552
541
 
553
- toml_path = path.join(theme_dir, _THEME_TOML)
554
- with open(toml_path, 'w', encoding='utf-8') as f:
555
- f.write('\n'.join(toml_lines) + '\n')
542
+ toml_path = theme_dir / _THEME_TOML
543
+ toml_path.write_text('\n'.join(toml_lines) + '\n', encoding='utf-8')
556
544
  print(f'Written converted settings to {toml_path!r}') # NoQA: T201
557
545
  return 0
558
546
 
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  import unicodedata
7
- from typing import TYPE_CHECKING, Any, cast
7
+ from typing import TYPE_CHECKING, cast
8
8
 
9
9
  from docutils import nodes
10
10
  from docutils.transforms import Transform, Transformer
@@ -23,7 +23,7 @@ from sphinx.util.nodes import apply_source_workaround, is_smartquotable
23
23
 
24
24
  if TYPE_CHECKING:
25
25
  from collections.abc import Iterator
26
- from typing import Literal, TypeAlias
26
+ from typing import Any, Literal, TypeAlias
27
27
 
28
28
  from docutils.nodes import Node, Text
29
29
  from typing_extensions import TypeIs
@@ -76,9 +76,7 @@ class SphinxTransform(Transform):
76
76
 
77
77
 
78
78
  class SphinxTransformer(Transformer):
79
- """
80
- A transformer for Sphinx.
81
- """
79
+ """A transformer for Sphinx."""
82
80
 
83
81
  document: nodes.document
84
82
  env: BuildEnvironment | None = None
@@ -106,9 +104,7 @@ class SphinxTransformer(Transformer):
106
104
 
107
105
 
108
106
  class DefaultSubstitutions(SphinxTransform):
109
- """
110
- Replace some substitutions if they aren't defined in the document.
111
- """
107
+ """Replace some substitutions if they aren't defined in the document."""
112
108
 
113
109
  # run before the default Substitutions
114
110
  default_priority = 210
@@ -150,8 +146,7 @@ def _calculate_translation_progress(document: nodes.document) -> str:
150
146
 
151
147
 
152
148
  class MoveModuleTargets(SphinxTransform):
153
- """
154
- Move module targets that are the first thing in a section to the section
149
+ """Move module targets that are the first thing in a section to the section
155
150
  title.
156
151
 
157
152
  XXX Python specific
@@ -176,9 +171,7 @@ class MoveModuleTargets(SphinxTransform):
176
171
 
177
172
 
178
173
  class HandleCodeBlocks(SphinxTransform):
179
- """
180
- Several code block related transformations.
181
- """
174
+ """Several code block related transformations."""
182
175
 
183
176
  default_priority = 210
184
177
 
@@ -200,9 +193,7 @@ class HandleCodeBlocks(SphinxTransform):
200
193
 
201
194
 
202
195
  class AutoNumbering(SphinxTransform):
203
- """
204
- Register IDs of tables, figures and literal_blocks to assign numbers.
205
- """
196
+ """Register IDs of tables, figures and literal_blocks to assign numbers."""
206
197
 
207
198
  default_priority = 210
208
199
 
@@ -219,9 +210,7 @@ class AutoNumbering(SphinxTransform):
219
210
 
220
211
 
221
212
  class SortIds(SphinxTransform):
222
- """
223
- Sort section IDs so that the "id[0-9]+" one comes last.
224
- """
213
+ """Sort section IDs so that the "id[0-9]+" one comes last."""
225
214
 
226
215
  default_priority = 261
227
216
 
@@ -241,9 +230,7 @@ TRANSLATABLE_NODES = {
241
230
 
242
231
 
243
232
  class ApplySourceWorkaround(SphinxTransform):
244
- """
245
- Update source and rawsource attributes
246
- """
233
+ """Update source and rawsource attributes"""
247
234
 
248
235
  default_priority = 10
249
236
 
@@ -254,9 +241,7 @@ class ApplySourceWorkaround(SphinxTransform):
254
241
 
255
242
 
256
243
  class AutoIndexUpgrader(SphinxTransform):
257
- """
258
- Detect old style (4 column based indices) and automatically upgrade to new style.
259
- """
244
+ """Detect old style (4 column based indices) and automatically upgrade to new style."""
260
245
 
261
246
  default_priority = 210
262
247
 
@@ -277,9 +262,7 @@ class AutoIndexUpgrader(SphinxTransform):
277
262
 
278
263
 
279
264
  class ExtraTranslatableNodes(SphinxTransform):
280
- """
281
- Make nodes translatable
282
- """
265
+ """Make nodes translatable"""
283
266
 
284
267
  default_priority = 10
285
268
 
@@ -297,9 +280,7 @@ class ExtraTranslatableNodes(SphinxTransform):
297
280
 
298
281
 
299
282
  class UnreferencedFootnotesDetector(SphinxTransform):
300
- """
301
- Detect unreferenced footnotes and emit warnings
302
- """
283
+ """Detect unreferenced footnotes and emit warnings"""
303
284
 
304
285
  default_priority = Footnotes.default_priority + 2
305
286
 
@@ -361,8 +342,7 @@ class FilterSystemMessages(SphinxTransform):
361
342
 
362
343
 
363
344
  class SphinxContentsFilter(ContentsFilter):
364
- """
365
- Used with BuildEnvironment.add_toc_from() to discard cross-file links
345
+ """Used with BuildEnvironment.add_toc_from() to discard cross-file links
366
346
  within table-of-contents link nodes.
367
347
  """
368
348
 
@@ -373,8 +353,7 @@ class SphinxContentsFilter(ContentsFilter):
373
353
 
374
354
 
375
355
  class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
376
- """
377
- Customized SmartQuotes to avoid transform for some extra node types.
356
+ """Customized SmartQuotes to avoid transform for some extra node types.
378
357
 
379
358
  refs: sphinx.parsers.RSTParser
380
359
  """
@@ -430,7 +409,7 @@ class DoctreeReadEvent(SphinxTransform):
430
409
  default_priority = 880
431
410
 
432
411
  def apply(self, **kwargs: Any) -> None:
433
- self.app.emit('doctree-read', self.document)
412
+ self.app.events.emit('doctree-read', self.document)
434
413
 
435
414
 
436
415
  class GlossarySorter(SphinxTransform):
@@ -443,11 +422,11 @@ class GlossarySorter(SphinxTransform):
443
422
  def apply(self, **kwargs: Any) -> None:
444
423
  for glossary in self.document.findall(addnodes.glossary):
445
424
  if glossary['sorted']:
446
- definition_list = cast(nodes.definition_list, glossary[0])
425
+ definition_list = cast('nodes.definition_list', glossary[0])
447
426
  definition_list[:] = sorted(
448
427
  definition_list,
449
428
  key=lambda item: unicodedata.normalize(
450
- 'NFD', cast(nodes.term, item)[0].astext().lower()
429
+ 'NFD', cast('nodes.term', item)[0].astext().lower()
451
430
  ),
452
431
  )
453
432
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import TYPE_CHECKING, Any, cast
5
+ from typing import TYPE_CHECKING, cast
6
6
 
7
7
  from docutils import nodes
8
8
 
@@ -10,6 +10,8 @@ from sphinx import addnodes
10
10
  from sphinx.transforms import SphinxTransform
11
11
 
12
12
  if TYPE_CHECKING:
13
+ from typing import Any
14
+
13
15
  from docutils.nodes import Node
14
16
 
15
17
  from sphinx.application import Sphinx
@@ -75,8 +77,8 @@ class RefOnlyBulletListTransform(SphinxTransform):
75
77
  for node in self.document.findall(nodes.bullet_list):
76
78
  if check_refonly_list(node):
77
79
  for item in node.findall(nodes.list_item):
78
- para = cast(nodes.paragraph, item[0])
79
- ref = cast(nodes.reference, para[0])
80
+ para = cast('nodes.paragraph', item[0])
81
+ ref = cast('nodes.reference', para[0])
80
82
  compact_para = addnodes.compact_paragraph()
81
83
  compact_para += ref
82
84
  item.replace(para, compact_para)
sphinx/transforms/i18n.py CHANGED
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import contextlib
6
- from os import path
7
6
  from re import DOTALL, match
8
7
  from textwrap import indent
9
8
  from typing import TYPE_CHECKING, Any, TypeVar
@@ -101,9 +100,7 @@ def parse_noqa(source: str) -> tuple[str, bool]:
101
100
 
102
101
 
103
102
  class PreserveTranslatableMessages(SphinxTransform):
104
- """
105
- Preserve original translatable messages before translation
106
- """
103
+ """Preserve original translatable messages before translation"""
107
104
 
108
105
  default_priority = 10 # this MUST be invoked before Locale transform
109
106
 
@@ -381,9 +378,7 @@ class _NodeUpdater:
381
378
 
382
379
 
383
380
  class Locale(SphinxTransform):
384
- """
385
- Replace translatable nodes with their translated doctree.
386
- """
381
+ """Replace translatable nodes with their translated doctree."""
387
382
 
388
383
  default_priority = 20
389
384
 
@@ -394,10 +389,8 @@ class Locale(SphinxTransform):
394
389
  textdomain = docname_to_domain(self.env.docname, self.config.gettext_compact)
395
390
 
396
391
  # fetch translations
397
- dirs = [
398
- path.join(self.env.srcdir, directory)
399
- for directory in self.config.locale_dirs
400
- ]
392
+ srcdir = self.env.srcdir
393
+ dirs = [srcdir / directory for directory in self.config.locale_dirs]
401
394
  catalog, has_catalog = init_locale(dirs, self.config.language, textdomain)
402
395
  if not has_catalog:
403
396
  return
@@ -420,7 +413,7 @@ class Locale(SphinxTransform):
420
413
  if not isinstance(node, LITERAL_TYPE_NODES):
421
414
  msgstr, _ = parse_noqa(msgstr)
422
415
 
423
- if msgstr.strip() == '':
416
+ if not msgstr.strip():
424
417
  # as-of-yet untranslated
425
418
  node['translated'] = False
426
419
  continue
@@ -612,9 +605,7 @@ class Locale(SphinxTransform):
612
605
 
613
606
 
614
607
  class TranslationProgressTotaliser(SphinxTransform):
615
- """
616
- Calculate the number of translated and untranslated nodes.
617
- """
608
+ """Calculate the number of translated and untranslated nodes."""
618
609
 
619
610
  default_priority = 25 # MUST happen after Locale
620
611
 
@@ -637,9 +628,7 @@ class TranslationProgressTotaliser(SphinxTransform):
637
628
 
638
629
 
639
630
  class AddTranslationClasses(SphinxTransform):
640
- """
641
- Add ``translated`` or ``untranslated`` classes to indicate translation status.
642
- """
631
+ """Add ``translated`` or ``untranslated`` classes to indicate translation status."""
643
632
 
644
633
  default_priority = 950
645
634
 
@@ -677,9 +666,7 @@ class AddTranslationClasses(SphinxTransform):
677
666
 
678
667
 
679
668
  class RemoveTranslatableInline(SphinxTransform):
680
- """
681
- Remove inline nodes used for translation as placeholders.
682
- """
669
+ """Remove inline nodes used for translation as placeholders."""
683
670
 
684
671
  default_priority = 999
685
672