Sphinx 7.4.7__py3-none-any.whl → 8.0.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 (107) hide show
  1. sphinx/__init__.py +2 -2
  2. sphinx/_cli/__init__.py +4 -4
  3. sphinx/application.py +7 -7
  4. sphinx/builders/__init__.py +2 -3
  5. sphinx/builders/_epub_base.py +33 -12
  6. sphinx/builders/changes.py +13 -5
  7. sphinx/builders/epub3.py +6 -2
  8. sphinx/builders/html/__init__.py +88 -58
  9. sphinx/builders/latex/__init__.py +38 -12
  10. sphinx/builders/latex/transforms.py +1 -1
  11. sphinx/builders/linkcheck.py +8 -49
  12. sphinx/builders/texinfo.py +12 -6
  13. sphinx/builders/text.py +7 -3
  14. sphinx/builders/xml.py +7 -3
  15. sphinx/cmd/quickstart.py +10 -20
  16. sphinx/config.py +12 -12
  17. sphinx/deprecation.py +8 -8
  18. sphinx/directives/other.py +2 -3
  19. sphinx/directives/patches.py +2 -2
  20. sphinx/domains/__init__.py +4 -2
  21. sphinx/domains/c/__init__.py +2 -2
  22. sphinx/domains/c/_ast.py +3 -2
  23. sphinx/domains/c/_parser.py +4 -3
  24. sphinx/domains/cpp/__init__.py +2 -2
  25. sphinx/domains/cpp/_ast.py +1 -2
  26. sphinx/domains/cpp/_parser.py +2 -2
  27. sphinx/domains/cpp/_symbol.py +2 -2
  28. sphinx/domains/math.py +1 -1
  29. sphinx/domains/python/_object.py +0 -1
  30. sphinx/domains/std/__init__.py +7 -8
  31. sphinx/environment/__init__.py +14 -32
  32. sphinx/environment/adapters/indexentries.py +4 -6
  33. sphinx/environment/adapters/toctree.py +4 -4
  34. sphinx/environment/collectors/title.py +1 -1
  35. sphinx/environment/collectors/toctree.py +1 -1
  36. sphinx/events.py +3 -1
  37. sphinx/ext/autodoc/__init__.py +17 -63
  38. sphinx/ext/autodoc/directive.py +7 -5
  39. sphinx/ext/autodoc/importer.py +2 -1
  40. sphinx/ext/autodoc/preserve_defaults.py +2 -2
  41. sphinx/ext/autosummary/__init__.py +7 -6
  42. sphinx/ext/autosummary/generate.py +5 -4
  43. sphinx/ext/doctest.py +5 -5
  44. sphinx/ext/graphviz.py +1 -1
  45. sphinx/ext/imgmath.py +1 -1
  46. sphinx/ext/inheritance_diagram.py +1 -1
  47. sphinx/ext/intersphinx/__init__.py +25 -5
  48. sphinx/ext/intersphinx/_cli.py +7 -6
  49. sphinx/ext/intersphinx/_load.py +240 -115
  50. sphinx/ext/intersphinx/_resolve.py +12 -11
  51. sphinx/ext/intersphinx/_shared.py +102 -9
  52. sphinx/ext/mathjax.py +1 -1
  53. sphinx/ext/napoleon/docstring.py +2 -2
  54. sphinx/ext/todo.py +2 -2
  55. sphinx/ext/viewcode.py +2 -1
  56. sphinx/highlighting.py +3 -3
  57. sphinx/io.py +2 -2
  58. sphinx/jinja2glue.py +13 -6
  59. sphinx/locale/__init__.py +4 -3
  60. sphinx/project.py +23 -19
  61. sphinx/pycode/ast.py +2 -2
  62. sphinx/pycode/parser.py +2 -2
  63. sphinx/pygments_styles.py +3 -3
  64. sphinx/registry.py +3 -8
  65. sphinx/search/__init__.py +1 -1
  66. sphinx/testing/path.py +2 -1
  67. sphinx/testing/util.py +1 -1
  68. sphinx/texinputs/Makefile.jinja +2 -1
  69. sphinx/texinputs_win/Makefile.jinja +2 -1
  70. sphinx/theming.py +3 -12
  71. sphinx/transforms/__init__.py +5 -5
  72. sphinx/transforms/references.py +1 -1
  73. sphinx/util/__init__.py +11 -35
  74. sphinx/util/_timestamps.py +12 -0
  75. sphinx/util/cfamily.py +5 -5
  76. sphinx/util/console.py +4 -3
  77. sphinx/util/display.py +3 -3
  78. sphinx/util/docfields.py +1 -1
  79. sphinx/util/docutils.py +44 -10
  80. sphinx/util/fileutil.py +25 -20
  81. sphinx/util/i18n.py +9 -4
  82. sphinx/util/images.py +3 -2
  83. sphinx/util/inspect.py +28 -43
  84. sphinx/util/inventory.py +2 -2
  85. sphinx/util/matching.py +2 -2
  86. sphinx/util/math.py +1 -1
  87. sphinx/util/nodes.py +8 -8
  88. sphinx/util/osutil.py +29 -28
  89. sphinx/util/parallel.py +2 -2
  90. sphinx/util/requests.py +1 -1
  91. sphinx/util/template.py +3 -3
  92. sphinx/util/typing.py +36 -72
  93. sphinx/writers/html.py +1 -1
  94. sphinx/writers/html5.py +1 -1
  95. sphinx/writers/latex.py +4 -4
  96. sphinx/writers/manpage.py +2 -2
  97. sphinx/writers/texinfo.py +5 -5
  98. sphinx/writers/text.py +4 -4
  99. sphinx/writers/xml.py +2 -2
  100. {sphinx-7.4.7.dist-info → sphinx-8.0.0rc1.dist-info}/METADATA +10 -9
  101. {sphinx-7.4.7.dist-info → sphinx-8.0.0rc1.dist-info}/RECORD +104 -106
  102. sphinx/templates/quickstart/Makefile.jinja +0 -98
  103. sphinx/templates/quickstart/make.bat.jinja +0 -110
  104. sphinx/util/_pathlib.py +0 -120
  105. {sphinx-7.4.7.dist-info → sphinx-8.0.0rc1.dist-info}/LICENSE.rst +0 -0
  106. {sphinx-7.4.7.dist-info → sphinx-8.0.0rc1.dist-info}/WHEEL +0 -0
  107. {sphinx-7.4.7.dist-info → sphinx-8.0.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/util/typing.py CHANGED
@@ -6,15 +6,15 @@ import dataclasses
6
6
  import sys
7
7
  import types
8
8
  import typing
9
- from collections.abc import Sequence
9
+ from collections.abc import Callable, Sequence
10
10
  from contextvars import Context, ContextVar, Token
11
11
  from struct import Struct
12
12
  from typing import (
13
13
  TYPE_CHECKING,
14
14
  Annotated,
15
15
  Any,
16
- Callable,
17
16
  ForwardRef,
17
+ NewType,
18
18
  TypedDict,
19
19
  TypeVar,
20
20
  Union,
@@ -25,9 +25,9 @@ from docutils.parsers.rst.states import Inliner
25
25
 
26
26
  if TYPE_CHECKING:
27
27
  from collections.abc import Mapping
28
- from typing import Final, Literal, Protocol
28
+ from typing import Final, Literal, Protocol, TypeAlias
29
29
 
30
- from typing_extensions import TypeAlias, TypeIs
30
+ from typing_extensions import TypeIs
31
31
 
32
32
  from sphinx.application import Sphinx
33
33
 
@@ -41,10 +41,6 @@ if TYPE_CHECKING:
41
41
  'smart',
42
42
  ]
43
43
 
44
- if sys.version_info >= (3, 10):
45
- from types import UnionType
46
- else:
47
- UnionType = None
48
44
 
49
45
  # classes that have an incorrect .__module__ attribute
50
46
  _INVALID_BUILTIN_CLASSES: Final[Mapping[object, str]] = {
@@ -85,13 +81,10 @@ def is_invalid_builtin_class(obj: Any) -> bool:
85
81
 
86
82
 
87
83
  # Text like nodes which are initialized with text and rawsource
88
- TextlikeNode = Union[nodes.Text, nodes.TextElement]
89
-
90
- # type of None
91
- NoneType = type(None)
84
+ TextlikeNode: TypeAlias = nodes.Text | nodes.TextElement
92
85
 
93
86
  # path matcher
94
- PathMatcher = Callable[[str], bool]
87
+ PathMatcher: TypeAlias = Callable[[str], bool]
95
88
 
96
89
  # common role functions
97
90
  if TYPE_CHECKING:
@@ -109,25 +102,25 @@ if TYPE_CHECKING:
109
102
  ) -> tuple[list[nodes.Node], list[nodes.system_message]]:
110
103
  ...
111
104
  else:
112
- RoleFunction = Callable[
105
+ RoleFunction: TypeAlias = Callable[
113
106
  [str, str, str, int, Inliner, dict[str, Any], Sequence[str]],
114
107
  tuple[list[nodes.Node], list[nodes.system_message]],
115
108
  ]
116
109
 
117
110
  # A option spec for directive
118
- OptionSpec = dict[str, Callable[[str], Any]]
111
+ OptionSpec: TypeAlias = dict[str, Callable[[str], Any]]
119
112
 
120
113
  # title getter functions for enumerable nodes (see sphinx.domains.std)
121
- TitleGetter = Callable[[nodes.Node], str]
114
+ TitleGetter: TypeAlias = Callable[[nodes.Node], str]
122
115
 
123
116
  # inventory data on memory
124
- InventoryItem = tuple[
117
+ InventoryItem: TypeAlias = tuple[
125
118
  str, # project name
126
119
  str, # project version
127
120
  str, # URL
128
121
  str, # display name
129
122
  ]
130
- Inventory = dict[str, dict[str, InventoryItem]]
123
+ Inventory: TypeAlias = dict[str, dict[str, InventoryItem]]
131
124
 
132
125
 
133
126
  class ExtensionMetadata(TypedDict, total=False):
@@ -151,7 +144,7 @@ class ExtensionMetadata(TypedDict, total=False):
151
144
 
152
145
 
153
146
  if TYPE_CHECKING:
154
- _ExtensionSetupFunc = Callable[[Sphinx], ExtensionMetadata]
147
+ _ExtensionSetupFunc: TypeAlias = Callable[[Sphinx], ExtensionMetadata]
155
148
 
156
149
 
157
150
  def get_type_hints(
@@ -204,24 +197,14 @@ def _is_unpack_form(obj: Any) -> bool:
204
197
  # that typing_extensions.Unpack should not be used in that case
205
198
  return typing.get_origin(obj) is Unpack
206
199
 
207
- # 3.9 and 3.10 require typing_extensions.Unpack
200
+ # Python 3.10 requires typing_extensions.Unpack
208
201
  origin = typing.get_origin(obj)
209
202
  return (
210
203
  getattr(origin, '__module__', None) == 'typing_extensions'
211
- and _typing_internal_name(origin) == 'Unpack'
204
+ and origin.__name__ == 'Unpack'
212
205
  )
213
206
 
214
207
 
215
- def _typing_internal_name(obj: Any) -> str | None:
216
- if sys.version_info[:2] >= (3, 10):
217
- try:
218
- return obj.__name__
219
- except AttributeError:
220
- # e.g. ParamSpecArgs, ParamSpecKwargs
221
- return ''
222
- return getattr(obj, '_name', None)
223
-
224
-
225
208
  def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> str:
226
209
  """Convert a type-like object to a reST reference.
227
210
 
@@ -234,7 +217,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
234
217
  Show the name of the annotation.
235
218
  """
236
219
  from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
237
- from sphinx.util import inspect # lazy loading
220
+ from sphinx.util.inspect import isgenericalias, object_description # lazy loading
238
221
 
239
222
  valid_modes = {'fully-qualified-except-typing', 'smart'}
240
223
  if mode not in valid_modes:
@@ -243,7 +226,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
243
226
  raise ValueError(msg)
244
227
 
245
228
  # things that are not types
246
- if cls is None or cls == NoneType:
229
+ if cls is None or cls == types.NoneType:
247
230
  return ':py:obj:`None`'
248
231
  if cls is Ellipsis:
249
232
  return '...'
@@ -288,12 +271,9 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
288
271
  return fr':py:class:`~typing.Annotated`\ [{args}, {meta}]'
289
272
  return (f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
290
273
  fr'\ [{args}, {meta}]')
291
- elif inspect.isNewType(cls):
292
- if sys.version_info[:2] >= (3, 10):
293
- # newtypes have correct module info since Python 3.10+
294
- return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
295
- return f':py:class:`{cls.__name__}`'
296
- elif UnionType and isinstance(cls, UnionType):
274
+ elif isinstance(cls, NewType):
275
+ return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`' # type: ignore[attr-defined]
276
+ elif isinstance(cls, types.UnionType):
297
277
  # Union types (PEP 585) retain their definition order when they
298
278
  # are printed natively and ``None``-like types are kept as is.
299
279
  return ' | '.join(restify(a, mode) for a in cls.__args__)
@@ -305,23 +285,18 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
305
285
  concatenated_args = ', '.join(restify(arg, mode) for arg in cls.__args__)
306
286
  return fr':py:class:`{cls.__name__}`\ [{concatenated_args}]'
307
287
  return f':py:class:`{cls.__name__}`'
308
- elif (inspect.isgenericalias(cls)
288
+ elif (isgenericalias(cls)
309
289
  and cls_module_is_typing
310
290
  and cls.__origin__ is Union):
311
291
  # *cls* is defined in ``typing``, and thus ``__args__`` must exist
312
292
  return ' | '.join(restify(a, mode) for a in cls.__args__)
313
- elif inspect.isgenericalias(cls):
314
- # A generic alias always has an __origin__, but it is difficult to
315
- # use a type guard on inspect.isgenericalias()
316
- # (ideally, we would use ``TypeIs`` introduced in Python 3.13).
317
- cls_name = _typing_internal_name(cls)
318
-
293
+ elif isgenericalias(cls):
319
294
  if isinstance(cls.__origin__, typing._SpecialForm):
320
295
  # ClassVar; Concatenate; Final; Literal; Unpack; TypeGuard; TypeIs
321
296
  # Required/NotRequired
322
297
  text = restify(cls.__origin__, mode)
323
- elif cls_name:
324
- text = f':py:class:`{module_prefix}{cls.__module__}.{cls_name}`'
298
+ elif cls.__name__:
299
+ text = f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
325
300
  else:
326
301
  text = restify(cls.__origin__, mode)
327
302
 
@@ -334,14 +309,14 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
334
309
 
335
310
  # Callable has special formatting
336
311
  if (
337
- (cls_module_is_typing and _typing_internal_name(cls) == 'Callable')
312
+ (cls_module_is_typing and cls.__name__ == 'Callable')
338
313
  or (cls.__module__ == 'collections.abc' and cls.__name__ == 'Callable')
339
314
  ):
340
315
  args = ', '.join(restify(a, mode) for a in __args__[:-1])
341
316
  returns = restify(__args__[-1], mode)
342
317
  return fr'{text}\ [[{args}], {returns}]'
343
318
 
344
- if cls_module_is_typing and _typing_internal_name(cls.__origin__) == 'Literal':
319
+ if cls_module_is_typing and cls.__origin__.__name__ == 'Literal':
345
320
  args = ', '.join(_format_literal_arg_restify(a, mode=mode)
346
321
  for a in cls.__args__)
347
322
  return fr'{text}\ [{args}]'
@@ -350,8 +325,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
350
325
  args = ', '.join(restify(a, mode) for a in __args__)
351
326
  return fr'{text}\ [{args}]'
352
327
  elif isinstance(cls, typing._SpecialForm):
353
- cls_name = _typing_internal_name(cls)
354
- return f':py:obj:`~{cls.__module__}.{cls_name}`'
328
+ return f':py:obj:`~{cls.__module__}.{cls.__name__}`' # type: ignore[attr-defined]
355
329
  elif sys.version_info[:2] >= (3, 11) and cls is typing.Any:
356
330
  # handle bpo-46998
357
331
  return f':py:obj:`~{cls.__module__}.{cls.__name__}`'
@@ -363,7 +337,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
363
337
  # not a class (ex. TypeVar) but should have a __name__
364
338
  return f':py:obj:`{module_prefix}{cls.__module__}.{cls.__name__}`'
365
339
  except (AttributeError, TypeError):
366
- return inspect.object_description(cls)
340
+ return object_description(cls)
367
341
 
368
342
 
369
343
  def _format_literal_arg_restify(arg: Any, /, *, mode: str) -> str:
@@ -398,7 +372,6 @@ def stringify_annotation(
398
372
  Show the module name and qualified name of the annotation.
399
373
  """
400
374
  from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
401
- from sphinx.util.inspect import isNewType # lazy loading
402
375
 
403
376
  valid_modes = {'fully-qualified-except-typing', 'fully-qualified', 'smart'}
404
377
  if mode not in valid_modes:
@@ -407,7 +380,7 @@ def stringify_annotation(
407
380
  raise ValueError(msg)
408
381
 
409
382
  # things that are not types
410
- if annotation is None or annotation == NoneType:
383
+ if annotation is None or annotation == types.NoneType:
411
384
  return 'None'
412
385
  if annotation is Ellipsis:
413
386
  return '...'
@@ -433,18 +406,15 @@ def stringify_annotation(
433
406
  if annotation_module_is_typing and mode in {'fully-qualified-except-typing', 'smart'}:
434
407
  return annotation_name
435
408
  return module_prefix + f'{annotation_module}.{annotation_name}'
436
- elif isNewType(annotation):
437
- if sys.version_info[:2] >= (3, 10):
438
- # newtypes have correct module info since Python 3.10+
439
- return module_prefix + f'{annotation_module}.{annotation_name}'
440
- return annotation_name
409
+ elif isinstance(annotation, NewType):
410
+ return module_prefix + f'{annotation_module}.{annotation_name}'
441
411
  elif ismockmodule(annotation):
442
412
  return module_prefix + annotation_name
443
413
  elif ismock(annotation):
444
414
  return module_prefix + f'{annotation_module}.{annotation_name}'
445
415
  elif is_invalid_builtin_class(annotation):
446
416
  return module_prefix + _INVALID_BUILTIN_CLASSES[annotation]
447
- elif _is_annotated_form(annotation): # for py39+
417
+ elif _is_annotated_form(annotation): # for py310+
448
418
  pass
449
419
  elif annotation_module == 'builtins' and annotation_qualname:
450
420
  args = getattr(annotation, '__args__', None)
@@ -478,8 +448,8 @@ def stringify_annotation(
478
448
  # handle ForwardRefs
479
449
  qualname = annotation_forward_arg
480
450
  else:
481
- if internal_name := _typing_internal_name(annotation):
482
- qualname = internal_name
451
+ if annotation_name:
452
+ qualname = annotation_name
483
453
  elif annotation_qualname:
484
454
  qualname = annotation_qualname
485
455
  else:
@@ -493,7 +463,7 @@ def stringify_annotation(
493
463
  elif hasattr(annotation, '__origin__'):
494
464
  # instantiated generic provided by a user
495
465
  qualname = stringify_annotation(annotation.__origin__, mode)
496
- elif UnionType and isinstance(annotation, UnionType): # types.UnionType (for py3.10+)
466
+ elif isinstance(annotation, types.UnionType):
497
467
  qualname = 'types.UnionType'
498
468
  else:
499
469
  # we weren't able to extract the base type, appending arguments would
@@ -503,7 +473,7 @@ def stringify_annotation(
503
473
  # Process the generic arguments (if any).
504
474
  # They must be a list or a tuple, otherwise they are considered 'broken'.
505
475
  annotation_args = getattr(annotation, '__args__', ())
506
- if annotation_args and isinstance(annotation_args, (list, tuple)):
476
+ if annotation_args and isinstance(annotation_args, list | tuple):
507
477
  if (
508
478
  qualname in {'Union', 'types.UnionType'}
509
479
  and all(getattr(a, '__origin__', ...) is typing.Literal for a in annotation_args)
@@ -523,7 +493,7 @@ def stringify_annotation(
523
493
  args = ', '.join(_format_literal_arg_stringify(a, mode=mode)
524
494
  for a in annotation_args)
525
495
  return f'{module_prefix}Literal[{args}]'
526
- elif _is_annotated_form(annotation): # for py39+
496
+ elif _is_annotated_form(annotation): # for py310+
527
497
  args = stringify_annotation(annotation_args[0], mode)
528
498
  meta_args = []
529
499
  for m in annotation.__metadata__:
@@ -539,11 +509,6 @@ def stringify_annotation(
539
509
  else:
540
510
  meta_args.append(repr(m))
541
511
  meta = ', '.join(meta_args)
542
- if sys.version_info[:2] <= (3, 9):
543
- if mode == 'smart':
544
- return f'~typing.Annotated[{args}, {meta}]'
545
- if mode == 'fully-qualified':
546
- return f'typing.Annotated[{args}, {meta}]'
547
512
  if sys.version_info[:2] <= (3, 11):
548
513
  if mode == 'fully-qualified-except-typing':
549
514
  return f'Annotated[{args}, {meta}]'
@@ -575,7 +540,6 @@ def _format_literal_arg_stringify(arg: Any, /, *, mode: str) -> str:
575
540
 
576
541
  # deprecated name -> (object to return, canonical path or empty string, removal version)
577
542
  _DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
578
- 'stringify': (stringify_annotation, 'sphinx.util.typing.stringify_annotation', (8, 0)),
579
543
  }
580
544
 
581
545
 
sphinx/writers/html.py CHANGED
@@ -20,7 +20,7 @@ HTMLTranslator = HTML5Translator
20
20
  # https://www.arnebrodowski.de/blog/write-your-own-restructuredtext-writer.html
21
21
 
22
22
 
23
- class HTMLWriter(Writer):
23
+ class HTMLWriter(Writer): # type: ignore[misc]
24
24
 
25
25
  # override embed-stylesheet default value to False.
26
26
  settings_default_overrides = {"embed_stylesheet": False}
sphinx/writers/html5.py CHANGED
@@ -43,7 +43,7 @@ def multiply_length(length: str, scale: int) -> str:
43
43
  return f"{int(result)}{unit}"
44
44
 
45
45
 
46
- class HTML5Translator(SphinxTranslator, BaseTranslator):
46
+ class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
47
47
  """
48
48
  Our custom HTML translator.
49
49
  """
sphinx/writers/latex.py CHANGED
@@ -66,7 +66,7 @@ class UnsupportedError(SphinxError):
66
66
  category = 'Markup is unsupported in LaTeX'
67
67
 
68
68
 
69
- class LaTeXWriter(writers.Writer):
69
+ class LaTeXWriter(writers.Writer): # type: ignore[misc]
70
70
 
71
71
  supported = ('sphinxlatex',)
72
72
 
@@ -1369,7 +1369,7 @@ class LaTeXTranslator(SphinxTranslator):
1369
1369
  not isinstance(node.parent[index - 1], nodes.compound)):
1370
1370
  # insert blank line, if the paragraph follows a non-paragraph node in a compound
1371
1371
  self.body.append(r'\noindent' + CR)
1372
- elif index == 1 and isinstance(node.parent, (nodes.footnote, footnotetext)):
1372
+ elif index == 1 and isinstance(node.parent, nodes.footnote | footnotetext):
1373
1373
  # don't insert blank line, if the paragraph is second child of a footnote
1374
1374
  # (first one is label node)
1375
1375
  pass
@@ -2081,7 +2081,7 @@ class LaTeXTranslator(SphinxTranslator):
2081
2081
  done = 0
2082
2082
  if len(node.children) == 1:
2083
2083
  child = node.children[0]
2084
- if isinstance(child, (nodes.bullet_list, nodes.enumerated_list)):
2084
+ if isinstance(child, nodes.bullet_list | nodes.enumerated_list):
2085
2085
  done = 1
2086
2086
  if not done:
2087
2087
  self.body.append(r'\begin{quote}' + CR)
@@ -2092,7 +2092,7 @@ class LaTeXTranslator(SphinxTranslator):
2092
2092
  done = 0
2093
2093
  if len(node.children) == 1:
2094
2094
  child = node.children[0]
2095
- if isinstance(child, (nodes.bullet_list, nodes.enumerated_list)):
2095
+ if isinstance(child, nodes.bullet_list | nodes.enumerated_list):
2096
2096
  done = 1
2097
2097
  if not done:
2098
2098
  self.body.append(r'\end{quote}' + CR)
sphinx/writers/manpage.py CHANGED
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
24
24
  logger = logging.getLogger(__name__)
25
25
 
26
26
 
27
- class ManualPageWriter(Writer):
27
+ class ManualPageWriter(Writer): # type: ignore[misc]
28
28
  def __init__(self, builder: Builder) -> None:
29
29
  super().__init__()
30
30
  self.builder = builder
@@ -70,7 +70,7 @@ class NestedInlineTransform:
70
70
  node.parent.remove(node)
71
71
 
72
72
 
73
- class ManualPageTranslator(SphinxTranslator, BaseTranslator):
73
+ class ManualPageTranslator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
74
74
  """
75
75
  Custom man page translator.
76
76
  """
sphinx/writers/texinfo.py CHANGED
@@ -105,7 +105,7 @@ def smart_capwords(s: str, sep: str | None = None) -> str:
105
105
  return (sep or ' ').join(words)
106
106
 
107
107
 
108
- class TexinfoWriter(writers.Writer):
108
+ class TexinfoWriter(writers.Writer): # type: ignore[misc]
109
109
  """Texinfo writer for generating Texinfo documents."""
110
110
 
111
111
  supported = ('texinfo', 'texi')
@@ -297,7 +297,7 @@ class TexinfoTranslator(SphinxTranslator):
297
297
  # try to find a suitable "Top" node
298
298
  title = self.document.next_node(nodes.title)
299
299
  top = title.parent if title else self.document
300
- if not isinstance(top, (nodes.document, nodes.section)):
300
+ if not isinstance(top, nodes.document | nodes.section):
301
301
  top = self.document
302
302
  if top is not self.document:
303
303
  entries = node_menus[top['node_name']]
@@ -625,7 +625,7 @@ class TexinfoTranslator(SphinxTranslator):
625
625
  parent = node.parent
626
626
  if isinstance(parent, nodes.table):
627
627
  return
628
- if isinstance(parent, (nodes.Admonition, nodes.sidebar, nodes.topic)):
628
+ if isinstance(parent, nodes.Admonition | nodes.sidebar | nodes.topic):
629
629
  raise nodes.SkipNode
630
630
  if not isinstance(parent, nodes.section):
631
631
  logger.warning(__('encountered title node not in section, topic, table, '
@@ -694,7 +694,7 @@ class TexinfoTranslator(SphinxTranslator):
694
694
  def visit_reference(self, node: Element) -> None:
695
695
  # an xref's target is displayed in Info so we ignore a few
696
696
  # cases for the sake of appearance
697
- if isinstance(node.parent, (nodes.title, addnodes.desc_type)):
697
+ if isinstance(node.parent, nodes.title | addnodes.desc_type):
698
698
  return
699
699
  if len(node) != 0 and isinstance(node[0], nodes.image):
700
700
  return
@@ -987,7 +987,7 @@ class TexinfoTranslator(SphinxTranslator):
987
987
  self.add_anchor(id, node)
988
988
  # anchors and indexes need to go in front
989
989
  for n in node[::]:
990
- if isinstance(n, (addnodes.index, nodes.target)):
990
+ if isinstance(n, addnodes.index | nodes.target):
991
991
  n.walkabout(self)
992
992
  node.remove(n)
993
993
  self.body.append('\n%s ' % self.at_item_x)
sphinx/writers/text.py CHANGED
@@ -6,7 +6,7 @@ import os
6
6
  import re
7
7
  import textwrap
8
8
  from collections.abc import Iterable, Iterator, Sequence
9
- from itertools import chain, groupby
9
+ from itertools import chain, groupby, pairwise
10
10
  from typing import TYPE_CHECKING, Any, cast
11
11
 
12
12
  from docutils import nodes, writers
@@ -221,10 +221,10 @@ class Table:
221
221
  tail = "+" if out[-1][0] == "-" else "|"
222
222
  glue = [
223
223
  "+" if left[0] == "-" or right[0] == "-" else "|"
224
- for left, right in zip(out, out[1:])
224
+ for left, right in pairwise(out)
225
225
  ]
226
226
  glue.append(tail)
227
- return head + "".join(chain.from_iterable(zip(out, glue)))
227
+ return head + "".join(chain.from_iterable(zip(out, glue, strict=False)))
228
228
 
229
229
  for lineno, line in enumerate(self.lines):
230
230
  if self.separator and lineno == self.separator:
@@ -356,7 +356,7 @@ def my_wrap(text: str, width: int = MAXWIDTH, **kwargs: Any) -> list[str]:
356
356
  return w.wrap(text)
357
357
 
358
358
 
359
- class TextWriter(writers.Writer):
359
+ class TextWriter(writers.Writer): # type: ignore[misc]
360
360
  supported = ('text',)
361
361
  settings_spec = ('No options here.', '', ())
362
362
  settings_defaults: dict[str, Any] = {}
sphinx/writers/xml.py CHANGED
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
10
10
  from sphinx.builders import Builder
11
11
 
12
12
 
13
- class XMLWriter(BaseXMLWriter):
13
+ class XMLWriter(BaseXMLWriter): # type: ignore[misc]
14
14
  output: str
15
15
 
16
16
  def __init__(self, builder: Builder) -> None:
@@ -29,7 +29,7 @@ class XMLWriter(BaseXMLWriter):
29
29
  return super().translate()
30
30
 
31
31
 
32
- class PseudoXMLWriter(BaseXMLWriter):
32
+ class PseudoXMLWriter(BaseXMLWriter): # type: ignore[misc]
33
33
 
34
34
  supported = ('pprint', 'pformat', 'pseudoxml')
35
35
  """Formats this writer supports."""
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Sphinx
3
- Version: 7.4.7
3
+ Version: 8.0.0rc1
4
4
  Summary: Python documentation generator
5
5
  Author-email: Georg Brandl <georg@python.org>
6
- Requires-Python: >=3.9
6
+ Requires-Python: >=3.10
7
7
  Description-Content-Type: text/x-rst
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Environment :: Console
@@ -18,7 +18,6 @@ Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python
19
19
  Classifier: Programming Language :: Python :: 3
20
20
  Classifier: Programming Language :: Python :: 3 :: Only
21
- Classifier: Programming Language :: Python :: 3.9
22
21
  Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
@@ -57,17 +56,19 @@ Requires-Dist: alabaster~=0.7.14
57
56
  Requires-Dist: imagesize>=1.3
58
57
  Requires-Dist: requests>=2.30.0
59
58
  Requires-Dist: packaging>=23.0
60
- Requires-Dist: importlib-metadata>=6.0; python_version < '3.10'
61
59
  Requires-Dist: tomli>=2; python_version < '3.11'
62
60
  Requires-Dist: colorama>=0.4.6; sys_platform == 'win32'
63
61
  Requires-Dist: sphinxcontrib-websupport ; extra == "docs"
64
62
  Requires-Dist: flake8>=6.0 ; extra == "lint"
65
- Requires-Dist: ruff==0.5.2 ; extra == "lint"
66
- Requires-Dist: mypy==1.10.1 ; extra == "lint"
63
+ Requires-Dist: ruff==0.5.4 ; extra == "lint"
64
+ Requires-Dist: mypy==1.11.0 ; extra == "lint"
67
65
  Requires-Dist: sphinx-lint>=0.9 ; extra == "lint"
68
- Requires-Dist: types-docutils==0.21.0.20240711 ; extra == "lint"
66
+ Requires-Dist: types-colorama==0.4.15.20240311 ; extra == "lint"
67
+ Requires-Dist: types-defusedxml==0.7.0.20240218 ; extra == "lint"
68
+ Requires-Dist: types-docutils==0.21.0.20240724 ; extra == "lint"
69
+ Requires-Dist: types-Pillow==10.2.0.20240520 ; extra == "lint"
70
+ Requires-Dist: types-Pygments==2.18.0.20240506 ; extra == "lint"
69
71
  Requires-Dist: types-requests>=2.30.0 ; extra == "lint"
70
- Requires-Dist: importlib-metadata>=6.0 ; extra == "lint"
71
72
  Requires-Dist: tomli>=2 ; extra == "lint"
72
73
  Requires-Dist: pytest>=6.0 ; extra == "lint"
73
74
  Requires-Dist: pytest>=8.0 ; extra == "test"
@@ -134,7 +135,7 @@ Installation
134
135
  The following command installs Sphinx from the `Python Package Index`_. You will
135
136
  need a working installation of Python and pip.
136
137
 
137
- .. code-block:: sh
138
+ .. code-block:: shell
138
139
 
139
140
  pip install -U sphinx
140
141