Sphinx 8.1.3__py3-none-any.whl → 8.2.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- 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 +829 -480
- 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.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.3.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.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/util/docutils.py
CHANGED
|
@@ -4,22 +4,20 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import re
|
|
7
|
-
from collections.abc import Sequence # NoQA: TCH003
|
|
8
7
|
from contextlib import contextmanager
|
|
9
8
|
from copy import copy
|
|
10
|
-
from
|
|
11
|
-
from typing import
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
12
11
|
|
|
13
12
|
import docutils
|
|
14
13
|
from docutils import nodes
|
|
15
14
|
from docutils.io import FileOutput
|
|
16
15
|
from docutils.parsers.rst import Directive, directives, roles
|
|
17
|
-
from docutils.
|
|
18
|
-
from docutils.statemachine import State, StateMachine, StringList
|
|
16
|
+
from docutils.statemachine import StateMachine
|
|
19
17
|
from docutils.utils import Reporter, unescape
|
|
20
18
|
|
|
21
19
|
from sphinx.errors import SphinxError
|
|
22
|
-
from sphinx.locale import
|
|
20
|
+
from sphinx.locale import __
|
|
23
21
|
from sphinx.util import logging
|
|
24
22
|
from sphinx.util.parsing import nested_parse_to_nodes
|
|
25
23
|
|
|
@@ -29,17 +27,44 @@ report_re = re.compile(
|
|
|
29
27
|
)
|
|
30
28
|
|
|
31
29
|
if TYPE_CHECKING:
|
|
32
|
-
from collections.abc import
|
|
33
|
-
from types import ModuleType
|
|
30
|
+
from collections.abc import Iterator, Sequence
|
|
31
|
+
from types import ModuleType, TracebackType
|
|
32
|
+
from typing import Any, Protocol
|
|
34
33
|
|
|
35
34
|
from docutils.frontend import Values
|
|
36
35
|
from docutils.nodes import Element, Node, system_message
|
|
36
|
+
from docutils.parsers.rst.states import Inliner
|
|
37
|
+
from docutils.statemachine import State, StringList
|
|
37
38
|
|
|
38
39
|
from sphinx.builders import Builder
|
|
39
40
|
from sphinx.config import Config
|
|
40
41
|
from sphinx.environment import BuildEnvironment
|
|
41
42
|
from sphinx.util.typing import RoleFunction
|
|
42
43
|
|
|
44
|
+
class _LanguageModule(Protocol):
|
|
45
|
+
labels: dict[str, str]
|
|
46
|
+
author_separators: list[str]
|
|
47
|
+
bibliographic_fields: list[str]
|
|
48
|
+
|
|
49
|
+
class _DirectivesDispatcher(Protocol):
|
|
50
|
+
def __call__(
|
|
51
|
+
self,
|
|
52
|
+
directive_name: str,
|
|
53
|
+
language_module: _LanguageModule,
|
|
54
|
+
document: nodes.document,
|
|
55
|
+
/,
|
|
56
|
+
) -> tuple[type[Directive] | None, list[system_message]]: ...
|
|
57
|
+
|
|
58
|
+
class _RolesDispatcher(Protocol):
|
|
59
|
+
def __call__(
|
|
60
|
+
self,
|
|
61
|
+
role_name: str,
|
|
62
|
+
language_module: _LanguageModule,
|
|
63
|
+
lineno: int,
|
|
64
|
+
reporter: Reporter,
|
|
65
|
+
/,
|
|
66
|
+
) -> tuple[RoleFunction | None, list[system_message]]: ...
|
|
67
|
+
|
|
43
68
|
|
|
44
69
|
additional_nodes: set[type[Element]] = set()
|
|
45
70
|
|
|
@@ -127,7 +152,7 @@ def patched_get_language() -> Iterator[None]:
|
|
|
127
152
|
"""Patch docutils.languages.get_language() temporarily.
|
|
128
153
|
|
|
129
154
|
This ignores the second argument ``reporter`` to suppress warnings.
|
|
130
|
-
|
|
155
|
+
See: https://github.com/sphinx-doc/sphinx/issues/3788
|
|
131
156
|
"""
|
|
132
157
|
from docutils.languages import get_language
|
|
133
158
|
|
|
@@ -153,7 +178,7 @@ def patched_rst_get_language() -> Iterator[None]:
|
|
|
153
178
|
This should also work for old versions of docutils,
|
|
154
179
|
because reporter is none by default.
|
|
155
180
|
|
|
156
|
-
|
|
181
|
+
See: https://github.com/sphinx-doc/sphinx/issues/10179
|
|
157
182
|
"""
|
|
158
183
|
from docutils.parsers.rst.languages import get_language
|
|
159
184
|
|
|
@@ -171,25 +196,23 @@ def patched_rst_get_language() -> Iterator[None]:
|
|
|
171
196
|
|
|
172
197
|
|
|
173
198
|
@contextmanager
|
|
174
|
-
def using_user_docutils_conf(confdir: str | None) -> Iterator[None]:
|
|
199
|
+
def using_user_docutils_conf(confdir: str | os.PathLike[str] | None) -> Iterator[None]:
|
|
175
200
|
"""Let docutils know the location of ``docutils.conf`` for Sphinx."""
|
|
176
201
|
try:
|
|
177
|
-
|
|
202
|
+
docutils_config = os.environ.get('DOCUTILSCONFIG', None)
|
|
178
203
|
if confdir:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
|
|
204
|
+
docutils_conf_path = Path(confdir, 'docutils.conf').resolve()
|
|
205
|
+
os.environ['DOCUTILSCONFIG'] = str(docutils_conf_path)
|
|
183
206
|
yield
|
|
184
207
|
finally:
|
|
185
|
-
if
|
|
208
|
+
if docutils_config is None:
|
|
186
209
|
os.environ.pop('DOCUTILSCONFIG', None)
|
|
187
210
|
else:
|
|
188
|
-
os.environ['DOCUTILSCONFIG'] =
|
|
211
|
+
os.environ['DOCUTILSCONFIG'] = docutils_config
|
|
189
212
|
|
|
190
213
|
|
|
191
214
|
@contextmanager
|
|
192
|
-
def patch_docutils(confdir: str | None = None) -> Iterator[None]:
|
|
215
|
+
def patch_docutils(confdir: str | os.PathLike[str] | None = None) -> Iterator[None]:
|
|
193
216
|
"""Patch to docutils temporarily."""
|
|
194
217
|
with (
|
|
195
218
|
patched_get_language(),
|
|
@@ -207,14 +230,17 @@ class CustomReSTDispatcher:
|
|
|
207
230
|
"""
|
|
208
231
|
|
|
209
232
|
def __init__(self) -> None:
|
|
210
|
-
self.directive_func:
|
|
211
|
-
self.roles_func:
|
|
233
|
+
self.directive_func: _DirectivesDispatcher = lambda *args: (None, [])
|
|
234
|
+
self.roles_func: _RolesDispatcher = lambda *args: (None, [])
|
|
212
235
|
|
|
213
236
|
def __enter__(self) -> None:
|
|
214
237
|
self.enable()
|
|
215
238
|
|
|
216
239
|
def __exit__(
|
|
217
|
-
self,
|
|
240
|
+
self,
|
|
241
|
+
exc_type: type[BaseException] | None,
|
|
242
|
+
exc_value: BaseException | None,
|
|
243
|
+
traceback: TracebackType | None,
|
|
218
244
|
) -> None:
|
|
219
245
|
self.disable()
|
|
220
246
|
|
|
@@ -226,7 +252,7 @@ class CustomReSTDispatcher:
|
|
|
226
252
|
roles.role = self.role # type: ignore[assignment]
|
|
227
253
|
|
|
228
254
|
def disable(self) -> None:
|
|
229
|
-
directives.directive = self.directive_func
|
|
255
|
+
directives.directive = self.directive_func # type: ignore[assignment]
|
|
230
256
|
roles.role = self.role_func
|
|
231
257
|
|
|
232
258
|
def directive(
|
|
@@ -262,51 +288,44 @@ class sphinx_domains(CustomReSTDispatcher):
|
|
|
262
288
|
"""
|
|
263
289
|
|
|
264
290
|
def __init__(self, env: BuildEnvironment) -> None:
|
|
265
|
-
self.
|
|
291
|
+
self.domains = env.domains
|
|
292
|
+
self.current_document = env.current_document
|
|
266
293
|
super().__init__()
|
|
267
294
|
|
|
268
|
-
def
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
295
|
+
def directive(
|
|
296
|
+
self,
|
|
297
|
+
directive_name: str,
|
|
298
|
+
language_module: ModuleType,
|
|
299
|
+
document: nodes.document,
|
|
300
|
+
) -> tuple[type[Directive] | None, list[system_message]]:
|
|
301
|
+
"""Lookup a directive, given its name which can include a domain."""
|
|
302
|
+
directive_name = directive_name.lower()
|
|
273
303
|
# explicit domain given?
|
|
274
|
-
if ':' in
|
|
275
|
-
domain_name, name =
|
|
276
|
-
|
|
277
|
-
domain = self.
|
|
278
|
-
|
|
304
|
+
if ':' in directive_name:
|
|
305
|
+
domain_name, _, name = directive_name.partition(':')
|
|
306
|
+
try:
|
|
307
|
+
domain = self.domains[domain_name]
|
|
308
|
+
except KeyError:
|
|
309
|
+
logger.warning(__('unknown directive name: %s'), directive_name)
|
|
310
|
+
else:
|
|
311
|
+
element = domain.directive(name)
|
|
279
312
|
if element is not None:
|
|
280
313
|
return element, []
|
|
281
|
-
else:
|
|
282
|
-
logger.warning(
|
|
283
|
-
_('unknown directive or role name: %s:%s'), domain_name, name
|
|
284
|
-
)
|
|
285
314
|
# else look in the default domain
|
|
286
315
|
else:
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
316
|
+
name = directive_name
|
|
317
|
+
default_domain = self.current_document.default_domain
|
|
318
|
+
if default_domain is not None:
|
|
319
|
+
element = default_domain.directive(name)
|
|
290
320
|
if element is not None:
|
|
291
321
|
return element, []
|
|
292
322
|
|
|
293
323
|
# always look in the std domain
|
|
294
|
-
element =
|
|
324
|
+
element = self.domains.standard_domain.directive(name)
|
|
295
325
|
if element is not None:
|
|
296
326
|
return element, []
|
|
297
327
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
def directive(
|
|
301
|
-
self,
|
|
302
|
-
directive_name: str,
|
|
303
|
-
language_module: ModuleType,
|
|
304
|
-
document: nodes.document,
|
|
305
|
-
) -> tuple[type[Directive] | None, list[system_message]]:
|
|
306
|
-
try:
|
|
307
|
-
return self.lookup_domain_element('directive', directive_name)
|
|
308
|
-
except ElementLookupError:
|
|
309
|
-
return super().directive(directive_name, language_module, document)
|
|
328
|
+
return super().directive(directive_name, language_module, document)
|
|
310
329
|
|
|
311
330
|
def role(
|
|
312
331
|
self,
|
|
@@ -315,10 +334,34 @@ class sphinx_domains(CustomReSTDispatcher):
|
|
|
315
334
|
lineno: int,
|
|
316
335
|
reporter: Reporter,
|
|
317
336
|
) -> tuple[RoleFunction, list[system_message]]:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
337
|
+
"""Lookup a role, given its name which can include a domain."""
|
|
338
|
+
role_name = role_name.lower()
|
|
339
|
+
# explicit domain given?
|
|
340
|
+
if ':' in role_name:
|
|
341
|
+
domain_name, _, name = role_name.partition(':')
|
|
342
|
+
try:
|
|
343
|
+
domain = self.domains[domain_name]
|
|
344
|
+
except KeyError:
|
|
345
|
+
logger.warning(__('unknown role name: %s'), role_name)
|
|
346
|
+
else:
|
|
347
|
+
element = domain.role(name)
|
|
348
|
+
if element is not None:
|
|
349
|
+
return element, []
|
|
350
|
+
# else look in the default domain
|
|
351
|
+
else:
|
|
352
|
+
name = role_name
|
|
353
|
+
default_domain = self.current_document.default_domain
|
|
354
|
+
if default_domain is not None:
|
|
355
|
+
element = default_domain.role(name)
|
|
356
|
+
if element is not None:
|
|
357
|
+
return element, []
|
|
358
|
+
|
|
359
|
+
# always look in the std domain
|
|
360
|
+
element = self.domains.standard_domain.role(name)
|
|
361
|
+
if element is not None:
|
|
362
|
+
return element, []
|
|
363
|
+
|
|
364
|
+
return super().role(role_name, language_module, lineno, reporter)
|
|
322
365
|
|
|
323
366
|
|
|
324
367
|
class WarningStream:
|
|
@@ -354,7 +397,7 @@ class LoggingReporter(Reporter):
|
|
|
354
397
|
debug: bool = False,
|
|
355
398
|
error_handler: str = 'backslashreplace',
|
|
356
399
|
) -> None:
|
|
357
|
-
stream =
|
|
400
|
+
stream = WarningStream()
|
|
358
401
|
super().__init__(
|
|
359
402
|
source, report_level, halt_level, stream, debug, error_handler=error_handler
|
|
360
403
|
)
|
|
@@ -368,7 +411,7 @@ class NullReporter(Reporter):
|
|
|
368
411
|
|
|
369
412
|
|
|
370
413
|
@contextmanager
|
|
371
|
-
def switch_source_input(state: State, content: StringList) -> Iterator[None]:
|
|
414
|
+
def switch_source_input(state: State[list[str]], content: StringList) -> Iterator[None]:
|
|
372
415
|
"""Switch current source input of state temporarily."""
|
|
373
416
|
try:
|
|
374
417
|
# remember the original ``get_source_and_line()`` method
|
|
@@ -377,7 +420,7 @@ def switch_source_input(state: State, content: StringList) -> Iterator[None]:
|
|
|
377
420
|
# replace it by new one
|
|
378
421
|
state_machine: StateMachine[None] = StateMachine([], None) # type: ignore[arg-type]
|
|
379
422
|
state_machine.input_lines = content
|
|
380
|
-
state.memo.reporter.get_source_and_line = state_machine.get_source_and_line # type: ignore[attr-defined]
|
|
423
|
+
state.memo.reporter.get_source_and_line = state_machine.get_source_and_line # type: ignore[attr-defined]
|
|
381
424
|
|
|
382
425
|
yield
|
|
383
426
|
finally:
|
|
@@ -402,9 +445,10 @@ class SphinxFileOutput(FileOutput):
|
|
|
402
445
|
and os.path.exists(self.destination_path)
|
|
403
446
|
):
|
|
404
447
|
with open(self.destination_path, encoding=self.encoding) as f:
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
448
|
+
on_disk = f.read()
|
|
449
|
+
# skip writing: content not changed
|
|
450
|
+
if on_disk == data:
|
|
451
|
+
return data
|
|
408
452
|
|
|
409
453
|
return super().write(data)
|
|
410
454
|
|
|
@@ -572,7 +616,7 @@ class SphinxRole:
|
|
|
572
616
|
text: str,
|
|
573
617
|
lineno: int,
|
|
574
618
|
inliner: Inliner,
|
|
575
|
-
options: dict | None = None,
|
|
619
|
+
options: dict[str, Any] | None = None,
|
|
576
620
|
content: Sequence[str] = (),
|
|
577
621
|
) -> tuple[list[Node], list[system_message]]:
|
|
578
622
|
self.rawtext = rawtext
|
|
@@ -586,7 +630,7 @@ class SphinxRole:
|
|
|
586
630
|
if name:
|
|
587
631
|
self.name = name.lower()
|
|
588
632
|
else:
|
|
589
|
-
self.name = self.env.
|
|
633
|
+
self.name = self.env.current_document.default_role
|
|
590
634
|
if not self.name:
|
|
591
635
|
self.name = self.env.config.default_role
|
|
592
636
|
if not self.name:
|
|
@@ -666,7 +710,7 @@ class ReferenceRole(SphinxRole):
|
|
|
666
710
|
text: str,
|
|
667
711
|
lineno: int,
|
|
668
712
|
inliner: Inliner,
|
|
669
|
-
options: dict | None = None,
|
|
713
|
+
options: dict[str, Any] | None = None,
|
|
670
714
|
content: Sequence[str] = (),
|
|
671
715
|
) -> tuple[list[Node], list[system_message]]:
|
|
672
716
|
if options is None:
|
|
@@ -707,10 +751,10 @@ class SphinxTranslator(nodes.NodeVisitor):
|
|
|
707
751
|
self.builder = builder
|
|
708
752
|
self.config = builder.config
|
|
709
753
|
self.settings = document.settings
|
|
754
|
+
self._domains = builder.env.domains
|
|
710
755
|
|
|
711
756
|
def dispatch_visit(self, node: Node) -> None:
|
|
712
|
-
"""
|
|
713
|
-
Dispatch node to appropriate visitor method.
|
|
757
|
+
"""Dispatch node to appropriate visitor method.
|
|
714
758
|
The priority of visitor method is:
|
|
715
759
|
|
|
716
760
|
1. ``self.visit_{node_class}()``
|
|
@@ -718,7 +762,7 @@ class SphinxTranslator(nodes.NodeVisitor):
|
|
|
718
762
|
3. ``self.unknown_visit()``
|
|
719
763
|
"""
|
|
720
764
|
for node_class in node.__class__.__mro__:
|
|
721
|
-
method = getattr(self, 'visit_%s' %
|
|
765
|
+
method = getattr(self, 'visit_%s' % node_class.__name__, None)
|
|
722
766
|
if method:
|
|
723
767
|
method(node)
|
|
724
768
|
break
|
|
@@ -726,8 +770,7 @@ class SphinxTranslator(nodes.NodeVisitor):
|
|
|
726
770
|
super().dispatch_visit(node)
|
|
727
771
|
|
|
728
772
|
def dispatch_departure(self, node: Node) -> None:
|
|
729
|
-
"""
|
|
730
|
-
Dispatch node to appropriate departure method.
|
|
773
|
+
"""Dispatch node to appropriate departure method.
|
|
731
774
|
The priority of departure method is:
|
|
732
775
|
|
|
733
776
|
1. ``self.depart_{node_class}()``
|
|
@@ -735,7 +778,7 @@ class SphinxTranslator(nodes.NodeVisitor):
|
|
|
735
778
|
3. ``self.unknown_departure()``
|
|
736
779
|
"""
|
|
737
780
|
for node_class in node.__class__.__mro__:
|
|
738
|
-
method = getattr(self, 'depart_%s' %
|
|
781
|
+
method = getattr(self, 'depart_%s' % node_class.__name__, None)
|
|
739
782
|
if method:
|
|
740
783
|
method(node)
|
|
741
784
|
break
|
|
@@ -758,7 +801,7 @@ def new_document(source_path: str, settings: Any = None) -> nodes.document:
|
|
|
758
801
|
caches the result of docutils' and use it on second call for instantiation.
|
|
759
802
|
This makes an instantiation of document nodes much faster.
|
|
760
803
|
"""
|
|
761
|
-
global __document_cache__
|
|
804
|
+
global __document_cache__ # NoQA: PLW0603
|
|
762
805
|
try:
|
|
763
806
|
cached_settings, reporter = __document_cache__
|
|
764
807
|
except NameError:
|
|
@@ -770,8 +813,6 @@ def new_document(source_path: str, settings: Any = None) -> nodes.document:
|
|
|
770
813
|
settings = copy(cached_settings)
|
|
771
814
|
|
|
772
815
|
# Create a new instance of nodes.document using cached reporter
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
document = addnodes.document(settings, reporter, source=source_path)
|
|
816
|
+
document = nodes.document(settings, reporter, source=source_path)
|
|
776
817
|
document.note_source(source_path, -1)
|
|
777
818
|
return document
|
sphinx/util/fileutil.py
CHANGED
|
@@ -5,16 +5,15 @@ from __future__ import annotations
|
|
|
5
5
|
import os
|
|
6
6
|
import posixpath
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
9
|
-
|
|
10
|
-
from docutils.utils import relative_path
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
11
9
|
|
|
12
10
|
from sphinx.locale import __
|
|
13
11
|
from sphinx.util import logging
|
|
14
|
-
from sphinx.util.osutil import copyfile, ensuredir
|
|
12
|
+
from sphinx.util.osutil import _relative_path, copyfile, ensuredir
|
|
15
13
|
|
|
16
14
|
if TYPE_CHECKING:
|
|
17
15
|
from collections.abc import Callable
|
|
16
|
+
from typing import Any
|
|
18
17
|
|
|
19
18
|
from sphinx.util.template import BaseRenderer
|
|
20
19
|
from sphinx.util.typing import PathMatcher
|
|
@@ -22,16 +21,16 @@ if TYPE_CHECKING:
|
|
|
22
21
|
logger = logging.getLogger(__name__)
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
def _template_basename(filename:
|
|
24
|
+
def _template_basename(filename: Path) -> Path | None:
|
|
26
25
|
"""Given an input filename:
|
|
27
26
|
If the input looks like a template, then return the filename output should
|
|
28
27
|
be written to. Otherwise, return no result (None).
|
|
29
28
|
"""
|
|
30
|
-
basename =
|
|
31
|
-
if basename.
|
|
32
|
-
return
|
|
33
|
-
elif basename.
|
|
34
|
-
return
|
|
29
|
+
basename = filename.name.lower()
|
|
30
|
+
if basename.endswith('_t'):
|
|
31
|
+
return filename.with_name(filename.name[:-2])
|
|
32
|
+
elif basename.endswith('.jinja'):
|
|
33
|
+
return filename.with_name(filename.name[:-6])
|
|
35
34
|
return None
|
|
36
35
|
|
|
37
36
|
|
|
@@ -54,13 +53,14 @@ def copy_asset_file(
|
|
|
54
53
|
:param renderer: The template engine. If not given, SphinxRenderer is used by default
|
|
55
54
|
:param bool force: Overwrite the destination file even if it exists.
|
|
56
55
|
"""
|
|
57
|
-
|
|
56
|
+
source = Path(source)
|
|
57
|
+
if not source.exists():
|
|
58
58
|
return
|
|
59
59
|
|
|
60
60
|
destination = Path(destination)
|
|
61
61
|
if destination.is_dir():
|
|
62
62
|
# Use source filename if destination points a directory
|
|
63
|
-
destination /=
|
|
63
|
+
destination /= source.name
|
|
64
64
|
|
|
65
65
|
if _template_basename(source) and context is not None:
|
|
66
66
|
if renderer is None:
|
|
@@ -68,8 +68,7 @@ def copy_asset_file(
|
|
|
68
68
|
|
|
69
69
|
renderer = SphinxRenderer()
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
template_content = fsrc.read()
|
|
71
|
+
template_content = source.read_text(encoding='utf-8')
|
|
73
72
|
rendered_template = renderer.render_string(template_content, context)
|
|
74
73
|
|
|
75
74
|
if not force and destination.exists() and template_content != rendered_template:
|
|
@@ -87,15 +86,14 @@ def copy_asset_file(
|
|
|
87
86
|
return
|
|
88
87
|
|
|
89
88
|
destination = _template_basename(destination) or destination
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
fdst.write(rendered_template)
|
|
89
|
+
msg = __('Writing evaluated template result to %s')
|
|
90
|
+
logger.info(
|
|
91
|
+
msg,
|
|
92
|
+
os.fsdecode(destination),
|
|
93
|
+
type='misc',
|
|
94
|
+
subtype='template_evaluation',
|
|
95
|
+
)
|
|
96
|
+
destination.write_text(rendered_template, encoding='utf-8')
|
|
99
97
|
else:
|
|
100
98
|
copyfile(source, destination, force=force)
|
|
101
99
|
|
|
@@ -125,7 +123,8 @@ def copy_asset(
|
|
|
125
123
|
:param onerror: The error handler.
|
|
126
124
|
:param bool force: Overwrite the destination file even if it exists.
|
|
127
125
|
"""
|
|
128
|
-
|
|
126
|
+
source = Path(source)
|
|
127
|
+
if not source.exists():
|
|
129
128
|
return
|
|
130
129
|
|
|
131
130
|
if renderer is None:
|
|
@@ -134,14 +133,14 @@ def copy_asset(
|
|
|
134
133
|
renderer = SphinxRenderer()
|
|
135
134
|
|
|
136
135
|
ensuredir(destination)
|
|
137
|
-
if
|
|
136
|
+
if source.is_file():
|
|
138
137
|
copy_asset_file(
|
|
139
138
|
source, destination, context=context, renderer=renderer, force=force
|
|
140
139
|
)
|
|
141
140
|
return
|
|
142
141
|
|
|
143
142
|
for root, dirs, files in os.walk(source, followlinks=True):
|
|
144
|
-
reldir =
|
|
143
|
+
reldir = _relative_path(Path(root), source).as_posix()
|
|
145
144
|
for dir in dirs.copy():
|
|
146
145
|
if excluded(posixpath.join(reldir, dir)):
|
|
147
146
|
dirs.remove(dir)
|