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.
- sphinx/__init__.py +2 -2
- sphinx/_cli/__init__.py +4 -4
- sphinx/application.py +7 -7
- sphinx/builders/__init__.py +2 -3
- sphinx/builders/_epub_base.py +33 -12
- sphinx/builders/changes.py +13 -5
- sphinx/builders/epub3.py +6 -2
- sphinx/builders/html/__init__.py +90 -59
- sphinx/builders/latex/__init__.py +38 -12
- sphinx/builders/latex/transforms.py +1 -1
- sphinx/builders/linkcheck.py +8 -49
- sphinx/builders/texinfo.py +12 -6
- sphinx/builders/text.py +7 -3
- sphinx/builders/xml.py +7 -3
- sphinx/cmd/quickstart.py +10 -20
- sphinx/config.py +12 -12
- sphinx/deprecation.py +8 -8
- sphinx/directives/__init__.py +14 -9
- sphinx/directives/other.py +2 -3
- sphinx/directives/patches.py +2 -2
- sphinx/domains/__init__.py +4 -2
- sphinx/domains/c/__init__.py +2 -2
- sphinx/domains/c/_ast.py +3 -2
- sphinx/domains/c/_parser.py +4 -3
- sphinx/domains/cpp/__init__.py +2 -2
- sphinx/domains/cpp/_ast.py +1 -2
- sphinx/domains/cpp/_parser.py +2 -2
- sphinx/domains/cpp/_symbol.py +2 -2
- sphinx/domains/javascript.py +1 -1
- sphinx/domains/math.py +1 -1
- sphinx/domains/python/__init__.py +1 -1
- sphinx/domains/python/_annotations.py +23 -1
- sphinx/domains/python/_object.py +0 -1
- sphinx/domains/std/__init__.py +7 -8
- sphinx/environment/__init__.py +14 -32
- sphinx/environment/adapters/indexentries.py +4 -6
- sphinx/environment/adapters/toctree.py +4 -4
- sphinx/environment/collectors/title.py +1 -1
- sphinx/environment/collectors/toctree.py +1 -1
- sphinx/events.py +3 -1
- sphinx/ext/autodoc/__init__.py +25 -67
- sphinx/ext/autodoc/directive.py +7 -5
- sphinx/ext/autodoc/importer.py +2 -1
- sphinx/ext/autodoc/preserve_defaults.py +2 -2
- sphinx/ext/autosummary/__init__.py +15 -7
- sphinx/ext/autosummary/generate.py +5 -4
- sphinx/ext/doctest.py +5 -5
- sphinx/ext/graphviz.py +1 -1
- sphinx/ext/imgmath.py +1 -1
- sphinx/ext/inheritance_diagram.py +1 -1
- sphinx/ext/intersphinx/__init__.py +25 -5
- sphinx/ext/intersphinx/_cli.py +7 -6
- sphinx/ext/intersphinx/_load.py +240 -115
- sphinx/ext/intersphinx/_resolve.py +12 -11
- sphinx/ext/intersphinx/_shared.py +102 -9
- sphinx/ext/mathjax.py +1 -1
- sphinx/ext/napoleon/docstring.py +2 -2
- sphinx/ext/todo.py +2 -2
- sphinx/ext/viewcode.py +2 -1
- sphinx/highlighting.py +3 -3
- sphinx/io.py +2 -2
- sphinx/jinja2glue.py +13 -6
- sphinx/locale/__init__.py +4 -3
- sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +1578 -1843
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +496 -704
- sphinx/project.py +23 -19
- sphinx/pycode/ast.py +2 -2
- sphinx/pycode/parser.py +2 -2
- sphinx/pygments_styles.py +3 -3
- sphinx/registry.py +3 -8
- sphinx/search/__init__.py +1 -1
- sphinx/testing/path.py +2 -1
- sphinx/testing/util.py +1 -1
- sphinx/texinputs/Makefile.jinja +2 -1
- sphinx/texinputs_win/Makefile.jinja +2 -1
- sphinx/theming.py +3 -12
- sphinx/transforms/__init__.py +5 -5
- sphinx/transforms/references.py +1 -1
- sphinx/util/__init__.py +11 -35
- sphinx/util/_timestamps.py +12 -0
- sphinx/util/cfamily.py +5 -5
- sphinx/util/console.py +4 -3
- sphinx/util/display.py +3 -3
- sphinx/util/docfields.py +1 -1
- sphinx/util/docutils.py +44 -10
- sphinx/util/fileutil.py +41 -9
- sphinx/util/i18n.py +9 -4
- sphinx/util/images.py +3 -2
- sphinx/util/inspect.py +29 -44
- sphinx/util/inventory.py +2 -2
- sphinx/util/matching.py +2 -2
- sphinx/util/math.py +1 -1
- sphinx/util/nodes.py +8 -8
- sphinx/util/osutil.py +46 -23
- sphinx/util/parallel.py +2 -2
- sphinx/util/requests.py +1 -1
- sphinx/util/template.py +3 -3
- sphinx/util/typing.py +67 -70
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +1 -1
- sphinx/writers/latex.py +4 -4
- sphinx/writers/manpage.py +2 -2
- sphinx/writers/texinfo.py +5 -5
- sphinx/writers/text.py +4 -4
- sphinx/writers/xml.py +2 -2
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/METADATA +10 -9
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/RECORD +112 -114
- sphinx/templates/quickstart/Makefile.jinja +0 -98
- sphinx/templates/quickstart/make.bat.jinja +0 -110
- sphinx/util/_pathlib.py +0 -120
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/LICENSE.rst +0 -0
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/WHEEL +0 -0
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/project.py
CHANGED
|
@@ -4,13 +4,13 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import os
|
|
7
|
-
from
|
|
7
|
+
from pathlib import Path
|
|
8
8
|
from typing import TYPE_CHECKING
|
|
9
9
|
|
|
10
10
|
from sphinx.locale import __
|
|
11
11
|
from sphinx.util import logging
|
|
12
12
|
from sphinx.util.matching import get_matching_files
|
|
13
|
-
from sphinx.util.osutil import path_stabilize
|
|
13
|
+
from sphinx.util.osutil import path_stabilize
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from collections.abc import Iterable
|
|
@@ -24,7 +24,7 @@ class Project:
|
|
|
24
24
|
|
|
25
25
|
def __init__(self, srcdir: str | os.PathLike[str], source_suffix: Iterable[str]) -> None:
|
|
26
26
|
#: Source directory.
|
|
27
|
-
self.srcdir = srcdir
|
|
27
|
+
self.srcdir = Path(srcdir)
|
|
28
28
|
|
|
29
29
|
#: source_suffix. Same as :confval:`source_suffix`.
|
|
30
30
|
self.source_suffix = tuple(source_suffix)
|
|
@@ -34,8 +34,8 @@ class Project:
|
|
|
34
34
|
self.docnames: set[str] = set()
|
|
35
35
|
|
|
36
36
|
# Bijective mapping between docnames and (srcdir relative) paths.
|
|
37
|
-
self._path_to_docname: dict[
|
|
38
|
-
self._docname_to_path: dict[str,
|
|
37
|
+
self._path_to_docname: dict[Path, str] = {}
|
|
38
|
+
self._docname_to_path: dict[str, Path] = {}
|
|
39
39
|
|
|
40
40
|
def restore(self, other: Project) -> None:
|
|
41
41
|
"""Take over a result of last build."""
|
|
@@ -60,22 +60,25 @@ class Project:
|
|
|
60
60
|
):
|
|
61
61
|
if docname := self.path2doc(filename):
|
|
62
62
|
if docname in self.docnames:
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
files = [
|
|
64
|
+
str(f.relative_to(self.srcdir))
|
|
65
|
+
for f in self.srcdir.glob(f'{docname}.*')
|
|
66
|
+
]
|
|
65
67
|
logger.warning(
|
|
66
68
|
__(
|
|
67
|
-
'multiple files found for the document "%s": %
|
|
69
|
+
'multiple files found for the document "%s": %s\n'
|
|
68
70
|
'Use %r for the build.'
|
|
69
71
|
),
|
|
70
72
|
docname,
|
|
71
|
-
files,
|
|
73
|
+
', '.join(files),
|
|
72
74
|
self.doc2path(docname, absolute=True),
|
|
73
75
|
once=True,
|
|
74
76
|
)
|
|
75
|
-
elif os.access(
|
|
77
|
+
elif os.access(self.srcdir / filename, os.R_OK):
|
|
76
78
|
self.docnames.add(docname)
|
|
77
|
-
|
|
78
|
-
self.
|
|
79
|
+
path = Path(filename)
|
|
80
|
+
self._path_to_docname[path] = docname
|
|
81
|
+
self._docname_to_path[docname] = path
|
|
79
82
|
else:
|
|
80
83
|
logger.warning(
|
|
81
84
|
__('Ignored unreadable document %r.'), filename, location=docname
|
|
@@ -91,18 +94,19 @@ class Project:
|
|
|
91
94
|
try:
|
|
92
95
|
return self._path_to_docname[filename] # type: ignore[index]
|
|
93
96
|
except KeyError:
|
|
94
|
-
|
|
97
|
+
path = Path(filename)
|
|
98
|
+
if path.is_absolute():
|
|
95
99
|
with contextlib.suppress(ValueError):
|
|
96
|
-
|
|
100
|
+
path = path.relative_to(self.srcdir)
|
|
97
101
|
|
|
98
102
|
for suffix in self.source_suffix:
|
|
99
|
-
if
|
|
100
|
-
return path_stabilize(
|
|
103
|
+
if path.name.endswith(suffix):
|
|
104
|
+
return path_stabilize(path).removesuffix(suffix)
|
|
101
105
|
|
|
102
106
|
# the file does not have a docname
|
|
103
107
|
return None
|
|
104
108
|
|
|
105
|
-
def doc2path(self, docname: str, absolute: bool) ->
|
|
109
|
+
def doc2path(self, docname: str, absolute: bool) -> Path:
|
|
106
110
|
"""Return the filename for the document name.
|
|
107
111
|
|
|
108
112
|
If *absolute* is True, return as an absolute path.
|
|
@@ -112,8 +116,8 @@ class Project:
|
|
|
112
116
|
filename = self._docname_to_path[docname]
|
|
113
117
|
except KeyError:
|
|
114
118
|
# Backwards compatibility: the document does not exist
|
|
115
|
-
filename = docname + self._first_source_suffix
|
|
119
|
+
filename = Path(docname + self._first_source_suffix)
|
|
116
120
|
|
|
117
121
|
if absolute:
|
|
118
|
-
return
|
|
122
|
+
return self.srcdir / filename
|
|
119
123
|
return filename
|
sphinx/pycode/ast.py
CHANGED
|
@@ -130,7 +130,7 @@ class _UnparseVisitor(ast.NodeVisitor):
|
|
|
130
130
|
def visit_Constant(self, node: ast.Constant) -> str:
|
|
131
131
|
if node.value is Ellipsis:
|
|
132
132
|
return "..."
|
|
133
|
-
elif isinstance(node.value,
|
|
133
|
+
elif isinstance(node.value, int | float | complex):
|
|
134
134
|
if self.code:
|
|
135
135
|
return ast.get_source_segment(self.code, node) or repr(node.value)
|
|
136
136
|
else:
|
|
@@ -141,7 +141,7 @@ class _UnparseVisitor(ast.NodeVisitor):
|
|
|
141
141
|
def visit_Dict(self, node: ast.Dict) -> str:
|
|
142
142
|
keys = (self.visit(k) for k in node.keys if k is not None)
|
|
143
143
|
values = (self.visit(v) for v in node.values)
|
|
144
|
-
items = (k + ": " + v for k, v in zip(keys, values))
|
|
144
|
+
items = (k + ": " + v for k, v in zip(keys, values, strict=True))
|
|
145
145
|
return "{" + ", ".join(items) + "}"
|
|
146
146
|
|
|
147
147
|
def visit_Lambda(self, node: ast.Lambda) -> str:
|
sphinx/pycode/parser.py
CHANGED
|
@@ -108,7 +108,7 @@ class Token:
|
|
|
108
108
|
return self.kind == other
|
|
109
109
|
elif isinstance(other, str):
|
|
110
110
|
return self.value == other
|
|
111
|
-
elif isinstance(other,
|
|
111
|
+
elif isinstance(other, list | tuple):
|
|
112
112
|
return [self.kind, self.value] == list(other)
|
|
113
113
|
elif other is None:
|
|
114
114
|
return False
|
|
@@ -404,7 +404,7 @@ class VariableCommentPicker(ast.NodeVisitor):
|
|
|
404
404
|
|
|
405
405
|
def visit_Expr(self, node: ast.Expr) -> None:
|
|
406
406
|
"""Handles Expr node and pick up a comment if string."""
|
|
407
|
-
if (isinstance(self.previous,
|
|
407
|
+
if (isinstance(self.previous, ast.Assign | ast.AnnAssign) and
|
|
408
408
|
isinstance(node.value, ast.Constant) and isinstance(node.value.value, str)):
|
|
409
409
|
try:
|
|
410
410
|
targets = get_assign_targets(self.previous)
|
sphinx/pygments_styles.py
CHANGED
|
@@ -28,12 +28,12 @@ class SphinxStyle(Style):
|
|
|
28
28
|
background_color = '#eeffcc'
|
|
29
29
|
default_style = ''
|
|
30
30
|
|
|
31
|
-
styles =
|
|
32
|
-
|
|
31
|
+
styles = {
|
|
32
|
+
**FriendlyStyle.styles,
|
|
33
33
|
Generic.Output: '#333',
|
|
34
34
|
Comment: 'italic #408090',
|
|
35
35
|
Number: '#208050',
|
|
36
|
-
}
|
|
36
|
+
}
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class PyramidStyle(Style):
|
sphinx/registry.py
CHANGED
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import sys
|
|
6
5
|
import traceback
|
|
7
6
|
from importlib import import_module
|
|
7
|
+
from importlib.metadata import entry_points
|
|
8
8
|
from types import MethodType
|
|
9
|
-
from typing import TYPE_CHECKING, Any
|
|
10
|
-
|
|
11
|
-
if sys.version_info >= (3, 10):
|
|
12
|
-
from importlib.metadata import entry_points
|
|
13
|
-
else:
|
|
14
|
-
from importlib_metadata import entry_points
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
15
10
|
|
|
16
11
|
from sphinx.domains import Domain, Index, ObjType
|
|
17
12
|
from sphinx.domains.std import GenericObject, Target
|
|
@@ -25,7 +20,7 @@ from sphinx.util import logging
|
|
|
25
20
|
from sphinx.util.logging import prefixed_warnings
|
|
26
21
|
|
|
27
22
|
if TYPE_CHECKING:
|
|
28
|
-
from collections.abc import Iterator, Sequence
|
|
23
|
+
from collections.abc import Callable, Iterator, Sequence
|
|
29
24
|
|
|
30
25
|
from docutils import nodes
|
|
31
26
|
from docutils.core import Publisher
|
sphinx/search/__init__.py
CHANGED
|
@@ -487,7 +487,7 @@ class IndexBuilder:
|
|
|
487
487
|
self._index_entries[docname] = sorted(_index_entries)
|
|
488
488
|
|
|
489
489
|
def _word_collector(self, doctree: nodes.document) -> WordStore:
|
|
490
|
-
def _visit_nodes(node):
|
|
490
|
+
def _visit_nodes(node: nodes.Node) -> None:
|
|
491
491
|
if isinstance(node, nodes.comment):
|
|
492
492
|
return
|
|
493
493
|
elif isinstance(node, nodes.raw):
|
sphinx/testing/path.py
CHANGED
|
@@ -4,12 +4,13 @@ import os
|
|
|
4
4
|
import shutil
|
|
5
5
|
import sys
|
|
6
6
|
import warnings
|
|
7
|
-
from typing import IO, TYPE_CHECKING, Any
|
|
7
|
+
from typing import IO, TYPE_CHECKING, Any
|
|
8
8
|
|
|
9
9
|
from sphinx.deprecation import RemovedInSphinx90Warning
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
import builtins
|
|
13
|
+
from collections.abc import Callable
|
|
13
14
|
|
|
14
15
|
warnings.warn("'sphinx.testing.path' is deprecated. "
|
|
15
16
|
"Use 'os.path' or 'pathlib' instead.",
|
sphinx/testing/util.py
CHANGED
|
@@ -43,7 +43,7 @@ def assert_node(node: Node, cls: Any = None, xpath: str = "", **kwargs: Any) ->
|
|
|
43
43
|
'The node%s has %d child nodes, not one' % (xpath, len(node))
|
|
44
44
|
assert_node(node[0], cls[1:], xpath=xpath + "[0]", **kwargs)
|
|
45
45
|
elif isinstance(cls, tuple):
|
|
46
|
-
assert isinstance(node,
|
|
46
|
+
assert isinstance(node, list | nodes.Element), \
|
|
47
47
|
'The node%s does not have any items' % xpath
|
|
48
48
|
assert len(node) == len(cls), \
|
|
49
49
|
'The node%s has %d child nodes, not %r' % (xpath, len(node), len(cls))
|
sphinx/texinputs/Makefile.jinja
CHANGED
|
@@ -77,7 +77,8 @@ tar: all-$(FMT)
|
|
|
77
77
|
rm -r $(ARCHIVEPREFIX)docs-$(FMT)
|
|
78
78
|
|
|
79
79
|
gz: tar
|
|
80
|
-
|
|
80
|
+
# -n to omit mtime from gzip headers
|
|
81
|
+
gzip -n -9 < $(ARCHIVEPREFIX)docs-$(FMT).tar > $(ARCHIVEPREFIX)docs-$(FMT).tar.gz
|
|
81
82
|
|
|
82
83
|
bz2: tar
|
|
83
84
|
bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar
|
|
@@ -49,7 +49,8 @@ tar: all-$(FMT)
|
|
|
49
49
|
rm -r $(ARCHIVEPREFIX)docs-$(FMT)
|
|
50
50
|
|
|
51
51
|
gz: tar
|
|
52
|
-
|
|
52
|
+
# -n to omit mtime from gzip headers
|
|
53
|
+
gzip -n -9 < $(ARCHIVEPREFIX)docs-$(FMT).tar > $(ARCHIVEPREFIX)docs-$(FMT).tar.gz
|
|
53
54
|
|
|
54
55
|
bz2: tar
|
|
55
56
|
bzip2 -9 -k $(ARCHIVEPREFIX)docs-$(FMT).tar
|
sphinx/theming.py
CHANGED
|
@@ -10,6 +10,7 @@ import os
|
|
|
10
10
|
import shutil
|
|
11
11
|
import sys
|
|
12
12
|
import tempfile
|
|
13
|
+
from importlib.metadata import entry_points
|
|
13
14
|
from os import path
|
|
14
15
|
from typing import TYPE_CHECKING, Any
|
|
15
16
|
from zipfile import ZipFile
|
|
@@ -26,10 +27,6 @@ if sys.version_info >= (3, 11):
|
|
|
26
27
|
else:
|
|
27
28
|
import tomli as tomllib
|
|
28
29
|
|
|
29
|
-
if sys.version_info >= (3, 10):
|
|
30
|
-
from importlib.metadata import entry_points
|
|
31
|
-
else:
|
|
32
|
-
from importlib_metadata import entry_points
|
|
33
30
|
|
|
34
31
|
if TYPE_CHECKING:
|
|
35
32
|
from collections.abc import Callable
|
|
@@ -121,17 +118,11 @@ class Theme:
|
|
|
121
118
|
elif section == 'options':
|
|
122
119
|
value = self._options.get(name, default)
|
|
123
120
|
else:
|
|
124
|
-
# https://github.com/sphinx-doc/sphinx/issues/12305
|
|
125
|
-
# For backwards compatibility when attempting to read a value
|
|
126
|
-
# from an unsupported configuration section.
|
|
127
|
-
# xref: RemovedInSphinx80Warning
|
|
128
121
|
msg = __(
|
|
129
122
|
'Theme configuration sections other than [theme] and [options] '
|
|
130
|
-
'are not supported
|
|
131
|
-
'(tried to get a value from %r)'
|
|
123
|
+
'are not supported (tried to get a value from %r).'
|
|
132
124
|
)
|
|
133
|
-
|
|
134
|
-
value = default
|
|
125
|
+
raise ThemeError(msg)
|
|
135
126
|
if value is _NO_DEFAULT:
|
|
136
127
|
msg = __('setting %s.%s occurs in none of the searched theme configs') % (
|
|
137
128
|
section,
|
sphinx/transforms/__init__.py
CHANGED
|
@@ -22,10 +22,10 @@ from sphinx.util.nodes import apply_source_workaround, is_smartquotable
|
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
24
|
from collections.abc import Iterator
|
|
25
|
-
from typing import Literal
|
|
25
|
+
from typing import Literal, TypeAlias
|
|
26
26
|
|
|
27
27
|
from docutils.nodes import Node, Text
|
|
28
|
-
from typing_extensions import
|
|
28
|
+
from typing_extensions import TypeIs
|
|
29
29
|
|
|
30
30
|
from sphinx.application import Sphinx
|
|
31
31
|
from sphinx.config import Config
|
|
@@ -247,7 +247,7 @@ class ApplySourceWorkaround(SphinxTransform):
|
|
|
247
247
|
|
|
248
248
|
def apply(self, **kwargs: Any) -> None:
|
|
249
249
|
for node in self.document.findall(): # type: Node
|
|
250
|
-
if isinstance(node,
|
|
250
|
+
if isinstance(node, nodes.TextElement | nodes.image | nodes.topic):
|
|
251
251
|
apply_source_workaround(node)
|
|
252
252
|
|
|
253
253
|
|
|
@@ -364,7 +364,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
|
|
|
364
364
|
# override default settings with :confval:`smartquotes_action`
|
|
365
365
|
self.smartquotes_action = self.config.smartquotes_action
|
|
366
366
|
|
|
367
|
-
super().apply()
|
|
367
|
+
super().apply() # type: ignore[no-untyped-call]
|
|
368
368
|
|
|
369
369
|
def is_available(self) -> bool:
|
|
370
370
|
builders = self.config.smartquotes_excludes.get('builders', [])
|
|
@@ -477,7 +477,7 @@ def _reorder_index_target_nodes(start_node: nodes.target) -> None:
|
|
|
477
477
|
# as we want *consecutive* target & index nodes.
|
|
478
478
|
node: nodes.Node
|
|
479
479
|
for node in start_node.findall(descend=False, siblings=True):
|
|
480
|
-
if isinstance(node,
|
|
480
|
+
if isinstance(node, nodes.target | addnodes.index):
|
|
481
481
|
nodes_to_reorder.append(node)
|
|
482
482
|
continue
|
|
483
483
|
break # must be a consecutive run of target or index nodes
|
sphinx/transforms/references.py
CHANGED
|
@@ -23,7 +23,7 @@ class SphinxDanglingReferences(DanglingReferences):
|
|
|
23
23
|
|
|
24
24
|
# suppress INFO level messages for a while
|
|
25
25
|
reporter.report_level = max(reporter.WARNING_LEVEL, reporter.report_level)
|
|
26
|
-
super().apply()
|
|
26
|
+
super().apply() # type: ignore[no-untyped-call]
|
|
27
27
|
finally:
|
|
28
28
|
reporter.report_level = report_level
|
|
29
29
|
|
sphinx/util/__init__.py
CHANGED
|
@@ -13,12 +13,8 @@ from urllib.parse import parse_qsl, quote_plus, urlencode, urlsplit, urlunsplit
|
|
|
13
13
|
|
|
14
14
|
from sphinx.errors import ExtensionError, FiletypeNotFoundError
|
|
15
15
|
from sphinx.locale import __
|
|
16
|
-
from sphinx.util import display as _display
|
|
17
|
-
from sphinx.util import exceptions as _exceptions
|
|
18
|
-
from sphinx.util import http_date as _http_date
|
|
19
16
|
from sphinx.util import index_entries as _index_entries
|
|
20
17
|
from sphinx.util import logging
|
|
21
|
-
from sphinx.util import osutil as _osutil
|
|
22
18
|
from sphinx.util.console import strip_colors # NoQA: F401
|
|
23
19
|
from sphinx.util.matching import patfilter # NoQA: F401
|
|
24
20
|
from sphinx.util.nodes import ( # NoQA: F401
|
|
@@ -33,10 +29,8 @@ from sphinx.util.nodes import ( # NoQA: F401
|
|
|
33
29
|
from sphinx.util.osutil import ( # NoQA: F401
|
|
34
30
|
SEP,
|
|
35
31
|
copyfile,
|
|
36
|
-
copytimes,
|
|
37
32
|
ensuredir,
|
|
38
33
|
make_filename,
|
|
39
|
-
mtimes_of_files,
|
|
40
34
|
os_path,
|
|
41
35
|
relative_uri,
|
|
42
36
|
)
|
|
@@ -54,9 +48,9 @@ def docname_join(basedocname: str, docname: str) -> str:
|
|
|
54
48
|
return posixpath.normpath(posixpath.join('/' + basedocname, '..', docname))[1:]
|
|
55
49
|
|
|
56
50
|
|
|
57
|
-
def get_filetype(source_suffix: dict[str, str], filename: str) -> str:
|
|
51
|
+
def get_filetype(source_suffix: dict[str, str], filename: str | os.PathLike) -> str:
|
|
58
52
|
for suffix, filetype in source_suffix.items():
|
|
59
|
-
if filename.endswith(suffix):
|
|
53
|
+
if os.fspath(filename).endswith(suffix):
|
|
60
54
|
# If default filetype (None), considered as restructuredtext.
|
|
61
55
|
return filetype or 'restructuredtext'
|
|
62
56
|
raise FiletypeNotFoundError
|
|
@@ -258,32 +252,16 @@ def isurl(url: str) -> bool:
|
|
|
258
252
|
return bool(url) and '://' in url
|
|
259
253
|
|
|
260
254
|
|
|
261
|
-
def _xml_name_checker() -> re.Pattern[str]:
|
|
262
|
-
# to prevent import cycles
|
|
263
|
-
from sphinx.builders.epub3 import _XML_NAME_PATTERN
|
|
264
|
-
|
|
265
|
-
return _XML_NAME_PATTERN
|
|
266
|
-
|
|
267
|
-
|
|
268
255
|
# deprecated name -> (object to return, canonical path or empty string)
|
|
269
|
-
_DEPRECATED_OBJECTS: dict[str, tuple[Any, str
|
|
270
|
-
'path_stabilize': (_osutil.path_stabilize, 'sphinx.util.osutil.path_stabilize'),
|
|
271
|
-
'display_chunk': (_display.display_chunk, 'sphinx.util.display.display_chunk'),
|
|
272
|
-
'status_iterator': (_display.status_iterator, 'sphinx.util.display.status_iterator'),
|
|
273
|
-
'SkipProgressMessage': (_display.SkipProgressMessage,
|
|
274
|
-
'sphinx.util.display.SkipProgressMessage'),
|
|
275
|
-
'progress_message': (_display.progress_message, 'sphinx.util.display.progress_message'),
|
|
276
|
-
'epoch_to_rfc1123': (_http_date.epoch_to_rfc1123, 'sphinx.http_date.epoch_to_rfc1123'),
|
|
277
|
-
'rfc1123_to_epoch': (_http_date.rfc1123_to_epoch, 'sphinx.http_date.rfc1123_to_epoch'),
|
|
278
|
-
'save_traceback': (_exceptions.save_traceback, 'sphinx.exceptions.save_traceback'),
|
|
279
|
-
'format_exception_cut_frames': (_exceptions.format_exception_cut_frames,
|
|
280
|
-
'sphinx.exceptions.format_exception_cut_frames'),
|
|
281
|
-
'xmlname_checker': (_xml_name_checker, 'sphinx.builders.epub3._XML_NAME_PATTERN'),
|
|
256
|
+
_DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
|
|
282
257
|
'split_index_msg': (_index_entries.split_index_msg,
|
|
283
|
-
'sphinx.util.index_entries.split_index_msg'
|
|
284
|
-
|
|
285
|
-
'
|
|
286
|
-
|
|
258
|
+
'sphinx.util.index_entries.split_index_msg',
|
|
259
|
+
(9, 0)),
|
|
260
|
+
'split_into': (_index_entries.split_index_msg,
|
|
261
|
+
'sphinx.util.index_entries.split_into',
|
|
262
|
+
(9, 0)),
|
|
263
|
+
'md5': (_md5, '', (9, 0)),
|
|
264
|
+
'sha1': (_sha1, '', (9, 0)),
|
|
287
265
|
}
|
|
288
266
|
|
|
289
267
|
|
|
@@ -294,8 +272,6 @@ def __getattr__(name: str) -> Any:
|
|
|
294
272
|
|
|
295
273
|
from sphinx.deprecation import _deprecation_warning
|
|
296
274
|
|
|
297
|
-
|
|
298
|
-
deprecated_object, canonical_name = info[:2]
|
|
299
|
-
remove = info[2] if len(info) == 3 else (8, 0)
|
|
275
|
+
deprecated_object, canonical_name, remove = _DEPRECATED_OBJECTS[name]
|
|
300
276
|
_deprecation_warning(__name__, name, canonical_name, remove=remove)
|
|
301
277
|
return deprecated_object
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _format_rfc3339_microseconds(timestamp: int, /) -> str:
|
|
7
|
+
"""Return an RFC 3339 formatted string representing the given timestamp.
|
|
8
|
+
|
|
9
|
+
:param timestamp: The timestamp to format, in microseconds.
|
|
10
|
+
"""
|
|
11
|
+
seconds, fraction = divmod(timestamp, 10**6)
|
|
12
|
+
return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(seconds)) + f'.{fraction // 1_000}'
|
sphinx/util/cfamily.py
CHANGED
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
6
|
from copy import deepcopy
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
9
9
|
from docutils import nodes
|
|
10
10
|
|
|
@@ -12,16 +12,16 @@ from sphinx import addnodes
|
|
|
12
12
|
from sphinx.util import logging
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
-
from collections.abc import Sequence
|
|
15
|
+
from collections.abc import Callable, Sequence
|
|
16
|
+
from typing import Any, TypeAlias
|
|
16
17
|
|
|
17
18
|
from docutils.nodes import TextElement
|
|
18
19
|
|
|
19
20
|
from sphinx.config import Config
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
StringifyTransform = Callable[[Any], str]
|
|
22
|
+
StringifyTransform: TypeAlias = Callable[[Any], str]
|
|
24
23
|
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
26
26
|
_whitespace_re = re.compile(r'\s+')
|
|
27
27
|
anon_identifier_re = re.compile(r'(@[a-zA-Z0-9_])[a-zA-Z0-9_]*\b')
|
sphinx/util/console.py
CHANGED
|
@@ -41,8 +41,9 @@ if TYPE_CHECKING:
|
|
|
41
41
|
try:
|
|
42
42
|
# check if colorama is installed to support color on Windows
|
|
43
43
|
import colorama
|
|
44
|
+
COLORAMA_AVAILABLE = True
|
|
44
45
|
except ImportError:
|
|
45
|
-
|
|
46
|
+
COLORAMA_AVAILABLE = False
|
|
46
47
|
|
|
47
48
|
_CSI: Final[str] = re.escape('\x1b[') # 'ESC [': Control Sequence Introducer
|
|
48
49
|
|
|
@@ -92,7 +93,7 @@ def term_width_line(text: str) -> str:
|
|
|
92
93
|
def color_terminal() -> bool:
|
|
93
94
|
if 'NO_COLOR' in os.environ:
|
|
94
95
|
return False
|
|
95
|
-
if sys.platform == 'win32' and
|
|
96
|
+
if sys.platform == 'win32' and COLORAMA_AVAILABLE:
|
|
96
97
|
colorama.just_fix_windows_console()
|
|
97
98
|
return True
|
|
98
99
|
if 'FORCE_COLOR' in os.environ:
|
|
@@ -108,7 +109,7 @@ def color_terminal() -> bool:
|
|
|
108
109
|
|
|
109
110
|
|
|
110
111
|
def nocolor() -> None:
|
|
111
|
-
if sys.platform == 'win32' and
|
|
112
|
+
if sys.platform == 'win32' and COLORAMA_AVAILABLE:
|
|
112
113
|
colorama.deinit()
|
|
113
114
|
codes.clear()
|
|
114
115
|
|
sphinx/util/display.py
CHANGED
|
@@ -7,9 +7,9 @@ from sphinx.util import logging
|
|
|
7
7
|
from sphinx.util.console import bold, color_terminal
|
|
8
8
|
|
|
9
9
|
if False:
|
|
10
|
-
from collections.abc import Iterable, Iterator
|
|
10
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
11
11
|
from types import TracebackType
|
|
12
|
-
from typing import Any,
|
|
12
|
+
from typing import Any, TypeVar
|
|
13
13
|
|
|
14
14
|
from typing_extensions import ParamSpec
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@ logger = logging.getLogger(__name__)
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def display_chunk(chunk: Any) -> str:
|
|
24
|
-
if isinstance(chunk,
|
|
24
|
+
if isinstance(chunk, list | tuple):
|
|
25
25
|
if len(chunk) == 1:
|
|
26
26
|
return str(chunk[0])
|
|
27
27
|
return f'{chunk[0]} .. {chunk[-1]}'
|
sphinx/util/docfields.py
CHANGED
|
@@ -356,7 +356,7 @@ class DocFieldTransformer:
|
|
|
356
356
|
if is_typefield:
|
|
357
357
|
# filter out only inline nodes; others will result in invalid
|
|
358
358
|
# markup being written out
|
|
359
|
-
content = [n for n in content if isinstance(n,
|
|
359
|
+
content = [n for n in content if isinstance(n, nodes.Inline | nodes.Text)]
|
|
360
360
|
if content:
|
|
361
361
|
types.setdefault(typename, {})[fieldarg] = content
|
|
362
362
|
continue
|
sphinx/util/docutils.py
CHANGED
|
@@ -8,7 +8,7 @@ from collections.abc import Sequence # NoQA: TCH003
|
|
|
8
8
|
from contextlib import contextmanager
|
|
9
9
|
from copy import copy
|
|
10
10
|
from os import path
|
|
11
|
-
from typing import IO, TYPE_CHECKING, Any,
|
|
11
|
+
from typing import IO, TYPE_CHECKING, Any, cast
|
|
12
12
|
|
|
13
13
|
import docutils
|
|
14
14
|
from docutils import nodes
|
|
@@ -27,7 +27,7 @@ logger = logging.getLogger(__name__)
|
|
|
27
27
|
report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ')
|
|
28
28
|
|
|
29
29
|
if TYPE_CHECKING:
|
|
30
|
-
from collections.abc import Iterator
|
|
30
|
+
from collections.abc import Callable, Iterator # NoQA: TCH003
|
|
31
31
|
from types import ModuleType
|
|
32
32
|
|
|
33
33
|
from docutils.frontend import Values
|
|
@@ -366,30 +366,47 @@ class SphinxDirective(Directive):
|
|
|
366
366
|
|
|
367
367
|
This class provides helper methods for Sphinx directives.
|
|
368
368
|
|
|
369
|
+
.. versionadded:: 1.8
|
|
370
|
+
|
|
369
371
|
.. note:: The subclasses of this class might not work with docutils.
|
|
370
372
|
This class is strongly coupled with Sphinx.
|
|
371
373
|
"""
|
|
372
374
|
|
|
373
375
|
@property
|
|
374
376
|
def env(self) -> BuildEnvironment:
|
|
375
|
-
"""Reference to the :class:`.BuildEnvironment` object.
|
|
377
|
+
"""Reference to the :class:`.BuildEnvironment` object.
|
|
378
|
+
|
|
379
|
+
.. versionadded:: 1.8
|
|
380
|
+
"""
|
|
376
381
|
return self.state.document.settings.env
|
|
377
382
|
|
|
378
383
|
@property
|
|
379
384
|
def config(self) -> Config:
|
|
380
|
-
"""Reference to the :class:`.Config` object.
|
|
385
|
+
"""Reference to the :class:`.Config` object.
|
|
386
|
+
|
|
387
|
+
.. versionadded:: 1.8
|
|
388
|
+
"""
|
|
381
389
|
return self.env.config
|
|
382
390
|
|
|
383
391
|
def get_source_info(self) -> tuple[str, int]:
|
|
384
|
-
"""Get source and line number.
|
|
392
|
+
"""Get source and line number.
|
|
393
|
+
|
|
394
|
+
.. versionadded:: 3.0
|
|
395
|
+
"""
|
|
385
396
|
return self.state_machine.get_source_and_line(self.lineno)
|
|
386
397
|
|
|
387
398
|
def set_source_info(self, node: Node) -> None:
|
|
388
|
-
"""Set source and line number to the node.
|
|
399
|
+
"""Set source and line number to the node.
|
|
400
|
+
|
|
401
|
+
.. versionadded:: 2.1
|
|
402
|
+
"""
|
|
389
403
|
node.source, node.line = self.get_source_info()
|
|
390
404
|
|
|
391
405
|
def get_location(self) -> str:
|
|
392
|
-
"""Get current location info for logging.
|
|
406
|
+
"""Get current location info for logging.
|
|
407
|
+
|
|
408
|
+
.. versionadded:: 4.2
|
|
409
|
+
"""
|
|
393
410
|
source, line = self.get_source_info()
|
|
394
411
|
if source and line:
|
|
395
412
|
return f'{source}:{line}'
|
|
@@ -473,6 +490,8 @@ class SphinxRole:
|
|
|
473
490
|
|
|
474
491
|
This class provides helper methods for Sphinx roles.
|
|
475
492
|
|
|
493
|
+
.. versionadded:: 2.0
|
|
494
|
+
|
|
476
495
|
.. note:: The subclasses of this class might not work with docutils.
|
|
477
496
|
This class is strongly coupled with Sphinx.
|
|
478
497
|
"""
|
|
@@ -517,24 +536,35 @@ class SphinxRole:
|
|
|
517
536
|
|
|
518
537
|
@property
|
|
519
538
|
def env(self) -> BuildEnvironment:
|
|
520
|
-
"""Reference to the :class:`.BuildEnvironment` object.
|
|
539
|
+
"""Reference to the :class:`.BuildEnvironment` object.
|
|
540
|
+
|
|
541
|
+
.. versionadded:: 2.0
|
|
542
|
+
"""
|
|
521
543
|
return self.inliner.document.settings.env
|
|
522
544
|
|
|
523
545
|
@property
|
|
524
546
|
def config(self) -> Config:
|
|
525
|
-
"""Reference to the :class:`.Config` object.
|
|
547
|
+
"""Reference to the :class:`.Config` object.
|
|
548
|
+
|
|
549
|
+
.. versionadded:: 2.0
|
|
550
|
+
"""
|
|
526
551
|
return self.env.config
|
|
527
552
|
|
|
528
553
|
def get_source_info(self, lineno: int | None = None) -> tuple[str, int]:
|
|
554
|
+
# .. versionadded:: 3.0
|
|
529
555
|
if lineno is None:
|
|
530
556
|
lineno = self.lineno
|
|
531
557
|
return self.inliner.reporter.get_source_and_line(lineno) # type: ignore[attr-defined]
|
|
532
558
|
|
|
533
559
|
def set_source_info(self, node: Node, lineno: int | None = None) -> None:
|
|
560
|
+
# .. versionadded:: 2.0
|
|
534
561
|
node.source, node.line = self.get_source_info(lineno)
|
|
535
562
|
|
|
536
563
|
def get_location(self) -> str:
|
|
537
|
-
"""Get current location info for logging.
|
|
564
|
+
"""Get current location info for logging.
|
|
565
|
+
|
|
566
|
+
.. versionadded:: 4.2
|
|
567
|
+
"""
|
|
538
568
|
source, line = self.get_source_info()
|
|
539
569
|
if source and line:
|
|
540
570
|
return f'{source}:{line}'
|
|
@@ -551,6 +581,8 @@ class ReferenceRole(SphinxRole):
|
|
|
551
581
|
The reference roles can accept ``link title <target>`` style as a text for
|
|
552
582
|
the role. The parsed result; link title and target will be stored to
|
|
553
583
|
``self.title`` and ``self.target``.
|
|
584
|
+
|
|
585
|
+
.. versionadded:: 2.0
|
|
554
586
|
"""
|
|
555
587
|
|
|
556
588
|
has_explicit_title: bool #: A boolean indicates the role has explicit title or not.
|
|
@@ -591,6 +623,8 @@ class SphinxTranslator(nodes.NodeVisitor):
|
|
|
591
623
|
|
|
592
624
|
It also provides helper methods for Sphinx translators.
|
|
593
625
|
|
|
626
|
+
.. versionadded:: 2.0
|
|
627
|
+
|
|
594
628
|
.. note:: The subclasses of this class might not work with docutils.
|
|
595
629
|
This class is strongly coupled with Sphinx.
|
|
596
630
|
"""
|