Sphinx 7.1.1__py3-none-any.whl → 7.2.0__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 +6 -6
- sphinx/__main__.py +3 -1
- sphinx/addnodes.py +35 -22
- sphinx/application.py +40 -38
- sphinx/builders/__init__.py +16 -12
- sphinx/builders/_epub_base.py +15 -11
- sphinx/builders/changes.py +6 -4
- sphinx/builders/dirhtml.py +4 -2
- sphinx/builders/dummy.py +6 -4
- sphinx/builders/epub3.py +16 -8
- sphinx/builders/gettext.py +40 -43
- sphinx/builders/html/__init__.py +166 -196
- sphinx/builders/html/_assets.py +116 -0
- sphinx/builders/html/transforms.py +4 -2
- sphinx/builders/latex/__init__.py +12 -7
- sphinx/builders/latex/theming.py +5 -2
- sphinx/builders/latex/transforms.py +6 -3
- sphinx/builders/linkcheck.py +21 -13
- sphinx/builders/manpage.py +6 -4
- sphinx/builders/singlehtml.py +16 -9
- sphinx/builders/texinfo.py +11 -6
- sphinx/builders/text.py +8 -3
- sphinx/builders/xml.py +9 -4
- sphinx/cmd/build.py +27 -14
- sphinx/cmd/make_mode.py +13 -4
- sphinx/cmd/quickstart.py +13 -4
- sphinx/config.py +17 -14
- sphinx/deprecation.py +4 -2
- sphinx/directives/__init__.py +44 -12
- sphinx/directives/code.py +5 -4
- sphinx/directives/other.py +92 -44
- sphinx/directives/patches.py +1 -1
- sphinx/domains/__init__.py +11 -8
- sphinx/domains/c.py +67 -57
- sphinx/domains/changeset.py +3 -2
- sphinx/domains/citation.py +2 -1
- sphinx/domains/cpp.py +136 -93
- sphinx/domains/index.py +9 -5
- sphinx/domains/javascript.py +32 -19
- sphinx/domains/math.py +5 -3
- sphinx/domains/python.py +69 -57
- sphinx/domains/rst.py +20 -11
- sphinx/domains/std.py +21 -15
- sphinx/environment/__init__.py +97 -65
- sphinx/environment/adapters/indexentries.py +13 -10
- sphinx/environment/adapters/toctree.py +485 -308
- sphinx/environment/collectors/__init__.py +3 -4
- sphinx/environment/collectors/asset.py +10 -4
- sphinx/environment/collectors/dependencies.py +7 -4
- sphinx/environment/collectors/metadata.py +7 -5
- sphinx/environment/collectors/title.py +5 -3
- sphinx/environment/collectors/toctree.py +13 -8
- sphinx/errors.py +1 -1
- sphinx/events.py +5 -5
- sphinx/ext/apidoc.py +49 -27
- sphinx/ext/autodoc/__init__.py +179 -161
- sphinx/ext/autodoc/directive.py +10 -6
- sphinx/ext/autodoc/importer.py +22 -13
- sphinx/ext/autodoc/mock.py +4 -1
- sphinx/ext/autodoc/preserve_defaults.py +80 -12
- sphinx/ext/autodoc/type_comment.py +14 -10
- sphinx/ext/autodoc/typehints.py +7 -3
- sphinx/ext/autosectionlabel.py +6 -3
- sphinx/ext/autosummary/__init__.py +21 -15
- sphinx/ext/autosummary/generate.py +176 -126
- sphinx/ext/coverage.py +93 -8
- sphinx/ext/doctest.py +28 -17
- sphinx/ext/duration.py +19 -17
- sphinx/ext/extlinks.py +11 -6
- sphinx/ext/githubpages.py +8 -7
- sphinx/ext/graphviz.py +61 -17
- sphinx/ext/ifconfig.py +7 -4
- sphinx/ext/imgconverter.py +4 -2
- sphinx/ext/imgmath.py +29 -23
- sphinx/ext/inheritance_diagram.py +41 -27
- sphinx/ext/intersphinx.py +45 -38
- sphinx/ext/linkcode.py +8 -5
- sphinx/ext/mathjax.py +13 -9
- sphinx/ext/napoleon/__init__.py +3 -3
- sphinx/ext/napoleon/docstring.py +40 -31
- sphinx/ext/todo.py +10 -7
- sphinx/ext/viewcode.py +46 -25
- sphinx/extension.py +1 -1
- sphinx/highlighting.py +20 -12
- sphinx/io.py +5 -4
- sphinx/jinja2glue.py +24 -19
- sphinx/locale/__init__.py +8 -2
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +756 -740
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +758 -742
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +762 -746
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +766 -750
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/gl/LC_MESSAGES/sphinx.js +60 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +3695 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +765 -749
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +762 -745
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +759 -743
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +760 -744
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +765 -749
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/sphinx.pot +748 -740
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr@latin/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr_RS/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +755 -739
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +763 -747
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +760 -749
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +759 -748
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +768 -752
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +754 -738
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +767 -751
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +754 -738
- sphinx/parsers.py +5 -4
- sphinx/project.py +52 -34
- sphinx/pycode/__init__.py +2 -1
- sphinx/pycode/ast.py +7 -13
- sphinx/pycode/parser.py +42 -38
- sphinx/registry.py +35 -29
- sphinx/roles.py +9 -4
- sphinx/search/__init__.py +5 -17
- sphinx/search/da.py +1 -1
- sphinx/search/de.py +1 -1
- sphinx/search/en.py +1 -1
- sphinx/search/es.py +1 -1
- sphinx/search/fi.py +1 -1
- sphinx/search/fr.py +1 -1
- sphinx/search/hu.py +1 -1
- sphinx/search/it.py +1 -1
- sphinx/search/ja.py +1 -1
- sphinx/search/nl.py +1 -1
- sphinx/search/no.py +1 -1
- sphinx/search/pt.py +1 -1
- sphinx/search/ro.py +1 -1
- sphinx/search/ru.py +1 -1
- sphinx/search/sv.py +1 -1
- sphinx/search/tr.py +1 -1
- sphinx/search/zh.py +1 -1
- sphinx/testing/fixtures.py +23 -30
- sphinx/testing/path.py +9 -0
- sphinx/testing/restructuredtext.py +13 -5
- sphinx/testing/util.py +20 -63
- sphinx/texinputs/sphinxlatexobjects.sty +15 -15
- sphinx/themes/agogo/static/agogo.css_t +10 -4
- sphinx/themes/basic/layout.html +1 -1
- sphinx/themes/basic/static/basic.css_t +4 -0
- sphinx/themes/basic/static/documentation_options.js_t +1 -2
- sphinx/themes/basic/static/searchtools.js +17 -9
- sphinx/themes/basic/static/sphinx_highlight.js +13 -3
- sphinx/themes/bizstyle/static/bizstyle.css_t +4 -0
- sphinx/themes/classic/theme.conf +1 -1
- sphinx/themes/epub/static/epub.css_t +6 -1
- sphinx/themes/haiku/theme.conf +1 -1
- sphinx/themes/nature/static/nature.css_t +4 -0
- sphinx/themes/nonav/static/nonav.css_t +6 -1
- sphinx/themes/pyramid/static/pyramid.css_t +4 -0
- sphinx/themes/scrolls/static/scrolls.css_t +4 -0
- sphinx/themes/scrolls/theme.conf +1 -1
- sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +4 -0
- sphinx/theming.py +9 -7
- sphinx/transforms/__init__.py +79 -3
- sphinx/transforms/compact_bullet_list.py +6 -3
- sphinx/transforms/i18n.py +26 -10
- sphinx/transforms/post_transforms/__init__.py +21 -8
- sphinx/transforms/post_transforms/code.py +6 -3
- sphinx/transforms/post_transforms/images.py +13 -9
- sphinx/util/__init__.py +21 -92
- sphinx/util/cfamily.py +7 -4
- sphinx/util/display.py +3 -2
- sphinx/util/docfields.py +7 -6
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +41 -31
- sphinx/util/fileutil.py +9 -6
- sphinx/util/i18n.py +21 -18
- sphinx/util/images.py +2 -1
- sphinx/util/index_entries.py +27 -0
- sphinx/util/inspect.py +83 -67
- sphinx/util/inventory.py +4 -2
- sphinx/util/logging.py +9 -6
- sphinx/util/matching.py +5 -2
- sphinx/util/math.py +6 -3
- sphinx/util/nodes.py +70 -31
- sphinx/util/osutil.py +22 -40
- sphinx/util/parallel.py +4 -1
- sphinx/util/rst.py +7 -3
- sphinx/util/tags.py +11 -4
- sphinx/util/template.py +17 -14
- sphinx/util/typing.py +61 -20
- sphinx/versioning.py +6 -4
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +32 -24
- sphinx/writers/latex.py +67 -53
- sphinx/writers/manpage.py +9 -5
- sphinx/writers/texinfo.py +11 -9
- sphinx/writers/text.py +14 -9
- sphinx/writers/xml.py +3 -2
- {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/METADATA +7 -5
- sphinx-7.2.0.dist-info/RECORD +568 -0
- sphinx/testing/comparer.py +0 -97
- sphinx-7.1.1.dist-info/RECORD +0 -564
- {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/LICENSE +0 -0
- {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/WHEEL +0 -0
- {sphinx-7.1.1.dist-info → sphinx-7.2.0.dist-info}/entry_points.txt +0 -0
sphinx/util/nodes.py
CHANGED
|
@@ -5,19 +5,22 @@ from __future__ import annotations
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import re
|
|
7
7
|
import unicodedata
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
9
9
|
|
|
10
10
|
from docutils import nodes
|
|
11
|
-
from docutils.nodes import Element, Node
|
|
12
|
-
from docutils.parsers.rst import Directive
|
|
13
|
-
from docutils.parsers.rst.states import Inliner
|
|
14
|
-
from docutils.statemachine import StringList
|
|
15
11
|
|
|
16
12
|
from sphinx import addnodes
|
|
17
13
|
from sphinx.locale import __
|
|
18
14
|
from sphinx.util import logging
|
|
19
15
|
|
|
20
16
|
if TYPE_CHECKING:
|
|
17
|
+
from collections.abc import Iterable
|
|
18
|
+
|
|
19
|
+
from docutils.nodes import Element, Node
|
|
20
|
+
from docutils.parsers.rst import Directive
|
|
21
|
+
from docutils.parsers.rst.states import Inliner
|
|
22
|
+
from docutils.statemachine import StringList
|
|
23
|
+
|
|
21
24
|
from sphinx.builders import Builder
|
|
22
25
|
from sphinx.environment import BuildEnvironment
|
|
23
26
|
from sphinx.util.tags import Tags
|
|
@@ -47,7 +50,7 @@ class NodeMatcher:
|
|
|
47
50
|
following example searches ``reference`` node having ``refdomain`` attributes::
|
|
48
51
|
|
|
49
52
|
from __future__ import annotations
|
|
50
|
-
from typing import Any
|
|
53
|
+
from typing import TYPE_CHECKING, Any
|
|
51
54
|
matcher = NodeMatcher(nodes.reference, refdomain=Any)
|
|
52
55
|
doctree.findall(matcher)
|
|
53
56
|
# => [<reference ...>, <reference ...>, ...]
|
|
@@ -196,7 +199,7 @@ def is_translatable(node: Node) -> bool:
|
|
|
196
199
|
if isinstance(node, nodes.image) and (node.get('translatable') or node.get('alt')):
|
|
197
200
|
return True
|
|
198
201
|
|
|
199
|
-
if isinstance(node, nodes.Inline) and 'translatable' not in node: # type: ignore
|
|
202
|
+
if isinstance(node, nodes.Inline) and 'translatable' not in node: # type: ignore[operator]
|
|
200
203
|
# inline node must not be translated if 'translatable' is not set
|
|
201
204
|
return False
|
|
202
205
|
|
|
@@ -223,7 +226,7 @@ def is_translatable(node: Node) -> bool:
|
|
|
223
226
|
return False
|
|
224
227
|
return True
|
|
225
228
|
|
|
226
|
-
if isinstance(node, nodes.meta): # type: ignore
|
|
229
|
+
if isinstance(node, nodes.meta): # type: ignore[attr-defined]
|
|
227
230
|
return True
|
|
228
231
|
|
|
229
232
|
return False
|
|
@@ -255,10 +258,11 @@ def extract_messages(doctree: Element) -> Iterable[tuple[Element, str]]:
|
|
|
255
258
|
if node.get('alt'):
|
|
256
259
|
yield node, node['alt']
|
|
257
260
|
if node.get('translatable'):
|
|
258
|
-
|
|
261
|
+
image_uri = node.get('original_uri', node['uri'])
|
|
262
|
+
msg = f'.. image:: {image_uri}'
|
|
259
263
|
else:
|
|
260
264
|
msg = ''
|
|
261
|
-
elif isinstance(node, nodes.meta): # type: ignore
|
|
265
|
+
elif isinstance(node, nodes.meta): # type: ignore[attr-defined]
|
|
262
266
|
msg = node["content"]
|
|
263
267
|
else:
|
|
264
268
|
msg = node.rawsource.replace('\n', ' ').strip()
|
|
@@ -272,14 +276,16 @@ def get_node_source(node: Element) -> str:
|
|
|
272
276
|
for pnode in traverse_parent(node):
|
|
273
277
|
if pnode.source:
|
|
274
278
|
return pnode.source
|
|
275
|
-
|
|
279
|
+
msg = 'node source not found'
|
|
280
|
+
raise ValueError(msg)
|
|
276
281
|
|
|
277
282
|
|
|
278
283
|
def get_node_line(node: Element) -> int:
|
|
279
284
|
for pnode in traverse_parent(node):
|
|
280
285
|
if pnode.line:
|
|
281
286
|
return pnode.line
|
|
282
|
-
|
|
287
|
+
msg = 'node line not found'
|
|
288
|
+
raise ValueError(msg)
|
|
283
289
|
|
|
284
290
|
|
|
285
291
|
def traverse_parent(node: Element, cls: Any = None) -> Iterable[Element]:
|
|
@@ -564,7 +570,8 @@ def set_source_info(directive: Directive, node: Node) -> None:
|
|
|
564
570
|
|
|
565
571
|
|
|
566
572
|
def set_role_source_info(inliner: Inliner, lineno: int, node: Node) -> None:
|
|
567
|
-
|
|
573
|
+
gsal = inliner.reporter.get_source_and_line # type: ignore[attr-defined]
|
|
574
|
+
node.source, node.line = gsal(lineno)
|
|
568
575
|
|
|
569
576
|
|
|
570
577
|
def copy_source_info(src: Element, dst: Element) -> None:
|
|
@@ -601,33 +608,65 @@ def is_smartquotable(node: Node) -> bool:
|
|
|
601
608
|
def process_only_nodes(document: Node, tags: Tags) -> None:
|
|
602
609
|
"""Filter ``only`` nodes which do not match *tags*."""
|
|
603
610
|
for node in document.findall(addnodes.only):
|
|
604
|
-
|
|
605
|
-
ret = tags.eval_condition(node['expr'])
|
|
606
|
-
except Exception as err:
|
|
607
|
-
logger.warning(__('exception while evaluating only directive expression: %s'), err,
|
|
608
|
-
location=node)
|
|
611
|
+
if _only_node_keep_children(node, tags):
|
|
609
612
|
node.replace_self(node.children or nodes.comment())
|
|
610
613
|
else:
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
# the only node, so we make sure docutils can transfer the id to
|
|
617
|
-
# something, even if it's just a comment and will lose the id anyway...
|
|
618
|
-
node.replace_self(nodes.comment())
|
|
614
|
+
# A comment on the comment() nodes being inserted: replacing by [] would
|
|
615
|
+
# result in a "Losing ids" exception if there is a target node before
|
|
616
|
+
# the only node, so we make sure docutils can transfer the id to
|
|
617
|
+
# something, even if it's just a comment and will lose the id anyway...
|
|
618
|
+
node.replace_self(nodes.comment())
|
|
619
619
|
|
|
620
620
|
|
|
621
|
-
def
|
|
621
|
+
def _only_node_keep_children(node: addnodes.only, tags: Tags) -> bool:
|
|
622
|
+
"""Keep children if tags match or error."""
|
|
623
|
+
try:
|
|
624
|
+
return tags.eval_condition(node['expr'])
|
|
625
|
+
except Exception as err:
|
|
626
|
+
logger.warning(
|
|
627
|
+
__('exception while evaluating only directive expression: %s'),
|
|
628
|
+
err,
|
|
629
|
+
location=node)
|
|
630
|
+
return True
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
def _copy_except__document(el: Element) -> Element:
|
|
622
634
|
"""Monkey-patch ```nodes.Element.copy``` to not copy the ``_document``
|
|
623
635
|
attribute.
|
|
624
636
|
|
|
625
637
|
xref: https://github.com/sphinx-doc/sphinx/issues/11116#issuecomment-1376767086
|
|
626
638
|
"""
|
|
627
|
-
newnode =
|
|
628
|
-
|
|
629
|
-
newnode.
|
|
639
|
+
newnode = object.__new__(el.__class__)
|
|
640
|
+
# set in Element.__init__()
|
|
641
|
+
newnode.children = []
|
|
642
|
+
newnode.rawsource = el.rawsource
|
|
643
|
+
newnode.tagname = el.tagname
|
|
644
|
+
# copied in Element.copy()
|
|
645
|
+
newnode.attributes = {k: (v
|
|
646
|
+
if k not in {'ids', 'classes', 'names', 'dupnames', 'backrefs'}
|
|
647
|
+
else v[:])
|
|
648
|
+
for k, v in el.attributes.items()}
|
|
649
|
+
newnode.line = el.line
|
|
650
|
+
newnode.source = el.source
|
|
651
|
+
return newnode
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
nodes.Element.copy = _copy_except__document # type: ignore[assignment]
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
def _deepcopy(el: Element) -> Element:
|
|
658
|
+
"""Monkey-patch ```nodes.Element.deepcopy``` for speed."""
|
|
659
|
+
newnode = el.copy()
|
|
660
|
+
newnode.children = [child.deepcopy() for child in el.children]
|
|
661
|
+
for child in newnode.children:
|
|
662
|
+
child.parent = newnode
|
|
663
|
+
if el.document:
|
|
664
|
+
child.document = el.document
|
|
665
|
+
if child.source is None:
|
|
666
|
+
child.source = el.document.current_source
|
|
667
|
+
if child.line is None:
|
|
668
|
+
child.line = el.document.current_line
|
|
630
669
|
return newnode
|
|
631
670
|
|
|
632
671
|
|
|
633
|
-
nodes.Element.
|
|
672
|
+
nodes.Element.deepcopy = _deepcopy # type: ignore[assignment]
|
sphinx/util/osutil.py
CHANGED
|
@@ -11,16 +11,12 @@ import sys
|
|
|
11
11
|
import unicodedata
|
|
12
12
|
from io import StringIO
|
|
13
13
|
from os import path
|
|
14
|
-
from typing import
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
15
15
|
|
|
16
16
|
from sphinx.deprecation import _deprecation_warning
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from sphinx.testing.path import path as Path
|
|
21
|
-
except ImportError:
|
|
22
|
-
Path = None # type: ignore
|
|
23
|
-
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from collections.abc import Iterator
|
|
24
20
|
|
|
25
21
|
# SEP separates path elements in the canonical file names
|
|
26
22
|
#
|
|
@@ -30,16 +26,16 @@ except ImportError:
|
|
|
30
26
|
SEP = "/"
|
|
31
27
|
|
|
32
28
|
|
|
33
|
-
def os_path(
|
|
34
|
-
return
|
|
29
|
+
def os_path(canonical_path: str, /) -> str:
|
|
30
|
+
return canonical_path.replace(SEP, path.sep)
|
|
35
31
|
|
|
36
32
|
|
|
37
|
-
def canon_path(
|
|
33
|
+
def canon_path(native_path: str | os.PathLike[str], /) -> str:
|
|
38
34
|
"""Return path in OS-independent form"""
|
|
39
|
-
return
|
|
35
|
+
return os.fspath(native_path).replace(path.sep, SEP)
|
|
40
36
|
|
|
41
37
|
|
|
42
|
-
def path_stabilize(filepath: str) -> str:
|
|
38
|
+
def path_stabilize(filepath: str | os.PathLike[str], /) -> str:
|
|
43
39
|
"Normalize path separator and unicode string"
|
|
44
40
|
new_path = canon_path(filepath)
|
|
45
41
|
return unicodedata.normalize('NFC', new_path)
|
|
@@ -68,9 +64,9 @@ def relative_uri(base: str, to: str) -> str:
|
|
|
68
64
|
return ('..' + SEP) * (len(b2) - 1) + SEP.join(t2)
|
|
69
65
|
|
|
70
66
|
|
|
71
|
-
def ensuredir(
|
|
67
|
+
def ensuredir(file: str | os.PathLike[str]) -> None:
|
|
72
68
|
"""Ensure that a path exists."""
|
|
73
|
-
os.makedirs(
|
|
69
|
+
os.makedirs(file, exist_ok=True)
|
|
74
70
|
|
|
75
71
|
|
|
76
72
|
def mtimes_of_files(dirnames: list[str], suffix: str) -> Iterator[float]:
|
|
@@ -78,30 +74,26 @@ def mtimes_of_files(dirnames: list[str], suffix: str) -> Iterator[float]:
|
|
|
78
74
|
for root, _dirs, files in os.walk(dirname):
|
|
79
75
|
for sfile in files:
|
|
80
76
|
if sfile.endswith(suffix):
|
|
81
|
-
|
|
77
|
+
with contextlib.suppress(OSError):
|
|
82
78
|
yield path.getmtime(path.join(root, sfile))
|
|
83
|
-
except OSError:
|
|
84
|
-
pass
|
|
85
79
|
|
|
86
80
|
|
|
87
|
-
def copytimes(source: str, dest: str) -> None:
|
|
81
|
+
def copytimes(source: str | os.PathLike[str], dest: str | os.PathLike[str]) -> None:
|
|
88
82
|
"""Copy a file's modification times."""
|
|
89
83
|
st = os.stat(source)
|
|
90
84
|
if hasattr(os, 'utime'):
|
|
91
85
|
os.utime(dest, (st.st_atime, st.st_mtime))
|
|
92
86
|
|
|
93
87
|
|
|
94
|
-
def copyfile(source: str, dest: str) -> None:
|
|
88
|
+
def copyfile(source: str | os.PathLike[str], dest: str | os.PathLike[str]) -> None:
|
|
95
89
|
"""Copy a file and its modification times, if possible.
|
|
96
90
|
|
|
97
91
|
Note: ``copyfile`` skips copying if the file has not been changed"""
|
|
98
92
|
if not path.exists(dest) or not filecmp.cmp(source, dest):
|
|
99
93
|
shutil.copyfile(source, dest)
|
|
100
|
-
|
|
94
|
+
with contextlib.suppress(OSError):
|
|
101
95
|
# don't do full copystat because the source may be read-only
|
|
102
96
|
copytimes(source, dest)
|
|
103
|
-
except OSError:
|
|
104
|
-
pass
|
|
105
97
|
|
|
106
98
|
|
|
107
99
|
no_fn_re = re.compile(r'[^a-zA-Z0-9_-]')
|
|
@@ -116,7 +108,8 @@ def make_filename_from_project(project: str) -> str:
|
|
|
116
108
|
return make_filename(project_suffix_re.sub('', project)).lower()
|
|
117
109
|
|
|
118
110
|
|
|
119
|
-
def relpath(path: str
|
|
111
|
+
def relpath(path: str | os.PathLike[str],
|
|
112
|
+
start: str | os.PathLike[str] | None = os.curdir) -> str:
|
|
120
113
|
"""Return a relative filepath to *path* either from the current directory or
|
|
121
114
|
from an optional *start* directory.
|
|
122
115
|
|
|
@@ -126,26 +119,14 @@ def relpath(path: str, start: str | None = os.curdir) -> str:
|
|
|
126
119
|
try:
|
|
127
120
|
return os.path.relpath(path, start)
|
|
128
121
|
except ValueError:
|
|
129
|
-
return path
|
|
122
|
+
return str(path)
|
|
130
123
|
|
|
131
124
|
|
|
132
125
|
safe_relpath = relpath # for compatibility
|
|
133
126
|
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
|
134
127
|
|
|
135
128
|
|
|
136
|
-
|
|
137
|
-
if Path is not None and isinstance(pathdir, Path):
|
|
138
|
-
return pathdir.abspath()
|
|
139
|
-
else:
|
|
140
|
-
pathdir = path.abspath(pathdir)
|
|
141
|
-
if isinstance(pathdir, bytes):
|
|
142
|
-
try:
|
|
143
|
-
pathdir = pathdir.decode(fs_encoding)
|
|
144
|
-
except UnicodeDecodeError as exc:
|
|
145
|
-
raise UnicodeDecodeError('multibyte filename not supported on '
|
|
146
|
-
'this filesystem encoding '
|
|
147
|
-
'(%r)' % fs_encoding) from exc
|
|
148
|
-
return pathdir
|
|
129
|
+
abspath = path.abspath
|
|
149
130
|
|
|
150
131
|
|
|
151
132
|
class _chdir:
|
|
@@ -194,7 +175,8 @@ class FileAvoidWrite:
|
|
|
194
175
|
def close(self) -> None:
|
|
195
176
|
"""Stop accepting writes and write file, if needed."""
|
|
196
177
|
if not self._io:
|
|
197
|
-
|
|
178
|
+
msg = 'FileAvoidWrite does not support empty files.'
|
|
179
|
+
raise Exception(msg)
|
|
198
180
|
|
|
199
181
|
buf = self.getvalue()
|
|
200
182
|
self._io.close()
|
|
@@ -222,8 +204,8 @@ class FileAvoidWrite:
|
|
|
222
204
|
def __getattr__(self, name: str) -> Any:
|
|
223
205
|
# Proxy to _io instance.
|
|
224
206
|
if not self._io:
|
|
225
|
-
|
|
226
|
-
|
|
207
|
+
msg = 'Must write to FileAvoidWrite before other methods can be used'
|
|
208
|
+
raise Exception(msg)
|
|
227
209
|
|
|
228
210
|
return getattr(self._io, name)
|
|
229
211
|
|
sphinx/util/parallel.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
import time
|
|
7
7
|
import traceback
|
|
8
8
|
from math import sqrt
|
|
9
|
-
from typing import Any, Callable
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
12
|
import multiprocessing
|
|
@@ -17,6 +17,9 @@ except ImportError:
|
|
|
17
17
|
from sphinx.errors import SphinxParallelError
|
|
18
18
|
from sphinx.util import logging
|
|
19
19
|
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Sequence
|
|
22
|
+
|
|
20
23
|
logger = logging.getLogger(__name__)
|
|
21
24
|
|
|
22
25
|
# our parallel functionality only works for the forking Process
|
sphinx/util/rst.py
CHANGED
|
@@ -5,19 +5,23 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from contextlib import contextmanager
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
9
|
from unicodedata import east_asian_width
|
|
10
10
|
|
|
11
11
|
from docutils.parsers.rst import roles
|
|
12
12
|
from docutils.parsers.rst.languages import en as english
|
|
13
13
|
from docutils.parsers.rst.states import Body
|
|
14
|
-
from docutils.statemachine import StringList
|
|
15
14
|
from docutils.utils import Reporter
|
|
16
15
|
from jinja2 import Environment, pass_environment
|
|
17
16
|
|
|
18
17
|
from sphinx.locale import __
|
|
19
18
|
from sphinx.util import docutils, logging
|
|
20
19
|
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from collections.abc import Generator
|
|
22
|
+
|
|
23
|
+
from docutils.statemachine import StringList
|
|
24
|
+
|
|
21
25
|
logger = logging.getLogger(__name__)
|
|
22
26
|
|
|
23
27
|
FIELD_NAME_RE = re.compile(Body.patterns['field_marker'])
|
|
@@ -61,7 +65,7 @@ def default_role(docname: str, name: str) -> Generator[None, None, None]:
|
|
|
61
65
|
dummy_reporter = Reporter('', 4, 4)
|
|
62
66
|
role_fn, _ = roles.role(name, english, 0, dummy_reporter)
|
|
63
67
|
if role_fn: # type: ignore[truthy-function]
|
|
64
|
-
docutils.register_role('', role_fn)
|
|
68
|
+
docutils.register_role('', role_fn) # type: ignore[arg-type]
|
|
65
69
|
else:
|
|
66
70
|
logger.warning(__('default role %s not found'), name, location=docname)
|
|
67
71
|
|
sphinx/util/tags.py
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from jinja2 import nodes
|
|
6
6
|
from jinja2.environment import Environment
|
|
7
|
-
from jinja2.nodes import Node
|
|
8
7
|
from jinja2.parser import Parser
|
|
9
8
|
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Iterator
|
|
11
|
+
|
|
12
|
+
from jinja2.nodes import Node
|
|
13
|
+
|
|
14
|
+
|
|
10
15
|
env = Environment()
|
|
11
16
|
|
|
12
17
|
|
|
@@ -59,7 +64,8 @@ class Tags:
|
|
|
59
64
|
parser = BooleanParser(env, condition, state='variable')
|
|
60
65
|
expr = parser.parse_expression()
|
|
61
66
|
if not parser.stream.eos:
|
|
62
|
-
|
|
67
|
+
msg = 'chunk after expression'
|
|
68
|
+
raise ValueError(msg)
|
|
63
69
|
|
|
64
70
|
def eval_node(node: Node) -> bool:
|
|
65
71
|
if isinstance(node, nodes.CondExpr):
|
|
@@ -76,6 +82,7 @@ class Tags:
|
|
|
76
82
|
elif isinstance(node, nodes.Name):
|
|
77
83
|
return self.tags.get(node.name, False)
|
|
78
84
|
else:
|
|
79
|
-
|
|
85
|
+
msg = 'invalid node, check parsing'
|
|
86
|
+
raise ValueError(msg)
|
|
80
87
|
|
|
81
88
|
return eval_node(expr)
|
sphinx/util/template.py
CHANGED
|
@@ -5,10 +5,9 @@ from __future__ import annotations
|
|
|
5
5
|
import os
|
|
6
6
|
from functools import partial
|
|
7
7
|
from os import path
|
|
8
|
-
from typing import Any, Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
9
9
|
|
|
10
10
|
from jinja2 import TemplateNotFound
|
|
11
|
-
from jinja2.environment import Environment
|
|
12
11
|
from jinja2.loaders import BaseLoader
|
|
13
12
|
from jinja2.sandbox import SandboxedEnvironment
|
|
14
13
|
|
|
@@ -17,6 +16,11 @@ from sphinx.jinja2glue import SphinxFileSystemLoader
|
|
|
17
16
|
from sphinx.locale import get_translator
|
|
18
17
|
from sphinx.util import rst, texescape
|
|
19
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
|
|
22
|
+
from jinja2.environment import Environment
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
class BaseRenderer:
|
|
22
26
|
def __init__(self, loader: BaseLoader | None = None) -> None:
|
|
@@ -32,8 +36,8 @@ class BaseRenderer:
|
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
class FileRenderer(BaseRenderer):
|
|
35
|
-
def __init__(self, search_path: str |
|
|
36
|
-
if isinstance(search_path, str):
|
|
39
|
+
def __init__(self, search_path: Sequence[str | os.PathLike[str]]) -> None:
|
|
40
|
+
if isinstance(search_path, (str, os.PathLike)):
|
|
37
41
|
search_path = [search_path]
|
|
38
42
|
else:
|
|
39
43
|
# filter "None" paths
|
|
@@ -50,7 +54,7 @@ class FileRenderer(BaseRenderer):
|
|
|
50
54
|
|
|
51
55
|
|
|
52
56
|
class SphinxRenderer(FileRenderer):
|
|
53
|
-
def __init__(self, template_path:
|
|
57
|
+
def __init__(self, template_path: Sequence[str | os.PathLike[str]] | None = None) -> None:
|
|
54
58
|
if template_path is None:
|
|
55
59
|
template_path = os.path.join(package_dir, 'templates')
|
|
56
60
|
super().__init__(template_path)
|
|
@@ -61,11 +65,10 @@ class SphinxRenderer(FileRenderer):
|
|
|
61
65
|
|
|
62
66
|
|
|
63
67
|
class LaTeXRenderer(SphinxRenderer):
|
|
64
|
-
def __init__(
|
|
65
|
-
|
|
66
|
-
) -> None:
|
|
68
|
+
def __init__(self, template_path: Sequence[str | os.PathLike[str]] | None = None,
|
|
69
|
+
latex_engine: str | None = None) -> None:
|
|
67
70
|
if template_path is None:
|
|
68
|
-
template_path = os.path.join(package_dir, 'templates', 'latex')
|
|
71
|
+
template_path = [os.path.join(package_dir, 'templates', 'latex')]
|
|
69
72
|
super().__init__(template_path)
|
|
70
73
|
|
|
71
74
|
# use texescape as escape filter
|
|
@@ -85,9 +88,8 @@ class LaTeXRenderer(SphinxRenderer):
|
|
|
85
88
|
|
|
86
89
|
|
|
87
90
|
class ReSTRenderer(SphinxRenderer):
|
|
88
|
-
def __init__(
|
|
89
|
-
|
|
90
|
-
) -> None:
|
|
91
|
+
def __init__(self, template_path: Sequence[str | os.PathLike[str]] | None = None,
|
|
92
|
+
language: str | None = None) -> None:
|
|
91
93
|
super().__init__(template_path)
|
|
92
94
|
|
|
93
95
|
# add language to environment
|
|
@@ -102,8 +104,9 @@ class ReSTRenderer(SphinxRenderer):
|
|
|
102
104
|
class SphinxTemplateLoader(BaseLoader):
|
|
103
105
|
"""A loader supporting template inheritance"""
|
|
104
106
|
|
|
105
|
-
def __init__(self, confdir: str
|
|
106
|
-
|
|
107
|
+
def __init__(self, confdir: str | os.PathLike[str],
|
|
108
|
+
templates_paths: Sequence[str | os.PathLike[str]],
|
|
109
|
+
system_templates_paths: Sequence[str | os.PathLike[str]]) -> None:
|
|
107
110
|
self.loaders = []
|
|
108
111
|
self.sysloaders = []
|
|
109
112
|
|