Sphinx 7.4.6__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 (115) 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 +90 -59
  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/__init__.py +14 -9
  19. sphinx/directives/other.py +2 -3
  20. sphinx/directives/patches.py +2 -2
  21. sphinx/domains/__init__.py +4 -2
  22. sphinx/domains/c/__init__.py +2 -2
  23. sphinx/domains/c/_ast.py +3 -2
  24. sphinx/domains/c/_parser.py +4 -3
  25. sphinx/domains/cpp/__init__.py +2 -2
  26. sphinx/domains/cpp/_ast.py +1 -2
  27. sphinx/domains/cpp/_parser.py +2 -2
  28. sphinx/domains/cpp/_symbol.py +2 -2
  29. sphinx/domains/javascript.py +1 -1
  30. sphinx/domains/math.py +1 -1
  31. sphinx/domains/python/__init__.py +1 -1
  32. sphinx/domains/python/_annotations.py +23 -1
  33. sphinx/domains/python/_object.py +0 -1
  34. sphinx/domains/std/__init__.py +7 -8
  35. sphinx/environment/__init__.py +14 -32
  36. sphinx/environment/adapters/indexentries.py +4 -6
  37. sphinx/environment/adapters/toctree.py +4 -4
  38. sphinx/environment/collectors/title.py +1 -1
  39. sphinx/environment/collectors/toctree.py +1 -1
  40. sphinx/events.py +3 -1
  41. sphinx/ext/autodoc/__init__.py +25 -67
  42. sphinx/ext/autodoc/directive.py +7 -5
  43. sphinx/ext/autodoc/importer.py +2 -1
  44. sphinx/ext/autodoc/preserve_defaults.py +2 -2
  45. sphinx/ext/autosummary/__init__.py +15 -7
  46. sphinx/ext/autosummary/generate.py +5 -4
  47. sphinx/ext/doctest.py +5 -5
  48. sphinx/ext/graphviz.py +1 -1
  49. sphinx/ext/imgmath.py +1 -1
  50. sphinx/ext/inheritance_diagram.py +1 -1
  51. sphinx/ext/intersphinx/__init__.py +25 -5
  52. sphinx/ext/intersphinx/_cli.py +7 -6
  53. sphinx/ext/intersphinx/_load.py +240 -115
  54. sphinx/ext/intersphinx/_resolve.py +12 -11
  55. sphinx/ext/intersphinx/_shared.py +102 -9
  56. sphinx/ext/mathjax.py +1 -1
  57. sphinx/ext/napoleon/docstring.py +2 -2
  58. sphinx/ext/todo.py +2 -2
  59. sphinx/ext/viewcode.py +2 -1
  60. sphinx/highlighting.py +3 -3
  61. sphinx/io.py +2 -2
  62. sphinx/jinja2glue.py +13 -6
  63. sphinx/locale/__init__.py +4 -3
  64. sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
  65. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  66. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1578 -1843
  67. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +496 -704
  68. sphinx/project.py +23 -19
  69. sphinx/pycode/ast.py +2 -2
  70. sphinx/pycode/parser.py +2 -2
  71. sphinx/pygments_styles.py +3 -3
  72. sphinx/registry.py +3 -8
  73. sphinx/search/__init__.py +1 -1
  74. sphinx/testing/path.py +2 -1
  75. sphinx/testing/util.py +1 -1
  76. sphinx/texinputs/Makefile.jinja +2 -1
  77. sphinx/texinputs_win/Makefile.jinja +2 -1
  78. sphinx/theming.py +3 -12
  79. sphinx/transforms/__init__.py +5 -5
  80. sphinx/transforms/references.py +1 -1
  81. sphinx/util/__init__.py +11 -35
  82. sphinx/util/_timestamps.py +12 -0
  83. sphinx/util/cfamily.py +5 -5
  84. sphinx/util/console.py +4 -3
  85. sphinx/util/display.py +3 -3
  86. sphinx/util/docfields.py +1 -1
  87. sphinx/util/docutils.py +44 -10
  88. sphinx/util/fileutil.py +41 -9
  89. sphinx/util/i18n.py +9 -4
  90. sphinx/util/images.py +3 -2
  91. sphinx/util/inspect.py +29 -44
  92. sphinx/util/inventory.py +2 -2
  93. sphinx/util/matching.py +2 -2
  94. sphinx/util/math.py +1 -1
  95. sphinx/util/nodes.py +8 -8
  96. sphinx/util/osutil.py +46 -23
  97. sphinx/util/parallel.py +2 -2
  98. sphinx/util/requests.py +1 -1
  99. sphinx/util/template.py +3 -3
  100. sphinx/util/typing.py +67 -70
  101. sphinx/writers/html.py +1 -1
  102. sphinx/writers/html5.py +1 -1
  103. sphinx/writers/latex.py +4 -4
  104. sphinx/writers/manpage.py +2 -2
  105. sphinx/writers/texinfo.py +5 -5
  106. sphinx/writers/text.py +4 -4
  107. sphinx/writers/xml.py +2 -2
  108. {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/METADATA +10 -9
  109. {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/RECORD +112 -114
  110. sphinx/templates/quickstart/Makefile.jinja +0 -98
  111. sphinx/templates/quickstart/make.bat.jinja +0 -110
  112. sphinx/util/_pathlib.py +0 -120
  113. {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/LICENSE.rst +0 -0
  114. {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/WHEEL +0 -0
  115. {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/entry_points.txt +0 -0
@@ -19,7 +19,7 @@ from sphinx.domains.c._ids import _macroKeywords, _max_id
19
19
  from sphinx.domains.c._parser import DefinitionParser
20
20
  from sphinx.domains.c._symbol import Symbol, _DuplicateSymbolError
21
21
  from sphinx.locale import _, __
22
- from sphinx.roles import SphinxRole, XRefRole
22
+ from sphinx.roles import XRefRole
23
23
  from sphinx.transforms import SphinxTransform
24
24
  from sphinx.transforms.post_transforms import ReferencesResolver
25
25
  from sphinx.util import logging
@@ -29,7 +29,7 @@ from sphinx.util.cfamily import (
29
29
  anon_identifier_re,
30
30
  )
31
31
  from sphinx.util.docfields import Field, GroupedField, TypedField
32
- from sphinx.util.docutils import SphinxDirective
32
+ from sphinx.util.docutils import SphinxDirective, SphinxRole
33
33
  from sphinx.util.nodes import make_refnode
34
34
 
35
35
  if TYPE_CHECKING:
sphinx/domains/c/_ast.py CHANGED
@@ -12,19 +12,20 @@ from sphinx.util.cfamily import (
12
12
  ASTAttributeList,
13
13
  ASTBaseBase,
14
14
  ASTBaseParenExprList,
15
- StringifyTransform,
16
15
  UnsupportedMultiCharacterCharLiteral,
17
16
  verify_description_mode,
18
17
  )
19
18
 
20
19
  if TYPE_CHECKING:
20
+ from typing import TypeAlias
21
21
 
22
22
  from docutils.nodes import Element, Node, TextElement
23
23
 
24
24
  from sphinx.domains.c._symbol import Symbol
25
25
  from sphinx.environment import BuildEnvironment
26
+ from sphinx.util.cfamily import StringifyTransform
26
27
 
27
- DeclarationType = Union[
28
+ DeclarationType: TypeAlias = Union[ # NoQA: UP007
28
29
  "ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
29
30
  "ASTType", "ASTTypeWithInit", "ASTMacro",
30
31
  ]
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Callable
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from sphinx.domains.c._ast import (
6
6
  ASTAlignofExpr,
@@ -53,7 +53,6 @@ from sphinx.domains.c._ast import (
53
53
  ASTTypeWithInit,
54
54
  ASTUnaryOpExpr,
55
55
  ASTUnion,
56
- DeclarationType,
57
56
  )
58
57
  from sphinx.domains.c._ids import (
59
58
  _expression_assignment_ops,
@@ -80,7 +79,9 @@ from sphinx.util.cfamily import (
80
79
  )
81
80
 
82
81
  if TYPE_CHECKING:
83
- from collections.abc import Sequence
82
+ from collections.abc import Callable, Sequence
83
+
84
+ from sphinx.domains.c._ast import DeclarationType
84
85
 
85
86
 
86
87
  class DefinitionParser(BaseParser):
@@ -23,7 +23,7 @@ from sphinx.domains.cpp._parser import DefinitionParser
23
23
  from sphinx.domains.cpp._symbol import Symbol, _DuplicateSymbolError
24
24
  from sphinx.errors import NoUri
25
25
  from sphinx.locale import _, __
26
- from sphinx.roles import SphinxRole, XRefRole
26
+ from sphinx.roles import XRefRole
27
27
  from sphinx.transforms import SphinxTransform
28
28
  from sphinx.transforms.post_transforms import ReferencesResolver
29
29
  from sphinx.util import logging
@@ -33,7 +33,7 @@ from sphinx.util.cfamily import (
33
33
  anon_identifier_re,
34
34
  )
35
35
  from sphinx.util.docfields import Field, GroupedField
36
- from sphinx.util.docutils import SphinxDirective
36
+ from sphinx.util.docutils import SphinxDirective, SphinxRole
37
37
  from sphinx.util.nodes import make_refnode
38
38
 
39
39
  if TYPE_CHECKING:
@@ -24,18 +24,17 @@ from sphinx.util.cfamily import (
24
24
  ASTBaseBase,
25
25
  ASTBaseParenExprList,
26
26
  NoOldIdError,
27
- StringifyTransform,
28
27
  UnsupportedMultiCharacterCharLiteral,
29
28
  verify_description_mode,
30
29
  )
31
30
 
32
31
  if TYPE_CHECKING:
33
-
34
32
  from docutils.nodes import Element, TextElement
35
33
 
36
34
  from sphinx.addnodes import desc_signature
37
35
  from sphinx.domains.cpp._symbol import Symbol
38
36
  from sphinx.environment import BuildEnvironment
37
+ from sphinx.util.cfamily import StringifyTransform
39
38
 
40
39
 
41
40
  class ASTBase(ASTBaseBase):
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import re
4
- from typing import TYPE_CHECKING, Any, Callable
4
+ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from sphinx.domains.cpp._ast import (
7
7
  ASTAlignofExpr,
@@ -127,7 +127,7 @@ from sphinx.util.cfamily import (
127
127
  )
128
128
 
129
129
  if TYPE_CHECKING:
130
- from collections.abc import Sequence
130
+ from collections.abc import Callable, Sequence
131
131
 
132
132
  logger = logging.getLogger(__name__)
133
133
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Callable, NoReturn
3
+ from typing import TYPE_CHECKING, Any, NoReturn
4
4
 
5
5
  from sphinx.domains.cpp._ast import (
6
6
  ASTDeclaration,
@@ -17,7 +17,7 @@ from sphinx.locale import __
17
17
  from sphinx.util import logging
18
18
 
19
19
  if TYPE_CHECKING:
20
- from collections.abc import Iterator
20
+ from collections.abc import Callable, Iterator
21
21
 
22
22
  from sphinx.environment import BuildEnvironment
23
23
 
@@ -309,7 +309,7 @@ class JSModule(SphinxDirective):
309
309
  def run(self) -> list[Node]:
310
310
  mod_name = self.arguments[0].strip()
311
311
  self.env.ref_context['js:module'] = mod_name
312
- no_index = 'no-index' in self.options or 'noindex' in self.options
312
+ no_index = 'no-index' in self.options
313
313
 
314
314
  content_nodes = self.parse_content_to_nodes(allow_section_headings=True)
315
315
 
sphinx/domains/math.py CHANGED
@@ -74,7 +74,7 @@ class MathDomain(Domain):
74
74
  def process_doc(self, env: BuildEnvironment, docname: str,
75
75
  document: nodes.document) -> None:
76
76
  def math_node(node: Node) -> bool:
77
- return isinstance(node, (nodes.math, nodes.math_block))
77
+ return isinstance(node, nodes.math | nodes.math_block)
78
78
 
79
79
  self.data['has_equations'][docname] = any(document.findall(math_node))
80
80
 
@@ -452,7 +452,7 @@ class PyModule(SphinxDirective):
452
452
  domain = cast(PythonDomain, self.env.get_domain('py'))
453
453
 
454
454
  modname = self.arguments[0].strip()
455
- no_index = 'no-index' in self.options or 'noindex' in self.options
455
+ no_index = 'no-index' in self.options
456
456
  self.env.ref_context['py:module'] = modname
457
457
 
458
458
  content_nodes = self.parse_content_to_nodes(allow_section_headings=True)
@@ -161,7 +161,29 @@ def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
161
161
  addnodes.desc_sig_punctuation('', ')')]
162
162
 
163
163
  return result
164
- raise SyntaxError # unsupported syntax
164
+ if isinstance(node, ast.Call):
165
+ # Call nodes can be used in Annotated type metadata,
166
+ # for example Annotated[str, ArbitraryTypeValidator(str, len=10)]
167
+ args = []
168
+ for arg in node.args:
169
+ args += unparse(arg)
170
+ args.append(addnodes.desc_sig_punctuation('', ','))
171
+ args.append(addnodes.desc_sig_space())
172
+ for kwd in node.keywords:
173
+ args.append(addnodes.desc_sig_name(kwd.arg, kwd.arg)) # type: ignore[arg-type]
174
+ args.append(addnodes.desc_sig_operator('', '='))
175
+ args += unparse(kwd.value)
176
+ args.append(addnodes.desc_sig_punctuation('', ','))
177
+ args.append(addnodes.desc_sig_space())
178
+ result = [
179
+ *unparse(node.func),
180
+ addnodes.desc_sig_punctuation('', '('),
181
+ *args[:-2], # skip the final comma and space
182
+ addnodes.desc_sig_punctuation('', ')'),
183
+ ]
184
+ return result
185
+ msg = f'unsupported syntax: {node}'
186
+ raise SyntaxError(msg) # unsupported syntax
165
187
 
166
188
  def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
167
189
  subscript = node.slice
@@ -25,7 +25,6 @@ from sphinx.util.nodes import (
25
25
  )
26
26
 
27
27
  if TYPE_CHECKING:
28
-
29
28
  from docutils.nodes import Node
30
29
  from docutils.parsers.rst.states import Inliner
31
30
 
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  from copy import copy
7
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Final, cast
7
+ from typing import TYPE_CHECKING, Any, ClassVar, Final, cast
8
8
 
9
9
  from docutils import nodes
10
10
  from docutils.nodes import Element, Node, system_message
@@ -23,7 +23,7 @@ from sphinx.util.nodes import clean_astext, make_id, make_refnode
23
23
  from sphinx.util.parsing import nested_parse_to_nodes
24
24
 
25
25
  if TYPE_CHECKING:
26
- from collections.abc import Iterable, Iterator
26
+ from collections.abc import Callable, Iterable, Iterator
27
27
 
28
28
  from sphinx.application import Sphinx
29
29
  from sphinx.builders import Builder
@@ -402,7 +402,7 @@ class Glossary(SphinxDirective):
402
402
  in_comment = False
403
403
  was_empty = True
404
404
  messages: list[Node] = []
405
- for line, (source, lineno) in zip(self.content, self.content.items):
405
+ for line, (source, lineno) in zip(self.content, self.content.items, strict=True):
406
406
  # empty line -> add to last definition
407
407
  if not line:
408
408
  if in_definition and entries:
@@ -814,13 +814,12 @@ class StandardDomain(Domain):
814
814
  if not sectname:
815
815
  continue
816
816
  else:
817
- if (isinstance(node, (nodes.definition_list,
818
- nodes.field_list)) and
817
+ if (isinstance(node, nodes.definition_list | nodes.field_list) and
819
818
  node.children):
820
819
  node = cast(nodes.Element, node.children[0])
821
- if isinstance(node, (nodes.field, nodes.definition_list_item)):
820
+ if isinstance(node, nodes.field | nodes.definition_list_item):
822
821
  node = cast(nodes.Element, node.children[0])
823
- if isinstance(node, (nodes.term, nodes.field_name)):
822
+ if isinstance(node, nodes.term | nodes.field_name):
824
823
  sectname = clean_astext(node)
825
824
  else:
826
825
  toctree = next(node.findall(addnodes.toctree), None)
@@ -1114,7 +1113,7 @@ class StandardDomain(Domain):
1114
1113
  return title_getter(elem)
1115
1114
  else:
1116
1115
  for subnode in elem:
1117
- if isinstance(subnode, (nodes.caption, nodes.title)):
1116
+ if isinstance(subnode, nodes.caption | nodes.title):
1118
1117
  return clean_astext(subnode)
1119
1118
 
1120
1119
  return None
@@ -5,11 +5,10 @@ from __future__ import annotations
5
5
  import functools
6
6
  import os
7
7
  import pickle
8
- import time
9
8
  from collections import defaultdict
10
9
  from copy import copy
11
10
  from os import path
12
- from typing import TYPE_CHECKING, Any, Callable, NoReturn
11
+ from typing import TYPE_CHECKING, Any, NoReturn
13
12
 
14
13
  from sphinx import addnodes
15
14
  from sphinx.environment.adapters import toctree as toctree_adapters
@@ -17,13 +16,14 @@ from sphinx.errors import BuildEnvironmentError, DocumentError, ExtensionError,
17
16
  from sphinx.locale import __
18
17
  from sphinx.transforms import SphinxTransformer
19
18
  from sphinx.util import DownloadFiles, FilenameUniqDict, logging
19
+ from sphinx.util._timestamps import _format_rfc3339_microseconds
20
20
  from sphinx.util.docutils import LoggingReporter
21
21
  from sphinx.util.i18n import CatalogRepository, docname_to_domain
22
22
  from sphinx.util.nodes import is_translatable
23
- from sphinx.util.osutil import canon_path, os_path
23
+ from sphinx.util.osutil import _last_modified_time, canon_path, os_path
24
24
 
25
25
  if TYPE_CHECKING:
26
- from collections.abc import Iterator
26
+ from collections.abc import Callable, Iterator
27
27
  from pathlib import Path
28
28
 
29
29
  from docutils import nodes
@@ -59,7 +59,7 @@ default_settings: dict[str, Any] = {
59
59
 
60
60
  # This is increased every time an environment attribute is added
61
61
  # or changed to properly invalidate pickle files.
62
- ENV_VERSION = 62
62
+ ENV_VERSION = 63
63
63
 
64
64
  # config status
65
65
  CONFIG_UNSET = -1
@@ -124,7 +124,7 @@ if TYPE_CHECKING:
124
124
  def __getitem__(self, key: Literal["todo"]) -> TodoDomain: ... # NoQA: E704
125
125
  @overload
126
126
  def __getitem__(self, key: str) -> Domain: ... # NoQA: E704
127
- def __getitem__(self, key): raise NotImplementedError # NoQA: E704
127
+ def __getitem__(self, _key: str) -> Domain: raise NotImplementedError # NoQA: E704
128
128
  def __setitem__( # NoQA: E301,E704
129
129
  self, key: str, value: Domain,
130
130
  ) -> NoReturn: raise NotImplementedError
@@ -413,13 +413,13 @@ class BuildEnvironment:
413
413
  """
414
414
  return self.project.path2doc(filename)
415
415
 
416
- def doc2path(self, docname: str, base: bool = True) -> str:
416
+ def doc2path(self, docname: str, base: bool = True) -> Path:
417
417
  """Return the filename for the document name.
418
418
 
419
419
  If *base* is True, return absolute path under self.srcdir.
420
420
  If *base* is False, return relative path to self.srcdir.
421
421
  """
422
- return self.project.doc2path(docname, base)
422
+ return self.project.doc2path(docname, absolute=base)
423
423
 
424
424
  def relfn2path(self, filename: str, docname: str | None = None) -> tuple[str, str]:
425
425
  """Return paths to a file referenced from a document, relative to
@@ -508,7 +508,8 @@ class BuildEnvironment:
508
508
  if newmtime > mtime:
509
509
  logger.debug('[build target] outdated %r: %s -> %s',
510
510
  docname,
511
- _format_modified_time(mtime), _format_modified_time(newmtime))
511
+ _format_rfc3339_microseconds(mtime),
512
+ _format_rfc3339_microseconds(newmtime))
512
513
  changed.add(docname)
513
514
  continue
514
515
  # finally, check the mtime of dependencies
@@ -528,7 +529,8 @@ class BuildEnvironment:
528
529
  logger.debug(
529
530
  '[build target] outdated %r from dependency %r: %s -> %s',
530
531
  docname, deppath,
531
- _format_modified_time(mtime), _format_modified_time(depmtime),
532
+ _format_rfc3339_microseconds(mtime),
533
+ _format_rfc3339_microseconds(depmtime),
532
534
  )
533
535
  changed.add(docname)
534
536
  break
@@ -628,7 +630,7 @@ class BuildEnvironment:
628
630
 
629
631
  doctree = pickle.loads(serialised)
630
632
  doctree.settings.env = self
631
- doctree.reporter = LoggingReporter(self.doc2path(docname))
633
+ doctree.reporter = LoggingReporter(str(self.doc2path(docname)))
632
634
  return doctree
633
635
 
634
636
  @functools.cached_property
@@ -650,7 +652,7 @@ class BuildEnvironment:
650
652
  try:
651
653
  doctree = self._write_doc_doctree_cache.pop(docname)
652
654
  doctree.settings.env = self
653
- doctree.reporter = LoggingReporter(self.doc2path(docname))
655
+ doctree.reporter = LoggingReporter(str(self.doc2path(docname)))
654
656
  except KeyError:
655
657
  doctree = self.get_doctree(docname)
656
658
 
@@ -756,26 +758,6 @@ class BuildEnvironment:
756
758
  self.events.emit('env-check-consistency', self)
757
759
 
758
760
 
759
- def _last_modified_time(filename: str | os.PathLike[str]) -> int:
760
- """Return the last modified time of ``filename``.
761
-
762
- The time is returned as integer microseconds.
763
- The lowest common denominator of modern file-systems seems to be
764
- microsecond-level precision.
765
-
766
- We prefer to err on the side of re-rendering a file,
767
- so we round up to the nearest microsecond.
768
- """
769
- # upside-down floor division to get the ceiling
770
- return -(os.stat(filename).st_mtime_ns // -1_000)
771
-
772
-
773
- def _format_modified_time(timestamp: int) -> str:
774
- """Return an RFC 3339 formatted string representing the given timestamp."""
775
- seconds, fraction = divmod(timestamp, 10**6)
776
- return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(seconds)) + f'.{fraction // 1_000}'
777
-
778
-
779
761
  def _traverse_toctree(
780
762
  traversed: set[str],
781
763
  parent: str | None,
@@ -13,16 +13,14 @@ from sphinx.util import logging
13
13
  from sphinx.util.index_entries import _split_into
14
14
 
15
15
  if TYPE_CHECKING:
16
- from typing import Literal, Optional, Union
17
-
18
- from typing_extensions import TypeAlias
16
+ from typing import Literal, TypeAlias
19
17
 
20
18
  from sphinx.builders import Builder
21
19
  from sphinx.environment import BuildEnvironment
22
20
 
23
- _IndexEntryTarget: TypeAlias = tuple[Optional[str], Union[str, Literal[False]]]
21
+ _IndexEntryTarget: TypeAlias = tuple[str | None, str | Literal[False]]
24
22
  _IndexEntryTargets: TypeAlias = list[_IndexEntryTarget]
25
- _IndexEntryCategoryKey: TypeAlias = Optional[str]
23
+ _IndexEntryCategoryKey: TypeAlias = str | None
26
24
  _IndexEntrySubItems: TypeAlias = dict[
27
25
  str,
28
26
  tuple[_IndexEntryTargets, _IndexEntryCategoryKey],
@@ -32,7 +30,7 @@ if TYPE_CHECKING:
32
30
  _IndexEntrySubItems,
33
31
  _IndexEntryCategoryKey,
34
32
  ]
35
- _IndexEntryMap = dict[str, _IndexEntry]
33
+ _IndexEntryMap: TypeAlias = dict[str, _IndexEntry]
36
34
  _Index: TypeAlias = list[
37
35
  tuple[
38
36
  str,
@@ -319,7 +319,7 @@ def _toctree_entry(
319
319
  ref, location=toctreenode, type='toc', subtype='no_title')
320
320
  except KeyError:
321
321
  # this is raised if the included file does not exist
322
- ref_path = env.doc2path(ref, False)
322
+ ref_path = str(env.doc2path(ref, False))
323
323
  if excluded(ref_path):
324
324
  message = __('toctree contains reference to excluded document %r')
325
325
  elif not included(ref_path):
@@ -404,7 +404,7 @@ def _toctree_standard_entry(
404
404
  def _toctree_add_classes(node: Element, depth: int, docname: str) -> None:
405
405
  """Add 'toctree-l%d' and 'current' classes to the toctree."""
406
406
  for subnode in node.children:
407
- if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)):
407
+ if isinstance(subnode, addnodes.compact_paragraph | nodes.list_item):
408
408
  # for <p> and <li>, indicate the depth level and recurse
409
409
  subnode['classes'].append(f'toctree-l{depth - 1}')
410
410
  _toctree_add_classes(subnode, depth, docname)
@@ -442,7 +442,7 @@ def _toctree_copy(node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tag
442
442
 
443
443
  copy = node.copy()
444
444
  for subnode in node.children:
445
- if isinstance(subnode, (addnodes.compact_paragraph, nodes.list_item)):
445
+ if isinstance(subnode, addnodes.compact_paragraph | nodes.list_item):
446
446
  # for <p> and <li>, just recurse
447
447
  copy.append(_toctree_copy(subnode, depth, maxdepth, collapse, tags))
448
448
  elif isinstance(subnode, nodes.bullet_list):
@@ -462,7 +462,7 @@ def _toctree_copy(node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tag
462
462
  copy.append(_toctree_copy(
463
463
  child, depth, maxdepth, collapse, tags, # type: ignore[type-var]
464
464
  ))
465
- elif isinstance(subnode, (nodes.reference, nodes.title)):
465
+ elif isinstance(subnode, nodes.reference | nodes.title):
466
466
  # deep copy references and captions
467
467
  sub_node_copy = subnode.copy()
468
468
  sub_node_copy.children = [child.deepcopy() for child in subnode.children]
@@ -43,7 +43,7 @@ class TitleCollector(EnvironmentCollector):
43
43
  for node in doctree.findall(nodes.section):
44
44
  visitor = SphinxContentsFilter(doctree)
45
45
  node[0].walkabout(visitor)
46
- titlenode += visitor.get_entry_text()
46
+ titlenode += visitor.get_entry_text() # type: ignore[no-untyped-call]
47
47
  break
48
48
  else:
49
49
  # document has no title
@@ -78,7 +78,7 @@ class TocTreeCollector(EnvironmentCollector):
78
78
  # and unnecessary stuff
79
79
  visitor = SphinxContentsFilter(doctree)
80
80
  title.walkabout(visitor)
81
- nodetext = visitor.get_entry_text()
81
+ nodetext = visitor.get_entry_text() # type: ignore[no-untyped-call]
82
82
  anchorname = _make_anchor_name(sectionnode['ids'], numentries)
83
83
  # make these nodes:
84
84
  # list_item -> compact_paragraph -> reference
sphinx/events.py CHANGED
@@ -8,7 +8,7 @@ from __future__ import annotations
8
8
  import contextlib
9
9
  from collections import defaultdict
10
10
  from operator import attrgetter
11
- from typing import TYPE_CHECKING, Any, Callable, NamedTuple
11
+ from typing import TYPE_CHECKING, Any, NamedTuple
12
12
 
13
13
  from sphinx.errors import ExtensionError, SphinxError
14
14
  from sphinx.locale import __
@@ -16,6 +16,8 @@ from sphinx.util import logging
16
16
  from sphinx.util.inspect import safe_getattr
17
17
 
18
18
  if TYPE_CHECKING:
19
+ from collections.abc import Callable
20
+
19
21
  from sphinx.application import Sphinx
20
22
 
21
23