Sphinx 8.1.3__py3-none-any.whl → 8.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 +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 +50 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +134 -61
- sphinx/domains/python/_object.py +155 -68
- 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 +66 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +99 -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 +281 -142
- 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/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/sphinx.pot +2069 -1964
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
- 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 +63 -52
- sphinx/writers/latex.py +83 -67
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +47 -47
- sphinx/writers/text.py +50 -32
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
- sphinx-8.2.0.dist-info/RECORD +606 -0
- {sphinx-8.1.3.dist-info → sphinx-8.2.0.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/RECORD +0 -598
- {sphinx-8.1.3.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
sphinx/util/__init__.py
CHANGED
|
@@ -2,56 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import hashlib
|
|
6
5
|
import os
|
|
7
6
|
import posixpath
|
|
8
7
|
import re
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from sphinx.util._uri import encode_uri # NoQA: F401
|
|
17
|
-
from sphinx.util._uri import is_url as isurl # NoQA: F401
|
|
18
|
-
from sphinx.util.console import strip_colors # NoQA: F401
|
|
19
|
-
from sphinx.util.matching import patfilter # NoQA: F401
|
|
20
|
-
from sphinx.util.nodes import ( # NoQA: F401
|
|
21
|
-
caption_ref_re,
|
|
22
|
-
explicit_title_re,
|
|
23
|
-
nested_parse_with_titles,
|
|
24
|
-
split_explicit_title,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
# import other utilities; partly for backwards compatibility, so don't
|
|
28
|
-
# prune unused ones indiscriminately
|
|
29
|
-
from sphinx.util.osutil import ( # NoQA: F401
|
|
30
|
-
SEP,
|
|
31
|
-
copyfile,
|
|
32
|
-
ensuredir,
|
|
33
|
-
make_filename,
|
|
34
|
-
os_path,
|
|
35
|
-
relative_uri,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
TYPE_CHECKING = False
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
import hashlib
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from types import ModuleType
|
|
14
|
+
from typing import Any
|
|
39
15
|
|
|
40
16
|
# Generally useful regular expressions.
|
|
41
17
|
ws_re: re.Pattern[str] = re.compile(r'\s+')
|
|
42
18
|
url_re: re.Pattern[str] = re.compile(r'(?P<schema>.+)://.*')
|
|
43
19
|
|
|
44
|
-
|
|
45
20
|
# High-level utility functions.
|
|
46
21
|
|
|
47
22
|
|
|
48
23
|
def docname_join(basedocname: str, docname: str) -> str:
|
|
49
|
-
return posixpath.normpath(posixpath.join('/'
|
|
24
|
+
return posixpath.normpath(posixpath.join(f'/{basedocname}', '..', docname))[1:]
|
|
50
25
|
|
|
51
26
|
|
|
52
27
|
def get_filetype(
|
|
53
28
|
source_suffix: dict[str, str], filename: str | os.PathLike[str]
|
|
54
29
|
) -> str:
|
|
30
|
+
from sphinx.errors import FiletypeNotFoundError
|
|
31
|
+
|
|
55
32
|
for suffix, filetype in source_suffix.items():
|
|
56
33
|
if os.fspath(filename).endswith(suffix):
|
|
57
34
|
# If default filetype (None), considered as restructuredtext.
|
|
@@ -64,6 +41,8 @@ def _md5(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
|
|
|
64
41
|
|
|
65
42
|
To be removed in Sphinx 9.0
|
|
66
43
|
"""
|
|
44
|
+
import hashlib
|
|
45
|
+
|
|
67
46
|
return hashlib.md5(data, usedforsecurity=False)
|
|
68
47
|
|
|
69
48
|
|
|
@@ -72,37 +51,107 @@ def _sha1(data: bytes = b'', **_kw: Any) -> hashlib._Hash:
|
|
|
72
51
|
|
|
73
52
|
To be removed in Sphinx 9.0
|
|
74
53
|
"""
|
|
54
|
+
import hashlib
|
|
55
|
+
|
|
75
56
|
return hashlib.sha1(data, usedforsecurity=False)
|
|
76
57
|
|
|
77
58
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'split_index_msg': (
|
|
81
|
-
_index_entries.split_index_msg,
|
|
82
|
-
'sphinx.util.index_entries.split_index_msg',
|
|
83
|
-
(9, 0),
|
|
84
|
-
),
|
|
85
|
-
'split_into': (
|
|
86
|
-
_index_entries.split_index_msg,
|
|
87
|
-
'sphinx.util.index_entries.split_into',
|
|
88
|
-
(9, 0),
|
|
89
|
-
),
|
|
90
|
-
'ExtensionError': (_ExtensionError, 'sphinx.errors.ExtensionError', (9, 0)),
|
|
91
|
-
'md5': (_md5, '', (9, 0)),
|
|
92
|
-
'sha1': (_sha1, '', (9, 0)),
|
|
93
|
-
'import_object': (_importer.import_object, '', (10, 0)),
|
|
94
|
-
'FilenameUniqDict': (_files.FilenameUniqDict, '', (10, 0)),
|
|
95
|
-
'DownloadFiles': (_files.DownloadFiles, '', (10, 0)),
|
|
96
|
-
}
|
|
59
|
+
def __getattr__(name: str) -> Any:
|
|
60
|
+
from sphinx.deprecation import _deprecation_warning
|
|
97
61
|
|
|
62
|
+
obj: Callable[..., Any]
|
|
63
|
+
mod: ModuleType
|
|
98
64
|
|
|
99
|
-
|
|
100
|
-
if name
|
|
101
|
-
|
|
102
|
-
raise AttributeError(msg)
|
|
65
|
+
# RemovedInSphinx90Warning
|
|
66
|
+
if name == 'split_index_msg':
|
|
67
|
+
from sphinx.util.index_entries import split_index_msg as obj
|
|
103
68
|
|
|
104
|
-
|
|
69
|
+
canonical_name = f'{obj.__module__}.{obj.__qualname__}'
|
|
70
|
+
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
|
71
|
+
return obj
|
|
72
|
+
|
|
73
|
+
if name == 'split_into':
|
|
74
|
+
from sphinx.util.index_entries import _split_into as obj
|
|
75
|
+
|
|
76
|
+
_deprecation_warning(__name__, name, '', remove=(9, 0))
|
|
77
|
+
return obj
|
|
78
|
+
|
|
79
|
+
if name == 'ExtensionError':
|
|
80
|
+
from sphinx.errors import ExtensionError as obj # NoQA: N813
|
|
81
|
+
|
|
82
|
+
canonical_name = f'{obj.__module__}.{obj.__qualname__}'
|
|
83
|
+
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
|
84
|
+
return obj
|
|
85
|
+
|
|
86
|
+
if name in {'md5', 'sha1'}:
|
|
87
|
+
obj = globals()[f'_{name}']
|
|
88
|
+
canonical_name = f'hashlib.{name}'
|
|
89
|
+
_deprecation_warning(__name__, name, canonical_name, remove=(9, 0))
|
|
90
|
+
return obj
|
|
91
|
+
|
|
92
|
+
# RemovedInSphinx10Warning
|
|
93
|
+
|
|
94
|
+
if name in {'DownloadFiles', 'FilenameUniqDict'}:
|
|
95
|
+
from sphinx.util import _files as mod
|
|
96
|
+
|
|
97
|
+
obj = getattr(mod, name)
|
|
98
|
+
_deprecation_warning(__name__, name, '', remove=(10, 0))
|
|
99
|
+
return obj
|
|
100
|
+
|
|
101
|
+
# Re-exported for backwards compatibility,
|
|
102
|
+
# but not currently deprecated
|
|
103
|
+
|
|
104
|
+
if name == 'encode_uri':
|
|
105
|
+
from sphinx.util._uri import encode_uri
|
|
106
|
+
|
|
107
|
+
return encode_uri
|
|
108
|
+
|
|
109
|
+
if name == 'import_object':
|
|
110
|
+
from sphinx.util._importer import import_object
|
|
111
|
+
|
|
112
|
+
return import_object
|
|
113
|
+
|
|
114
|
+
if name == 'isurl':
|
|
115
|
+
from sphinx.util._uri import is_url
|
|
116
|
+
|
|
117
|
+
return is_url
|
|
118
|
+
|
|
119
|
+
if name == 'parselinenos':
|
|
120
|
+
from sphinx.util._lines import parse_line_num_spec
|
|
121
|
+
|
|
122
|
+
return parse_line_num_spec
|
|
123
|
+
|
|
124
|
+
if name == 'patfilter':
|
|
125
|
+
from sphinx.util.matching import patfilter
|
|
126
|
+
|
|
127
|
+
return patfilter
|
|
128
|
+
|
|
129
|
+
if name == 'strip_escape_sequences':
|
|
130
|
+
from sphinx._cli.util.errors import strip_escape_sequences
|
|
131
|
+
|
|
132
|
+
return strip_escape_sequences
|
|
133
|
+
|
|
134
|
+
if name in {
|
|
135
|
+
'caption_ref_re',
|
|
136
|
+
'explicit_title_re',
|
|
137
|
+
'nested_parse_with_titles',
|
|
138
|
+
'split_explicit_title',
|
|
139
|
+
}:
|
|
140
|
+
from sphinx.util import nodes as mod
|
|
141
|
+
|
|
142
|
+
return getattr(mod, name)
|
|
143
|
+
|
|
144
|
+
if name in {
|
|
145
|
+
'SEP',
|
|
146
|
+
'copyfile',
|
|
147
|
+
'ensuredir',
|
|
148
|
+
'make_filename',
|
|
149
|
+
'os_path',
|
|
150
|
+
'relative_uri',
|
|
151
|
+
}:
|
|
152
|
+
from sphinx.util import osutil as mod
|
|
153
|
+
|
|
154
|
+
return getattr(mod, name)
|
|
105
155
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return deprecated_object
|
|
156
|
+
msg = f'module {__name__!r} has no attribute {name!r}'
|
|
157
|
+
raise AttributeError(msg)
|
sphinx/util/_files.py
CHANGED
|
@@ -1,33 +1,44 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
|
-
import
|
|
5
|
-
from typing import
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from sphinx.util._pathlib import _StrPath
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
import os
|
|
11
|
+
from collections.abc import Set
|
|
6
12
|
|
|
7
13
|
|
|
8
14
|
class FilenameUniqDict(dict[str, tuple[set[str], str]]):
|
|
9
|
-
"""
|
|
10
|
-
A dictionary that automatically generates unique names for its keys,
|
|
15
|
+
"""A dictionary that automatically generates unique names for its keys,
|
|
11
16
|
interpreted as filenames, and keeps track of a set of docnames they
|
|
12
17
|
appear in. Used for images and downloadable files in the environment.
|
|
13
18
|
"""
|
|
14
19
|
|
|
15
20
|
def __init__(self) -> None:
|
|
21
|
+
super().__init__()
|
|
16
22
|
self._existing: set[str] = set()
|
|
17
23
|
|
|
18
|
-
def add_file(self, docname: str, newfile: str) -> str:
|
|
24
|
+
def add_file(self, docname: str, newfile: str | os.PathLike[str]) -> str:
|
|
25
|
+
newfile = str(newfile)
|
|
19
26
|
if newfile in self:
|
|
20
|
-
self[newfile]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
docnames, unique_name = self[newfile]
|
|
28
|
+
docnames.add(docname)
|
|
29
|
+
return unique_name
|
|
30
|
+
|
|
31
|
+
new_file = Path(newfile)
|
|
32
|
+
unique_name = new_file.name
|
|
33
|
+
base = new_file.stem
|
|
34
|
+
ext = new_file.suffix
|
|
24
35
|
i = 0
|
|
25
|
-
while
|
|
36
|
+
while unique_name in self._existing:
|
|
26
37
|
i += 1
|
|
27
|
-
|
|
28
|
-
self[newfile] = ({docname},
|
|
29
|
-
self._existing.add(
|
|
30
|
-
return
|
|
38
|
+
unique_name = f'{base}{i}{ext}'
|
|
39
|
+
self[newfile] = ({docname}, unique_name)
|
|
40
|
+
self._existing.add(unique_name)
|
|
41
|
+
return unique_name
|
|
31
42
|
|
|
32
43
|
def purge_doc(self, docname: str) -> None:
|
|
33
44
|
for filename, (docs, unique) in list(self.items()):
|
|
@@ -37,7 +48,7 @@ class FilenameUniqDict(dict[str, tuple[set[str], str]]):
|
|
|
37
48
|
self._existing.discard(unique)
|
|
38
49
|
|
|
39
50
|
def merge_other(
|
|
40
|
-
self, docnames:
|
|
51
|
+
self, docnames: Set[str], other: dict[str, tuple[set[str], str]]
|
|
41
52
|
) -> None:
|
|
42
53
|
for filename, (docs, _unique) in other.items():
|
|
43
54
|
for doc in docs & set(docnames):
|
|
@@ -50,21 +61,26 @@ class FilenameUniqDict(dict[str, tuple[set[str], str]]):
|
|
|
50
61
|
self._existing = state
|
|
51
62
|
|
|
52
63
|
|
|
53
|
-
class DownloadFiles(dict[
|
|
64
|
+
class DownloadFiles(dict[Path, tuple[set[str], _StrPath]]):
|
|
54
65
|
"""A special dictionary for download files.
|
|
55
66
|
|
|
56
67
|
.. important:: This class would be refactored in nearly future.
|
|
57
68
|
Hence don't hack this directly.
|
|
58
69
|
"""
|
|
59
70
|
|
|
60
|
-
def add_file(self, docname: str, filename: str) ->
|
|
71
|
+
def add_file(self, docname: str, filename: str | os.PathLike[str]) -> _StrPath:
|
|
72
|
+
filename = Path(filename)
|
|
61
73
|
if filename not in self:
|
|
62
|
-
digest = hashlib.md5(
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
digest = hashlib.md5(
|
|
75
|
+
filename.as_posix().encode(), usedforsecurity=False
|
|
76
|
+
).hexdigest()
|
|
77
|
+
dest_path = _StrPath(digest, filename.name)
|
|
78
|
+
self[filename] = ({docname}, dest_path)
|
|
79
|
+
return dest_path
|
|
65
80
|
|
|
66
|
-
self[filename]
|
|
67
|
-
|
|
81
|
+
docnames, dest_path = self[filename]
|
|
82
|
+
docnames.add(docname)
|
|
83
|
+
return dest_path
|
|
68
84
|
|
|
69
85
|
def purge_doc(self, docname: str) -> None:
|
|
70
86
|
for filename, (docs, _dest) in list(self.items()):
|
|
@@ -73,7 +89,7 @@ class DownloadFiles(dict[str, tuple[set[str], str]]):
|
|
|
73
89
|
del self[filename]
|
|
74
90
|
|
|
75
91
|
def merge_other(
|
|
76
|
-
self, docnames:
|
|
92
|
+
self, docnames: Set[str], other: dict[Path, tuple[set[str], _StrPath]]
|
|
77
93
|
) -> None:
|
|
78
94
|
for filename, (docs, _dest) in other.items():
|
|
79
95
|
for docname in docs & set(docnames):
|
sphinx/util/_importer.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from importlib import import_module
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from sphinx.errors import ExtensionError
|
|
7
7
|
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
8
11
|
|
|
9
12
|
def import_object(object_name: str, /, source: str = '') -> Any:
|
|
10
13
|
"""Import python object by qualname."""
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import zlib
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from sphinx.util import logging
|
|
7
|
+
|
|
8
|
+
BUFSIZE = 16 * 1024
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Iterator
|
|
13
|
+
from typing import Protocol
|
|
14
|
+
|
|
15
|
+
# Readable file stream for inventory loading
|
|
16
|
+
class _SupportsRead(Protocol):
|
|
17
|
+
def read(self, size: int = ...) -> bytes: ...
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = ('InventoryFileReader',)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class InventoryFileReader:
|
|
24
|
+
"""A file reader for an inventory file.
|
|
25
|
+
|
|
26
|
+
This reader supports mixture of texts and compressed texts.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, stream: _SupportsRead) -> None:
|
|
30
|
+
self.stream = stream
|
|
31
|
+
self.buffer = b''
|
|
32
|
+
self.eof = False
|
|
33
|
+
|
|
34
|
+
def read_buffer(self) -> None:
|
|
35
|
+
chunk = self.stream.read(BUFSIZE)
|
|
36
|
+
if chunk == b'':
|
|
37
|
+
self.eof = True
|
|
38
|
+
self.buffer += chunk
|
|
39
|
+
|
|
40
|
+
def readline(self) -> str:
|
|
41
|
+
pos = self.buffer.find(b'\n')
|
|
42
|
+
if pos != -1:
|
|
43
|
+
line = self.buffer[:pos].decode()
|
|
44
|
+
self.buffer = self.buffer[pos + 1 :]
|
|
45
|
+
elif self.eof:
|
|
46
|
+
line = self.buffer.decode()
|
|
47
|
+
self.buffer = b''
|
|
48
|
+
else:
|
|
49
|
+
self.read_buffer()
|
|
50
|
+
line = self.readline()
|
|
51
|
+
|
|
52
|
+
return line
|
|
53
|
+
|
|
54
|
+
def readlines(self) -> Iterator[str]:
|
|
55
|
+
while not self.eof:
|
|
56
|
+
line = self.readline()
|
|
57
|
+
if line:
|
|
58
|
+
yield line
|
|
59
|
+
|
|
60
|
+
def read_compressed_chunks(self) -> Iterator[bytes]:
|
|
61
|
+
decompressor = zlib.decompressobj()
|
|
62
|
+
while not self.eof:
|
|
63
|
+
self.read_buffer()
|
|
64
|
+
yield decompressor.decompress(self.buffer)
|
|
65
|
+
self.buffer = b''
|
|
66
|
+
yield decompressor.flush()
|
|
67
|
+
|
|
68
|
+
def read_compressed_lines(self) -> Iterator[str]:
|
|
69
|
+
buf = b''
|
|
70
|
+
for chunk in self.read_compressed_chunks():
|
|
71
|
+
buf += chunk
|
|
72
|
+
pos = buf.find(b'\n')
|
|
73
|
+
while pos != -1:
|
|
74
|
+
yield buf[:pos].decode()
|
|
75
|
+
buf = buf[pos + 1 :]
|
|
76
|
+
pos = buf.find(b'\n')
|
sphinx/util/_io.py
CHANGED
|
@@ -2,13 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
-
from sphinx.util.
|
|
5
|
+
from sphinx._cli.util.errors import strip_escape_sequences
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from typing import Protocol
|
|
9
9
|
|
|
10
10
|
class SupportsWrite(Protocol):
|
|
11
|
-
def write(self, text: str, /) -> int | None: ...
|
|
11
|
+
def write(self, text: str, /) -> int | None: ...
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class TeeStripANSI:
|
sphinx/util/_lines.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
def parse_line_num_spec(spec: str, total: int) -> list[int]:
|
|
2
5
|
"""Parse a line number spec (such as "1,2,4-6") and return a list of
|
|
3
6
|
wanted line numbers.
|
|
@@ -8,17 +11,17 @@ def parse_line_num_spec(spec: str, total: int) -> list[int]:
|
|
|
8
11
|
try:
|
|
9
12
|
begend = part.strip().split('-')
|
|
10
13
|
if begend == ['', '']:
|
|
11
|
-
raise ValueError
|
|
14
|
+
raise ValueError # NoQA: TRY301
|
|
12
15
|
if len(begend) == 1:
|
|
13
16
|
items.append(int(begend[0]) - 1)
|
|
14
17
|
elif len(begend) == 2:
|
|
15
18
|
start = int(begend[0] or 1) # left half open (cf. -10)
|
|
16
19
|
end = int(begend[1] or max(start, total)) # right half open (cf. 10-)
|
|
17
20
|
if start > end: # invalid range (cf. 10-1)
|
|
18
|
-
raise ValueError
|
|
21
|
+
raise ValueError # NoQA: TRY301
|
|
19
22
|
items.extend(range(start - 1, end))
|
|
20
23
|
else:
|
|
21
|
-
raise ValueError
|
|
24
|
+
raise ValueError # NoQA: TRY301
|
|
22
25
|
except ValueError as exc:
|
|
23
26
|
msg = f'invalid line number spec: {spec!r}'
|
|
24
27
|
raise ValueError(msg) from exc
|
sphinx/util/_pathlib.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Instances of _StrPath should not be constructed except in Sphinx itself.
|
|
4
4
|
Consumers of Sphinx APIs should prefer using ``pathlib.Path`` objects
|
|
5
5
|
where possible. _StrPath objects can be treated as equivalent to ``Path``,
|
|
6
|
-
save that ``_StrPath.replace`` is
|
|
6
|
+
save that ``_StrPath.replace`` is overridden with ``str.replace``.
|
|
7
7
|
|
|
8
8
|
To continue treating path-like objects as strings, use ``os.fspath``,
|
|
9
9
|
or explicit string coercion.
|
|
@@ -17,10 +17,13 @@ from __future__ import annotations
|
|
|
17
17
|
import sys
|
|
18
18
|
import warnings
|
|
19
19
|
from pathlib import Path, PosixPath, PurePath, WindowsPath
|
|
20
|
-
from typing import
|
|
20
|
+
from typing import TYPE_CHECKING, overload
|
|
21
21
|
|
|
22
22
|
from sphinx.deprecation import RemovedInSphinx90Warning
|
|
23
23
|
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
24
27
|
_STR_METHODS = frozenset(str.__dict__)
|
|
25
28
|
_PATH_NAME = Path().__class__.__name__
|
|
26
29
|
|
|
@@ -133,3 +136,38 @@ else:
|
|
|
133
136
|
def __len__(self) -> int:
|
|
134
137
|
warnings.warn(_MSG, RemovedInSphinx90Warning, stacklevel=2)
|
|
135
138
|
return len(self.__str__())
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class _StrPathProperty:
|
|
142
|
+
def __init__(self) -> None:
|
|
143
|
+
self.instance_attr: str = ''
|
|
144
|
+
|
|
145
|
+
def __set_name__(self, owner: object, name: str) -> None:
|
|
146
|
+
self.instance_attr = f'_{name}' # i.e. '_srcdir'
|
|
147
|
+
|
|
148
|
+
@overload
|
|
149
|
+
def __get__(self, obj: None, objtype: None) -> _StrPathProperty: ...
|
|
150
|
+
|
|
151
|
+
@overload
|
|
152
|
+
def __get__(self, obj: object, objtype: type[object]) -> _StrPath: ...
|
|
153
|
+
|
|
154
|
+
def __get__(
|
|
155
|
+
self, obj: object | None, objtype: type[object] | None = None
|
|
156
|
+
) -> _StrPathProperty | _StrPath:
|
|
157
|
+
if obj is None:
|
|
158
|
+
return self
|
|
159
|
+
if not self.instance_attr:
|
|
160
|
+
raise AttributeError
|
|
161
|
+
return getattr(obj, self.instance_attr)
|
|
162
|
+
|
|
163
|
+
def __set__(self, obj: Any, value: _StrPath | Path) -> None:
|
|
164
|
+
try:
|
|
165
|
+
setattr(obj, self.instance_attr, _StrPath(value))
|
|
166
|
+
except TypeError as err:
|
|
167
|
+
cls_name = type(obj).__qualname__
|
|
168
|
+
name = self.instance_attr.removeprefix('_')
|
|
169
|
+
msg = f'{cls_name}.{name} may only be set to path-like objects'
|
|
170
|
+
raise TypeError(msg) from err
|
|
171
|
+
|
|
172
|
+
def __delete__(self, obj: Any) -> None:
|
|
173
|
+
delattr(obj, self.instance_attr)
|
sphinx/util/build_phase.py
CHANGED
sphinx/util/cfamily.py
CHANGED
|
@@ -13,7 +13,7 @@ from sphinx.util import logging
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from collections.abc import Callable, Sequence
|
|
16
|
-
from typing import Any, TypeAlias
|
|
16
|
+
from typing import Any, NoReturn, TypeAlias
|
|
17
17
|
|
|
18
18
|
from docutils.nodes import TextElement
|
|
19
19
|
|
|
@@ -33,7 +33,7 @@ identifier_re = re.compile(
|
|
|
33
33
|
| (@[a-zA-Z0-9_]) # our extension for names of anonymous entities
|
|
34
34
|
)
|
|
35
35
|
[a-zA-Z0-9_]*\b
|
|
36
|
-
""",
|
|
36
|
+
""",
|
|
37
37
|
flags=re.VERBOSE,
|
|
38
38
|
)
|
|
39
39
|
integer_literal_re = re.compile(r'[1-9][0-9]*(\'[0-9]+)*')
|
|
@@ -50,7 +50,7 @@ integers_literal_suffix_re = re.compile(
|
|
|
50
50
|
)\b
|
|
51
51
|
# the ending word boundary is important for distinguishing
|
|
52
52
|
# between suffixes and UDLs in C++
|
|
53
|
-
""",
|
|
53
|
+
""",
|
|
54
54
|
flags=re.VERBOSE,
|
|
55
55
|
)
|
|
56
56
|
float_literal_re = re.compile(
|
|
@@ -66,7 +66,7 @@ float_literal_re = re.compile(
|
|
|
66
66
|
[0-9a-fA-F]+(\'[0-9a-fA-F]+)*([pP][+-]?[0-9a-fA-F]+(\'[0-9a-fA-F]+)*)?)
|
|
67
67
|
| (0[xX][0-9a-fA-F]+(\'[0-9a-fA-F]+)*\.([pP][+-]?[0-9a-fA-F]+(\'[0-9a-fA-F]+)*)?)
|
|
68
68
|
)
|
|
69
|
-
""",
|
|
69
|
+
""",
|
|
70
70
|
flags=re.VERBOSE,
|
|
71
71
|
)
|
|
72
72
|
float_literal_suffix_re = re.compile(r'[fFlL]\b')
|
|
@@ -84,13 +84,13 @@ char_literal_re = re.compile(
|
|
|
84
84
|
| (?:U[0-9a-fA-F]{8})
|
|
85
85
|
))
|
|
86
86
|
)'
|
|
87
|
-
""",
|
|
87
|
+
""",
|
|
88
88
|
flags=re.VERBOSE,
|
|
89
89
|
)
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
def verify_description_mode(mode: str) -> None:
|
|
93
|
-
if mode not in
|
|
93
|
+
if mode not in {'lastIsName', 'noneIsName', 'markType', 'markName', 'param', 'udl'}:
|
|
94
94
|
raise Exception("Description mode '%s' is invalid." % mode)
|
|
95
95
|
|
|
96
96
|
|
|
@@ -108,11 +108,14 @@ class ASTBaseBase:
|
|
|
108
108
|
except AttributeError:
|
|
109
109
|
return False
|
|
110
110
|
|
|
111
|
+
def __hash__(self) -> int:
|
|
112
|
+
return hash(sorted(self.__dict__.items()))
|
|
113
|
+
|
|
111
114
|
def clone(self) -> Any:
|
|
112
115
|
return deepcopy(self)
|
|
113
116
|
|
|
114
117
|
def _stringify(self, transform: StringifyTransform) -> str:
|
|
115
|
-
raise NotImplementedError
|
|
118
|
+
raise NotImplementedError
|
|
116
119
|
|
|
117
120
|
def __str__(self) -> str:
|
|
118
121
|
return self._stringify(str)
|
|
@@ -121,7 +124,9 @@ class ASTBaseBase:
|
|
|
121
124
|
return self._stringify(lambda ast: ast.get_display_string())
|
|
122
125
|
|
|
123
126
|
def __repr__(self) -> str:
|
|
124
|
-
|
|
127
|
+
if repr_string := self._stringify(repr):
|
|
128
|
+
return f'<{self.__class__.__name__}: {repr_string}>'
|
|
129
|
+
return f'<{self.__class__.__name__}>'
|
|
125
130
|
|
|
126
131
|
|
|
127
132
|
################################################################################
|
|
@@ -336,7 +341,7 @@ class BaseParser:
|
|
|
336
341
|
indicator = '-' * self.pos + '^'
|
|
337
342
|
logger.debug(f'{msg}\n{self.definition}\n{indicator}') # NoQA: G004
|
|
338
343
|
|
|
339
|
-
def fail(self, msg: str) ->
|
|
344
|
+
def fail(self, msg: str) -> NoReturn:
|
|
340
345
|
errors = []
|
|
341
346
|
indicator = '-' * self.pos + '^'
|
|
342
347
|
msg = (
|
|
@@ -431,7 +436,7 @@ class BaseParser:
|
|
|
431
436
|
def _parse_balanced_token_seq(self, end: list[str]) -> str:
|
|
432
437
|
# TODO: add handling of string literals and similar
|
|
433
438
|
brackets = {'(': ')', '[': ']', '{': '}'}
|
|
434
|
-
|
|
439
|
+
start_pos = self.pos
|
|
435
440
|
symbols: list[str] = []
|
|
436
441
|
while not self.eof:
|
|
437
442
|
if len(symbols) == 0 and self.current_char in end:
|
|
@@ -445,17 +450,17 @@ class BaseParser:
|
|
|
445
450
|
self.pos += 1
|
|
446
451
|
if self.eof:
|
|
447
452
|
self.fail(
|
|
448
|
-
f'Could not find end of balanced-token-seq starting at {
|
|
453
|
+
f'Could not find end of balanced-token-seq starting at {start_pos}.'
|
|
449
454
|
)
|
|
450
|
-
return self.definition[
|
|
455
|
+
return self.definition[start_pos : self.pos]
|
|
451
456
|
|
|
452
457
|
def _parse_attribute(self) -> ASTAttribute | None:
|
|
453
458
|
self.skip_ws()
|
|
454
459
|
# try C++11 style
|
|
455
|
-
|
|
460
|
+
start_pos = self.pos
|
|
456
461
|
if self.skip_string_and_ws('['):
|
|
457
462
|
if not self.skip_string('['):
|
|
458
|
-
self.pos =
|
|
463
|
+
self.pos = start_pos
|
|
459
464
|
else:
|
|
460
465
|
# TODO: actually implement the correct grammar
|
|
461
466
|
arg = self._parse_balanced_token_seq(end=[']'])
|