Sphinx 8.1.2__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.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +48 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +114 -57
- sphinx/domains/python/_object.py +151 -67
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +21 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +66 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +271 -143
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +61 -50
- sphinx/writers/latex.py +80 -65
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +44 -45
- sphinx/writers/text.py +48 -30
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/__init__.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""The Sphinx documentation toolchain."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__version__ = '8.2.0rc1'
|
|
4
6
|
__display_version__ = __version__ # used for command line version
|
|
5
7
|
|
|
6
8
|
# Keep this file executable as-is in Python 3!
|
|
@@ -9,6 +11,8 @@ __display_version__ = __version__ # used for command line version
|
|
|
9
11
|
import os
|
|
10
12
|
import warnings
|
|
11
13
|
|
|
14
|
+
from sphinx.util._pathlib import _StrPath
|
|
15
|
+
|
|
12
16
|
# by default, all DeprecationWarning under sphinx package will be emit.
|
|
13
17
|
# Users can avoid this by using environment variable: PYTHONWARNINGS=
|
|
14
18
|
if 'PYTHONWARNINGS' not in os.environ:
|
|
@@ -30,9 +34,9 @@ warnings.filterwarnings(
|
|
|
30
34
|
#:
|
|
31
35
|
#: .. versionadded:: 1.2
|
|
32
36
|
#: Before version 1.2, check the string ``sphinx.__version__``.
|
|
33
|
-
version_info = (8,
|
|
37
|
+
version_info = (8, 2, 0, 'candidate', 1)
|
|
34
38
|
|
|
35
|
-
package_dir =
|
|
39
|
+
package_dir = _StrPath(__file__).resolve().parent
|
|
36
40
|
|
|
37
41
|
_in_development = False
|
|
38
42
|
if _in_development:
|
|
@@ -41,7 +45,7 @@ if _in_development:
|
|
|
41
45
|
|
|
42
46
|
try:
|
|
43
47
|
if ret := subprocess.run(
|
|
44
|
-
['git', 'rev-parse', '--short', 'HEAD'],
|
|
48
|
+
['git', 'rev-parse', '--short', 'HEAD'], # NoQA: S607
|
|
45
49
|
cwd=package_dir,
|
|
46
50
|
capture_output=True,
|
|
47
51
|
check=False,
|
sphinx/__main__.py
CHANGED
sphinx/_cli/__init__.py
CHANGED
|
@@ -168,11 +168,8 @@ class _RootArgumentParser(argparse.ArgumentParser):
|
|
|
168
168
|
raise ValueError(msg)
|
|
169
169
|
|
|
170
170
|
def error(self, message: str) -> NoReturn:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
'{0}: error: {1}\n' "Run '{0} --help' for information" # NoQA: COM812
|
|
174
|
-
).format(self.prog, message)
|
|
175
|
-
)
|
|
171
|
+
msg = __("{0}: error: {1}\nRun '{0} --help' for information")
|
|
172
|
+
sys.stderr.write(msg.format(self.prog, message))
|
|
176
173
|
raise SystemExit(2)
|
|
177
174
|
|
|
178
175
|
|
sphinx/_cli/util/colour.py
CHANGED
|
@@ -2,24 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import os
|
|
6
5
|
import sys
|
|
7
|
-
from
|
|
6
|
+
from os import environ as _environ
|
|
7
|
+
|
|
8
|
+
TYPE_CHECKING = False
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Callable
|
|
8
11
|
|
|
9
12
|
if sys.platform == 'win32':
|
|
10
13
|
import colorama
|
|
11
14
|
|
|
15
|
+
colorama.just_fix_windows_console()
|
|
16
|
+
del colorama
|
|
17
|
+
|
|
12
18
|
|
|
13
|
-
_COLOURING_DISABLED =
|
|
19
|
+
_COLOURING_DISABLED = False
|
|
14
20
|
|
|
15
21
|
|
|
16
22
|
def terminal_supports_colour() -> bool:
|
|
17
23
|
"""Return True if coloured terminal output is supported."""
|
|
18
|
-
if 'NO_COLOUR' in
|
|
24
|
+
if 'NO_COLOUR' in _environ or 'NO_COLOR' in _environ:
|
|
19
25
|
return False
|
|
20
26
|
if sys.platform == 'win32':
|
|
21
|
-
|
|
22
|
-
if 'FORCE_COLOUR' in
|
|
27
|
+
return True
|
|
28
|
+
if 'FORCE_COLOUR' in _environ or 'FORCE_COLOR' in _environ:
|
|
29
|
+
return True
|
|
30
|
+
if _environ.get('CI', '').lower() in {'true', '1'}:
|
|
23
31
|
return True
|
|
24
32
|
|
|
25
33
|
try:
|
|
@@ -31,23 +39,37 @@ def terminal_supports_colour() -> bool:
|
|
|
31
39
|
return False
|
|
32
40
|
|
|
33
41
|
# Do not colour output if on a dumb terminal
|
|
34
|
-
return
|
|
42
|
+
return _environ.get('TERM', 'unknown').lower() not in {'dumb', 'unknown'}
|
|
35
43
|
|
|
36
44
|
|
|
37
45
|
def disable_colour() -> None:
|
|
38
|
-
global _COLOURING_DISABLED
|
|
46
|
+
global _COLOURING_DISABLED # NoQA: PLW0603
|
|
39
47
|
_COLOURING_DISABLED = True
|
|
40
48
|
|
|
41
49
|
|
|
42
50
|
def enable_colour() -> None:
|
|
43
|
-
global _COLOURING_DISABLED
|
|
51
|
+
global _COLOURING_DISABLED # NoQA: PLW0603
|
|
44
52
|
_COLOURING_DISABLED = False
|
|
45
53
|
|
|
46
54
|
|
|
47
55
|
def colourise(colour_name: str, text: str, /) -> str:
|
|
48
56
|
if _COLOURING_DISABLED:
|
|
49
57
|
return text
|
|
50
|
-
|
|
58
|
+
if colour_name.startswith('_') or colour_name in {
|
|
59
|
+
'annotations',
|
|
60
|
+
'sys',
|
|
61
|
+
'terminal_supports_colour',
|
|
62
|
+
'disable_colour',
|
|
63
|
+
'enable_colour',
|
|
64
|
+
'colourise',
|
|
65
|
+
}:
|
|
66
|
+
msg = f'Invalid colour name: {colour_name!r}'
|
|
67
|
+
raise ValueError(msg)
|
|
68
|
+
try:
|
|
69
|
+
return globals()[colour_name](text)
|
|
70
|
+
except KeyError:
|
|
71
|
+
msg = f'Invalid colour name: {colour_name!r}'
|
|
72
|
+
raise ValueError(msg) from None
|
|
51
73
|
|
|
52
74
|
|
|
53
75
|
def _create_colour_func(escape_code: str, /) -> Callable[[str], str]:
|
|
@@ -56,6 +78,7 @@ def _create_colour_func(escape_code: str, /) -> Callable[[str], str]:
|
|
|
56
78
|
return text
|
|
57
79
|
return f'\x1b[{escape_code}m{text}\x1b[39;49;00m'
|
|
58
80
|
|
|
81
|
+
inner.__escape_code = escape_code # type: ignore[attr-defined]
|
|
59
82
|
return inner
|
|
60
83
|
|
|
61
84
|
|
|
@@ -73,7 +96,7 @@ else:
|
|
|
73
96
|
def inner(text: str) -> str:
|
|
74
97
|
if _COLOURING_DISABLED:
|
|
75
98
|
return text
|
|
76
|
-
return f'\
|
|
99
|
+
return f'\1\x1b[{escape_code}m\2{text}\1\x1b[39;49;00m\2'
|
|
77
100
|
|
|
78
101
|
return inner
|
|
79
102
|
|
sphinx/_cli/util/errors.py
CHANGED
|
@@ -2,15 +2,35 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
|
-
import
|
|
6
|
-
from typing import TYPE_CHECKING, TextIO
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
7
6
|
|
|
8
|
-
from sphinx.errors import SphinxParallelError
|
|
7
|
+
from sphinx.errors import SphinxError, SphinxParallelError
|
|
9
8
|
|
|
10
9
|
if TYPE_CHECKING:
|
|
11
|
-
from
|
|
10
|
+
from collections.abc import Collection
|
|
11
|
+
from typing import Final, Protocol
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
from sphinx.extension import Extension
|
|
14
|
+
|
|
15
|
+
class SupportsWrite(Protocol):
|
|
16
|
+
def write(self, text: str, /) -> int | None: ...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_CSI: Final[str] = re.escape('\x1b[') # 'ESC [': Control Sequence Introducer
|
|
20
|
+
|
|
21
|
+
# Pattern matching ANSI CSI colors (SGR) and erase line (EL) sequences.
|
|
22
|
+
#
|
|
23
|
+
# See ``_strip_escape_sequences()`` for details.
|
|
24
|
+
_ANSI_CODES: Final[re.Pattern[str]] = re.compile(
|
|
25
|
+
'\x1b'
|
|
26
|
+
r"""\[
|
|
27
|
+
(?:
|
|
28
|
+
(?:\d+;){0,2}\d*m # ANSI color code ('m' is equivalent to '0m')
|
|
29
|
+
|
|
|
30
|
+
[012]?K # ANSI Erase in Line ('K' is equivalent to '0K')
|
|
31
|
+
)""",
|
|
32
|
+
re.VERBOSE | re.ASCII,
|
|
33
|
+
)
|
|
14
34
|
|
|
15
35
|
|
|
16
36
|
def terminal_safe(s: str, /) -> str:
|
|
@@ -18,11 +38,63 @@ def terminal_safe(s: str, /) -> str:
|
|
|
18
38
|
return s.encode('ascii', 'backslashreplace').decode('ascii')
|
|
19
39
|
|
|
20
40
|
|
|
21
|
-
def
|
|
22
|
-
|
|
41
|
+
def strip_escape_sequences(text: str, /) -> str:
|
|
42
|
+
r"""Remove the ANSI CSI colors and "erase in line" sequences.
|
|
43
|
+
|
|
44
|
+
Other `escape sequences <https://en.wikipedia.org/wiki/ANSI_escape_code>`_
|
|
45
|
+
(e.g., VT100-specific functions) are not supported. Only control sequences
|
|
46
|
+
*natively* known to Sphinx (i.e., colour sequences used in Sphinx
|
|
47
|
+
and "erase entire line" (``'\x1b[2K'``)) are stripped by this function.
|
|
48
|
+
|
|
49
|
+
.. warning:: This function only for use within Sphinx..
|
|
50
|
+
|
|
51
|
+
__ https://en.wikipedia.org/wiki/ANSI_escape_code
|
|
52
|
+
"""
|
|
53
|
+
return _ANSI_CODES.sub('', text)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def full_exception_context(
|
|
57
|
+
exception: BaseException,
|
|
58
|
+
*,
|
|
59
|
+
message_log: Collection[str] = (),
|
|
60
|
+
extensions: Collection[Extension] = (),
|
|
61
|
+
full_traceback: bool = True,
|
|
62
|
+
) -> str:
|
|
63
|
+
"""Return a formatted message containing useful debugging context."""
|
|
64
|
+
messages = [f' {strip_escape_sequences(msg)}'.rstrip() for msg in message_log]
|
|
65
|
+
while messages and not messages[-1]:
|
|
66
|
+
messages.pop()
|
|
67
|
+
last_msgs = '\n'.join(messages)
|
|
68
|
+
exts_list = '\n'.join(
|
|
69
|
+
f'* {ext.name} ({ext.version})'
|
|
70
|
+
for ext in extensions
|
|
71
|
+
if ext.version != 'builtin'
|
|
72
|
+
)
|
|
73
|
+
exc_format = format_traceback(exception, short_traceback=not full_traceback)
|
|
74
|
+
return error_info(last_msgs or 'None.', exts_list or 'None.', exc_format)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def format_traceback(
|
|
78
|
+
exception: BaseException, /, *, short_traceback: bool = False
|
|
79
|
+
) -> str:
|
|
80
|
+
"""Format the given exception's traceback."""
|
|
81
|
+
if short_traceback:
|
|
82
|
+
from traceback import TracebackException
|
|
83
|
+
|
|
84
|
+
# format an exception with traceback, but only the last frame.
|
|
85
|
+
te = TracebackException.from_exception(exception, limit=-1)
|
|
86
|
+
exc_format = te.stack.format()[-1] + ''.join(te.format_exception_only())
|
|
87
|
+
elif isinstance(exception, SphinxParallelError):
|
|
88
|
+
exc_format = f'(Error in parallel process)\n{exception.traceback}'
|
|
89
|
+
else:
|
|
90
|
+
from traceback import format_exception
|
|
91
|
+
|
|
92
|
+
exc_format = ''.join(format_exception(exception))
|
|
93
|
+
return '\n'.join(f' {line}' for line in exc_format.rstrip().splitlines())
|
|
23
94
|
|
|
24
95
|
|
|
25
96
|
def error_info(messages: str, extensions: str, traceback: str) -> str:
|
|
97
|
+
"""Format the traceback and extensions list with environment information."""
|
|
26
98
|
import platform
|
|
27
99
|
|
|
28
100
|
import docutils
|
|
@@ -59,29 +131,30 @@ Traceback
|
|
|
59
131
|
"""
|
|
60
132
|
|
|
61
133
|
|
|
62
|
-
def save_traceback(
|
|
134
|
+
def save_traceback(
|
|
135
|
+
exception: BaseException,
|
|
136
|
+
*,
|
|
137
|
+
message_log: Collection[str] = (),
|
|
138
|
+
extensions: Collection[Extension] = (),
|
|
139
|
+
) -> str:
|
|
63
140
|
"""Save the given exception's traceback in a temporary file."""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
f'* {ext.name} ({ext.version})'
|
|
77
|
-
for ext in extensions
|
|
78
|
-
if ext.version != 'builtin'
|
|
79
|
-
)
|
|
141
|
+
output = full_exception_context(
|
|
142
|
+
exception=exception,
|
|
143
|
+
message_log=message_log,
|
|
144
|
+
extensions=extensions,
|
|
145
|
+
)
|
|
146
|
+
filename = write_temporary_file(output)
|
|
147
|
+
return filename
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def write_temporary_file(content: str) -> str:
|
|
151
|
+
"""Write content to a temporary file and return the filename."""
|
|
152
|
+
import tempfile
|
|
80
153
|
|
|
81
154
|
with tempfile.NamedTemporaryFile(
|
|
82
|
-
suffix='.log', prefix='sphinx-err-', delete=False
|
|
155
|
+
'w', encoding='utf-8', suffix='.log', prefix='sphinx-err-', delete=False
|
|
83
156
|
) as f:
|
|
84
|
-
f.write(
|
|
157
|
+
f.write(content)
|
|
85
158
|
|
|
86
159
|
return f.name
|
|
87
160
|
|
|
@@ -90,18 +163,17 @@ def handle_exception(
|
|
|
90
163
|
exception: BaseException,
|
|
91
164
|
/,
|
|
92
165
|
*,
|
|
93
|
-
stderr:
|
|
166
|
+
stderr: SupportsWrite = sys.stderr,
|
|
94
167
|
use_pdb: bool = False,
|
|
95
168
|
print_traceback: bool = False,
|
|
96
|
-
|
|
169
|
+
message_log: Collection[str] = (),
|
|
170
|
+
extensions: Collection[Extension] = (),
|
|
97
171
|
) -> None:
|
|
98
172
|
from bdb import BdbQuit
|
|
99
|
-
from traceback import TracebackException, print_exc
|
|
100
173
|
|
|
101
174
|
from docutils.utils import SystemMessage
|
|
102
175
|
|
|
103
176
|
from sphinx._cli.util.colour import red
|
|
104
|
-
from sphinx.errors import SphinxError
|
|
105
177
|
from sphinx.locale import __
|
|
106
178
|
|
|
107
179
|
if isinstance(exception, BdbQuit):
|
|
@@ -114,57 +186,52 @@ def handle_exception(
|
|
|
114
186
|
print_err(*map(red, values))
|
|
115
187
|
|
|
116
188
|
print_err()
|
|
117
|
-
if
|
|
118
|
-
print_exc(file=stderr)
|
|
119
|
-
print_err()
|
|
120
|
-
|
|
121
|
-
if use_pdb:
|
|
122
|
-
from pdb import post_mortem
|
|
123
|
-
|
|
124
|
-
print_red(__('Exception occurred, starting debugger:'))
|
|
125
|
-
post_mortem()
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
if isinstance(exception, KeyboardInterrupt):
|
|
189
|
+
if not use_pdb and isinstance(exception, KeyboardInterrupt):
|
|
129
190
|
print_err(__('Interrupted!'))
|
|
130
191
|
return
|
|
131
192
|
|
|
132
193
|
if isinstance(exception, SystemMessage):
|
|
133
|
-
print_red(__('reStructuredText markup error
|
|
134
|
-
print_err(str(exception))
|
|
135
|
-
return
|
|
194
|
+
print_red(__('reStructuredText markup error!'))
|
|
136
195
|
|
|
137
196
|
if isinstance(exception, SphinxError):
|
|
138
|
-
print_red(f'{exception.category}
|
|
139
|
-
print_err(str(exception))
|
|
140
|
-
return
|
|
197
|
+
print_red(f'{exception.category}!')
|
|
141
198
|
|
|
142
199
|
if isinstance(exception, UnicodeError):
|
|
143
|
-
print_red(__('Encoding error
|
|
144
|
-
print_err(str(exception))
|
|
145
|
-
return
|
|
200
|
+
print_red(__('Encoding error!'))
|
|
146
201
|
|
|
147
202
|
if isinstance(exception, RecursionError):
|
|
148
|
-
print_red(__('Recursion error
|
|
149
|
-
print_err(str(exception))
|
|
203
|
+
print_red(__('Recursion error!'))
|
|
150
204
|
print_err()
|
|
151
205
|
print_err(
|
|
152
206
|
__(
|
|
153
207
|
'This can happen with very large or deeply nested source '
|
|
154
208
|
'files. You can carefully increase the default Python '
|
|
155
|
-
'recursion limit of
|
|
209
|
+
'recursion limit of 1,000 in conf.py with e.g.:'
|
|
156
210
|
)
|
|
157
211
|
)
|
|
158
212
|
print_err('\n import sys\n sys.setrecursionlimit(1_500)\n')
|
|
159
|
-
return
|
|
160
213
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
214
|
+
print_err()
|
|
215
|
+
error_context = full_exception_context(
|
|
216
|
+
exception,
|
|
217
|
+
message_log=message_log,
|
|
218
|
+
extensions=extensions,
|
|
219
|
+
full_traceback=print_traceback or use_pdb,
|
|
220
|
+
)
|
|
221
|
+
print_err(error_context)
|
|
222
|
+
print_err()
|
|
223
|
+
|
|
224
|
+
if use_pdb:
|
|
225
|
+
from pdb import post_mortem
|
|
164
226
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
227
|
+
print_red(__('Starting debugger:'))
|
|
228
|
+
post_mortem(exception.__traceback__)
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
# Save full traceback to log file
|
|
232
|
+
traceback_info_path = save_traceback(
|
|
233
|
+
exception, message_log=message_log, extensions=extensions
|
|
234
|
+
)
|
|
168
235
|
print_err(__('The full traceback has been saved in:'))
|
|
169
236
|
print_err(traceback_info_path)
|
|
170
237
|
print_err()
|
sphinx/addnodes.py
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from docutils import nodes
|
|
8
|
+
from docutils.nodes import document # NoQA: F401
|
|
8
9
|
|
|
9
10
|
if TYPE_CHECKING:
|
|
10
11
|
from collections.abc import Sequence
|
|
12
|
+
from typing import Any
|
|
11
13
|
|
|
12
14
|
from docutils.nodes import Element
|
|
13
15
|
|
|
@@ -15,21 +17,6 @@ if TYPE_CHECKING:
|
|
|
15
17
|
from sphinx.util.typing import ExtensionMetadata
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
class document(nodes.document):
|
|
19
|
-
"""The document root element patched by Sphinx.
|
|
20
|
-
|
|
21
|
-
This fixes that document.set_id() does not support a node having multiple node Ids.
|
|
22
|
-
see https://sourceforge.net/p/docutils/patches/167/
|
|
23
|
-
|
|
24
|
-
.. important:: This is only for Sphinx internal use. Please don't use this
|
|
25
|
-
in your extensions. It will be removed without deprecation period.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
def set_id(self, node: Element, msgnode: Element | None = None,
|
|
29
|
-
suggested_prefix: str = '') -> str:
|
|
30
|
-
return super().set_id(node, msgnode, suggested_prefix)
|
|
31
|
-
|
|
32
|
-
|
|
33
20
|
class translatable(nodes.Node):
|
|
34
21
|
"""Node which supports translation.
|
|
35
22
|
|
|
@@ -48,7 +35,9 @@ class translatable(nodes.Node):
|
|
|
48
35
|
"""Preserve original translatable messages."""
|
|
49
36
|
raise NotImplementedError
|
|
50
37
|
|
|
51
|
-
def apply_translated_message(
|
|
38
|
+
def apply_translated_message(
|
|
39
|
+
self, original_message: str, translated_message: str
|
|
40
|
+
) -> None:
|
|
52
41
|
"""Apply translated message."""
|
|
53
42
|
raise NotImplementedError
|
|
54
43
|
|
|
@@ -80,7 +69,9 @@ class toctree(nodes.General, nodes.Element, translatable):
|
|
|
80
69
|
if self.get('caption'):
|
|
81
70
|
self['rawcaption'] = self['caption']
|
|
82
71
|
|
|
83
|
-
def apply_translated_message(
|
|
72
|
+
def apply_translated_message(
|
|
73
|
+
self, original_message: str, translated_message: str
|
|
74
|
+
) -> None:
|
|
84
75
|
# toctree entries
|
|
85
76
|
for i, (title, docname) in enumerate(self['entries']):
|
|
86
77
|
if title == original_message:
|
|
@@ -106,6 +97,7 @@ class toctree(nodes.General, nodes.Element, translatable):
|
|
|
106
97
|
# Domain-specific object descriptions (class, function etc.)
|
|
107
98
|
#############################################################
|
|
108
99
|
|
|
100
|
+
|
|
109
101
|
class _desc_classes_injector(nodes.Element, not_smartquotable):
|
|
110
102
|
"""Helper base class for injecting a fixed list of classes.
|
|
111
103
|
|
|
@@ -122,6 +114,7 @@ class _desc_classes_injector(nodes.Element, not_smartquotable):
|
|
|
122
114
|
# Top-level nodes
|
|
123
115
|
#################
|
|
124
116
|
|
|
117
|
+
|
|
125
118
|
class desc(nodes.Admonition, nodes.Element):
|
|
126
119
|
"""Node for a list of object signatures and a common description of them.
|
|
127
120
|
|
|
@@ -138,7 +131,9 @@ class desc(nodes.Admonition, nodes.Element):
|
|
|
138
131
|
# that forces the specification of the domain and objtyp?
|
|
139
132
|
|
|
140
133
|
|
|
141
|
-
class desc_signature(
|
|
134
|
+
class desc_signature(
|
|
135
|
+
_desc_classes_injector, nodes.Part, nodes.Inline, nodes.TextElement
|
|
136
|
+
):
|
|
142
137
|
"""Node for a single object signature.
|
|
143
138
|
|
|
144
139
|
As default the signature is a single-line signature.
|
|
@@ -198,7 +193,10 @@ class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement):
|
|
|
198
193
|
|
|
199
194
|
# nodes to use within a desc_signature or desc_signature_line
|
|
200
195
|
|
|
201
|
-
|
|
196
|
+
|
|
197
|
+
class desc_name(
|
|
198
|
+
_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTextElement
|
|
199
|
+
):
|
|
202
200
|
"""Node for the main object name.
|
|
203
201
|
|
|
204
202
|
For example, in the declaration of a Python class ``MyModule.MyClass``,
|
|
@@ -210,7 +208,9 @@ class desc_name(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTex
|
|
|
210
208
|
classes = ['sig-name', 'descname'] # 'descname' is for backwards compatibility
|
|
211
209
|
|
|
212
210
|
|
|
213
|
-
class desc_addname(
|
|
211
|
+
class desc_addname(
|
|
212
|
+
_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTextElement
|
|
213
|
+
):
|
|
214
214
|
"""Node for additional name parts for an object.
|
|
215
215
|
|
|
216
216
|
For example, in the declaration of a Python class ``MyModule.MyClass``,
|
|
@@ -244,6 +244,8 @@ class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
|
|
244
244
|
As default the parameter list is written in line with the rest of the signature.
|
|
245
245
|
Set ``multi_line_parameter_list = True`` to describe a multi-line parameter list.
|
|
246
246
|
In that case each parameter will then be written on its own, indented line.
|
|
247
|
+
A trailing comma will be added on the last line
|
|
248
|
+
if ``multi_line_trailing_comma`` is True.
|
|
247
249
|
"""
|
|
248
250
|
|
|
249
251
|
child_text_separator = ', '
|
|
@@ -258,6 +260,8 @@ class desc_type_parameter_list(nodes.Part, nodes.Inline, nodes.FixedTextElement)
|
|
|
258
260
|
As default the type parameters list is written in line with the rest of the signature.
|
|
259
261
|
Set ``multi_line_parameter_list = True`` to describe a multi-line type parameters list.
|
|
260
262
|
In that case each type parameter will then be written on its own, indented line.
|
|
263
|
+
A trailing comma will be added on the last line
|
|
264
|
+
if ``multi_line_trailing_comma`` is True.
|
|
261
265
|
"""
|
|
262
266
|
|
|
263
267
|
child_text_separator = ', '
|
|
@@ -305,13 +309,15 @@ SIG_ELEMENTS: set[type[desc_sig_element]] = set()
|
|
|
305
309
|
# When adding a new one, add it to SIG_ELEMENTS via the class
|
|
306
310
|
# keyword argument `_sig_element=True` (e.g., see `desc_sig_space`).
|
|
307
311
|
|
|
312
|
+
|
|
308
313
|
class desc_sig_element(nodes.inline, _desc_classes_injector):
|
|
309
314
|
"""Common parent class of nodes for inline text of a signature."""
|
|
310
315
|
|
|
311
316
|
classes: list[str] = []
|
|
312
317
|
|
|
313
|
-
def __init__(
|
|
314
|
-
|
|
318
|
+
def __init__(
|
|
319
|
+
self, rawsource: str = '', text: str = '', *children: Element, **attributes: Any
|
|
320
|
+
) -> None:
|
|
315
321
|
super().__init__(rawsource, text, *children, **attributes)
|
|
316
322
|
self['classes'].extend(self.classes)
|
|
317
323
|
|
|
@@ -325,67 +331,74 @@ class desc_sig_element(nodes.inline, _desc_classes_injector):
|
|
|
325
331
|
# to not reinvent the wheel, the classes in the following desc_sig classes
|
|
326
332
|
# are based on those used in Pygments
|
|
327
333
|
|
|
334
|
+
|
|
328
335
|
class desc_sig_space(desc_sig_element, _sig_element=True):
|
|
329
336
|
"""Node for a space in a signature."""
|
|
330
337
|
|
|
331
|
-
classes = [
|
|
338
|
+
classes = ['w']
|
|
332
339
|
|
|
333
|
-
def __init__(
|
|
334
|
-
|
|
340
|
+
def __init__(
|
|
341
|
+
self,
|
|
342
|
+
rawsource: str = '',
|
|
343
|
+
text: str = ' ',
|
|
344
|
+
*children: Element,
|
|
345
|
+
**attributes: Any,
|
|
346
|
+
) -> None:
|
|
335
347
|
super().__init__(rawsource, text, *children, **attributes)
|
|
336
348
|
|
|
337
349
|
|
|
338
350
|
class desc_sig_name(desc_sig_element, _sig_element=True):
|
|
339
351
|
"""Node for an identifier in a signature."""
|
|
340
352
|
|
|
341
|
-
classes = [
|
|
353
|
+
classes = ['n']
|
|
342
354
|
|
|
343
355
|
|
|
344
356
|
class desc_sig_operator(desc_sig_element, _sig_element=True):
|
|
345
357
|
"""Node for an operator in a signature."""
|
|
346
358
|
|
|
347
|
-
classes = [
|
|
359
|
+
classes = ['o']
|
|
348
360
|
|
|
349
361
|
|
|
350
362
|
class desc_sig_punctuation(desc_sig_element, _sig_element=True):
|
|
351
363
|
"""Node for punctuation in a signature."""
|
|
352
364
|
|
|
353
|
-
classes = [
|
|
365
|
+
classes = ['p']
|
|
354
366
|
|
|
355
367
|
|
|
356
368
|
class desc_sig_keyword(desc_sig_element, _sig_element=True):
|
|
357
369
|
"""Node for a general keyword in a signature."""
|
|
358
370
|
|
|
359
|
-
classes = [
|
|
371
|
+
classes = ['k']
|
|
360
372
|
|
|
361
373
|
|
|
362
374
|
class desc_sig_keyword_type(desc_sig_element, _sig_element=True):
|
|
363
375
|
"""Node for a keyword which is a built-in type in a signature."""
|
|
364
376
|
|
|
365
|
-
classes = [
|
|
377
|
+
classes = ['kt']
|
|
366
378
|
|
|
367
379
|
|
|
368
380
|
class desc_sig_literal_number(desc_sig_element, _sig_element=True):
|
|
369
381
|
"""Node for a numeric literal in a signature."""
|
|
370
382
|
|
|
371
|
-
classes = [
|
|
383
|
+
classes = ['m']
|
|
372
384
|
|
|
373
385
|
|
|
374
386
|
class desc_sig_literal_string(desc_sig_element, _sig_element=True):
|
|
375
387
|
"""Node for a string literal in a signature."""
|
|
376
388
|
|
|
377
|
-
classes = [
|
|
389
|
+
classes = ['s']
|
|
378
390
|
|
|
379
391
|
|
|
380
392
|
class desc_sig_literal_char(desc_sig_element, _sig_element=True):
|
|
381
393
|
"""Node for a character literal in a signature."""
|
|
382
394
|
|
|
383
|
-
classes = [
|
|
395
|
+
classes = ['sc']
|
|
384
396
|
|
|
385
397
|
|
|
386
398
|
###############################################################
|
|
387
399
|
# new admonition-like constructs
|
|
388
400
|
|
|
401
|
+
|
|
389
402
|
class versionmodified(nodes.Admonition, nodes.TextElement):
|
|
390
403
|
"""Node for version change entries.
|
|
391
404
|
|
|
@@ -411,6 +424,7 @@ class production(nodes.Part, nodes.Inline, nodes.FixedTextElement):
|
|
|
411
424
|
|
|
412
425
|
# other directive-level nodes
|
|
413
426
|
|
|
427
|
+
|
|
414
428
|
class index(nodes.Invisible, nodes.Inline, nodes.TextElement):
|
|
415
429
|
"""Node for index entries.
|
|
416
430
|
|
|
@@ -422,7 +436,7 @@ class index(nodes.Invisible, nodes.Inline, nodes.TextElement):
|
|
|
422
436
|
|
|
423
437
|
*key* is categorization characters (usually a single character) for
|
|
424
438
|
general index page. For the details of this, please see also:
|
|
425
|
-
:rst:dir:`glossary` and
|
|
439
|
+
:rst:dir:`glossary` and https://github.com/sphinx-doc/sphinx/pull/2320.
|
|
426
440
|
"""
|
|
427
441
|
|
|
428
442
|
|
|
@@ -458,6 +472,7 @@ class only(nodes.Element):
|
|
|
458
472
|
|
|
459
473
|
# meta-information nodes
|
|
460
474
|
|
|
475
|
+
|
|
461
476
|
class start_of_file(nodes.Element):
|
|
462
477
|
"""Node to mark start of a new file, used in the LaTeX builder only."""
|
|
463
478
|
|
|
@@ -474,6 +489,7 @@ class tabular_col_spec(nodes.Element):
|
|
|
474
489
|
|
|
475
490
|
# inline nodes
|
|
476
491
|
|
|
492
|
+
|
|
477
493
|
class pending_xref(nodes.Inline, nodes.Element):
|
|
478
494
|
"""Node for cross-references that cannot be resolved without complete
|
|
479
495
|
information about all documents.
|