Sphinx 8.1.2__py3-none-any.whl → 8.2.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +48 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +114 -57
- sphinx/domains/python/_object.py +151 -67
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +21 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +66 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +271 -143
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +61 -50
- sphinx/writers/latex.py +80 -65
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +44 -45
- sphinx/writers/text.py +48 -30
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- {sphinx-8.1.2.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/jinja2glue.py
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
|
|
6
|
+
import os.path
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
from pprint import pformat
|
|
8
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
9
10
|
|
|
10
11
|
from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound
|
|
11
12
|
from jinja2.sandbox import SandboxedEnvironment
|
|
@@ -13,20 +14,26 @@ from jinja2.utils import open_if_exists, pass_context
|
|
|
13
14
|
|
|
14
15
|
from sphinx.application import TemplateBridge
|
|
15
16
|
from sphinx.util import logging
|
|
17
|
+
from sphinx.util._pathlib import _StrPath
|
|
16
18
|
from sphinx.util.osutil import _last_modified_time
|
|
17
19
|
|
|
18
20
|
if TYPE_CHECKING:
|
|
19
21
|
from collections.abc import Callable, Iterator
|
|
22
|
+
from typing import Any
|
|
20
23
|
|
|
21
24
|
from jinja2.environment import Environment
|
|
22
25
|
|
|
23
26
|
from sphinx.builders import Builder
|
|
27
|
+
from sphinx.environment.adapters.indexentries import (
|
|
28
|
+
_RealIndexEntries,
|
|
29
|
+
_RealIndexEntry,
|
|
30
|
+
)
|
|
24
31
|
from sphinx.theming import Theme
|
|
25
32
|
|
|
26
33
|
|
|
27
34
|
def _tobool(val: str) -> bool:
|
|
28
35
|
if isinstance(val, str):
|
|
29
|
-
return val.lower() in
|
|
36
|
+
return val.lower() in {'true', '1', 'yes', 'on'}
|
|
30
37
|
return bool(val)
|
|
31
38
|
|
|
32
39
|
|
|
@@ -38,8 +45,7 @@ def _toint(val: str) -> int:
|
|
|
38
45
|
|
|
39
46
|
|
|
40
47
|
def _todim(val: int | str) -> str:
|
|
41
|
-
"""
|
|
42
|
-
Make val a css dimension. In particular the following transformations
|
|
48
|
+
"""Make val a css dimension. In particular the following transformations
|
|
43
49
|
are performed:
|
|
44
50
|
|
|
45
51
|
- None -> 'initial' (default CSS value)
|
|
@@ -55,7 +61,9 @@ def _todim(val: int | str) -> str:
|
|
|
55
61
|
return val # type: ignore[return-value]
|
|
56
62
|
|
|
57
63
|
|
|
58
|
-
def _slice_index(
|
|
64
|
+
def _slice_index(
|
|
65
|
+
values: _RealIndexEntries, slices: int
|
|
66
|
+
) -> Iterator[list[_RealIndexEntry]]:
|
|
59
67
|
seq = values.copy()
|
|
60
68
|
length = 0
|
|
61
69
|
for value in values:
|
|
@@ -111,8 +119,7 @@ def warning(context: dict[str, Any], message: str, *args: Any, **kwargs: Any) ->
|
|
|
111
119
|
|
|
112
120
|
|
|
113
121
|
class SphinxFileSystemLoader(FileSystemLoader):
|
|
114
|
-
"""
|
|
115
|
-
FileSystemLoader subclass that is not so strict about '..' entries in
|
|
122
|
+
"""FileSystemLoader subclass that is not so strict about '..' entries in
|
|
116
123
|
template names.
|
|
117
124
|
"""
|
|
118
125
|
|
|
@@ -125,14 +132,14 @@ class SphinxFileSystemLoader(FileSystemLoader):
|
|
|
125
132
|
else:
|
|
126
133
|
legacy_template = None
|
|
127
134
|
|
|
128
|
-
for
|
|
129
|
-
filename =
|
|
130
|
-
f = open_if_exists(filename)
|
|
135
|
+
for search_path in map(Path, self.searchpath):
|
|
136
|
+
filename = search_path / template
|
|
137
|
+
f = open_if_exists(str(filename))
|
|
131
138
|
if f is not None:
|
|
132
139
|
break
|
|
133
140
|
if legacy_template is not None:
|
|
134
|
-
filename =
|
|
135
|
-
f = open_if_exists(filename)
|
|
141
|
+
filename = search_path / legacy_template
|
|
142
|
+
f = open_if_exists(str(filename))
|
|
136
143
|
if f is not None:
|
|
137
144
|
break
|
|
138
145
|
else:
|
|
@@ -149,13 +156,11 @@ class SphinxFileSystemLoader(FileSystemLoader):
|
|
|
149
156
|
except OSError:
|
|
150
157
|
return False
|
|
151
158
|
|
|
152
|
-
return contents, filename, uptodate
|
|
159
|
+
return contents, str(filename), uptodate
|
|
153
160
|
|
|
154
161
|
|
|
155
162
|
class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
156
|
-
"""
|
|
157
|
-
Interfaces the rendering environment of jinja2 for use in Sphinx.
|
|
158
|
-
"""
|
|
163
|
+
"""Interfaces the rendering environment of jinja2 for use in Sphinx."""
|
|
159
164
|
|
|
160
165
|
# TemplateBridge interface
|
|
161
166
|
|
|
@@ -170,10 +175,10 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
|
170
175
|
# the theme's own dir and its bases' dirs
|
|
171
176
|
pathchain = theme.get_theme_dirs()
|
|
172
177
|
# the loader dirs: pathchain + the parent directories for all themes
|
|
173
|
-
loaderchain = pathchain + [
|
|
178
|
+
loaderchain = pathchain + [p.parent for p in pathchain]
|
|
174
179
|
elif dirs:
|
|
175
|
-
pathchain = list(dirs)
|
|
176
|
-
loaderchain = list(dirs)
|
|
180
|
+
pathchain = list(map(_StrPath, dirs))
|
|
181
|
+
loaderchain = list(map(_StrPath, dirs))
|
|
177
182
|
else:
|
|
178
183
|
pathchain = []
|
|
179
184
|
loaderchain = []
|
|
@@ -182,7 +187,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
|
182
187
|
self.templatepathlen = len(builder.config.templates_path)
|
|
183
188
|
if builder.config.templates_path:
|
|
184
189
|
cfg_templates_path = [
|
|
185
|
-
|
|
190
|
+
builder.confdir / tp for tp in builder.config.templates_path
|
|
186
191
|
]
|
|
187
192
|
pathchain[0:0] = cfg_templates_path
|
|
188
193
|
loaderchain[0:0] = cfg_templates_path
|
|
@@ -193,7 +198,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
|
193
198
|
# make the paths into loaders
|
|
194
199
|
self.loaders = [SphinxFileSystemLoader(x) for x in loaderchain]
|
|
195
200
|
|
|
196
|
-
use_i18n = builder.
|
|
201
|
+
use_i18n = builder._translator is not None
|
|
197
202
|
extensions = ['jinja2.ext.i18n'] if use_i18n else []
|
|
198
203
|
self.environment = SandboxedEnvironment(loader=self, extensions=extensions)
|
|
199
204
|
self.environment.filters['tobool'] = _tobool
|
|
@@ -206,9 +211,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
|
206
211
|
self.environment.globals['idgen'] = idgen
|
|
207
212
|
if use_i18n:
|
|
208
213
|
# ``install_gettext_translations`` is injected by the ``jinja2.ext.i18n`` extension
|
|
209
|
-
self.environment.install_gettext_translations( # type: ignore[attr-defined]
|
|
210
|
-
builder.app.translator
|
|
211
|
-
)
|
|
214
|
+
self.environment.install_gettext_translations(builder._translator) # type: ignore[attr-defined]
|
|
212
215
|
|
|
213
216
|
def render(self, template: str, context: dict[str, Any]) -> str: # type: ignore[override]
|
|
214
217
|
return self.environment.get_template(template).render(context)
|
|
@@ -224,7 +227,7 @@ class BuiltinTemplateLoader(TemplateBridge, BaseLoader):
|
|
|
224
227
|
|
|
225
228
|
def _newest_template_mtime_name(self) -> tuple[float, str]:
|
|
226
229
|
return max(
|
|
227
|
-
(
|
|
230
|
+
(Path(root, sfile).stat().st_mtime_ns / 10**9, sfile)
|
|
228
231
|
for dirname in self.pathchain
|
|
229
232
|
for root, _dirs, files in os.walk(dirname)
|
|
230
233
|
for sfile in files
|
sphinx/locale/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import locale
|
|
6
6
|
import sys
|
|
7
7
|
from gettext import NullTranslations, translation
|
|
8
|
-
from
|
|
8
|
+
from pathlib import Path
|
|
9
9
|
from typing import TYPE_CHECKING
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
@@ -15,8 +15,7 @@ if TYPE_CHECKING:
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class _TranslationProxy:
|
|
18
|
-
"""
|
|
19
|
-
The proxy implementation attempts to be as complete as possible, so that
|
|
18
|
+
"""The proxy implementation attempts to be as complete as possible, so that
|
|
20
19
|
the lazy objects should mostly work as expected, for example for sorting.
|
|
21
20
|
"""
|
|
22
21
|
|
|
@@ -141,11 +140,11 @@ def init(
|
|
|
141
140
|
return translator, has_translation
|
|
142
141
|
|
|
143
142
|
|
|
144
|
-
_LOCALE_DIR =
|
|
143
|
+
_LOCALE_DIR = Path(__file__).resolve().parent
|
|
145
144
|
|
|
146
145
|
|
|
147
146
|
def init_console(
|
|
148
|
-
locale_dir: str | None = None,
|
|
147
|
+
locale_dir: str | os.PathLike[str] | None = None,
|
|
149
148
|
catalog: str = 'sphinx',
|
|
150
149
|
) -> tuple[NullTranslations, bool]:
|
|
151
150
|
"""Initialize locale for console.
|
|
@@ -184,7 +183,7 @@ def get_translation(catalog: str, namespace: str = 'general') -> Callable[[str],
|
|
|
184
183
|
The extension can use this API to translate the messages on the
|
|
185
184
|
extension::
|
|
186
185
|
|
|
187
|
-
import
|
|
186
|
+
from pathlib import Path
|
|
188
187
|
from sphinx.locale import get_translation
|
|
189
188
|
|
|
190
189
|
MESSAGE_CATALOG_NAME = 'myextension' # name of *.pot, *.po and *.mo files
|
|
@@ -193,8 +192,8 @@ def get_translation(catalog: str, namespace: str = 'general') -> Callable[[str],
|
|
|
193
192
|
|
|
194
193
|
|
|
195
194
|
def setup(app):
|
|
196
|
-
package_dir =
|
|
197
|
-
locale_dir =
|
|
195
|
+
package_dir = Path(__file__).resolve().parent
|
|
196
|
+
locale_dir = package_dir / 'locales'
|
|
198
197
|
app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_dir)
|
|
199
198
|
|
|
200
199
|
With this code, sphinx searches a message catalog from
|
|
@@ -207,7 +206,7 @@ def get_translation(catalog: str, namespace: str = 'general') -> Callable[[str],
|
|
|
207
206
|
def gettext(message: str) -> str:
|
|
208
207
|
if not is_translator_registered(catalog, namespace):
|
|
209
208
|
# not initialized yet
|
|
210
|
-
return _TranslationProxy(catalog, namespace, message) # type: ignore[return-value]
|
|
209
|
+
return _TranslationProxy(catalog, namespace, message) # type: ignore[return-value]
|
|
211
210
|
else:
|
|
212
211
|
translator = get_translator(catalog, namespace)
|
|
213
212
|
return translator.gettext(message)
|
sphinx/parsers.py
CHANGED
|
@@ -6,7 +6,6 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
|
|
7
7
|
import docutils.parsers
|
|
8
8
|
import docutils.parsers.rst
|
|
9
|
-
from docutils import nodes
|
|
10
9
|
from docutils.parsers.rst import states
|
|
11
10
|
from docutils.statemachine import StringList
|
|
12
11
|
from docutils.transforms.universal import SmartQuotes
|
|
@@ -14,6 +13,7 @@ from docutils.transforms.universal import SmartQuotes
|
|
|
14
13
|
from sphinx.util.rst import append_epilog, prepend_prolog
|
|
15
14
|
|
|
16
15
|
if TYPE_CHECKING:
|
|
16
|
+
from docutils import nodes
|
|
17
17
|
from docutils.transforms import Transform
|
|
18
18
|
|
|
19
19
|
from sphinx.application import Sphinx
|
|
@@ -23,10 +23,12 @@ if TYPE_CHECKING:
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Parser(docutils.parsers.Parser):
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
"""A base class of source parsers.
|
|
27
|
+
|
|
28
|
+
The additional parsers should inherit this class
|
|
29
|
+
instead of ``docutils.parsers.Parser``.
|
|
30
|
+
Compared with ``docutils.parsers.Parser``,
|
|
31
|
+
this class improves accessibility to Sphinx APIs.
|
|
30
32
|
|
|
31
33
|
The subclasses can access sphinx core runtime objects (app, config and env).
|
|
32
34
|
"""
|
|
@@ -51,8 +53,7 @@ class RSTParser(docutils.parsers.rst.Parser, Parser):
|
|
|
51
53
|
"""A reST parser for Sphinx."""
|
|
52
54
|
|
|
53
55
|
def get_transforms(self) -> list[type[Transform]]:
|
|
54
|
-
"""
|
|
55
|
-
Sphinx's reST parser replaces a transform class for smart-quotes by its own
|
|
56
|
+
"""Sphinx's reST parser replaces a transform class for smart-quotes by its own
|
|
56
57
|
|
|
57
58
|
refs: sphinx.io.SphinxStandaloneReader
|
|
58
59
|
"""
|
sphinx/project.py
CHANGED
|
@@ -96,10 +96,10 @@ class Project:
|
|
|
96
96
|
|
|
97
97
|
*filename* should be absolute or relative to the source directory.
|
|
98
98
|
"""
|
|
99
|
+
path = Path(filename)
|
|
99
100
|
try:
|
|
100
|
-
return self._path_to_docname[
|
|
101
|
+
return self._path_to_docname[path]
|
|
101
102
|
except KeyError:
|
|
102
|
-
path = Path(filename)
|
|
103
103
|
if path.is_absolute():
|
|
104
104
|
with contextlib.suppress(ValueError):
|
|
105
105
|
path = path.relative_to(self.srcdir)
|
sphinx/pycode/__init__.py
CHANGED
|
@@ -4,14 +4,16 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import tokenize
|
|
6
6
|
from importlib import import_module
|
|
7
|
-
from
|
|
8
|
-
from typing import TYPE_CHECKING, Any
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
9
8
|
|
|
10
9
|
from sphinx.errors import PycodeError
|
|
11
10
|
from sphinx.pycode.parser import Parser
|
|
11
|
+
from sphinx.util._pathlib import _StrPath
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
+
import os
|
|
14
15
|
from inspect import Signature
|
|
16
|
+
from typing import Any, Literal
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class ModuleAnalyzer:
|
|
@@ -23,10 +25,10 @@ class ModuleAnalyzer:
|
|
|
23
25
|
tags: dict[str, tuple[str, int, int]]
|
|
24
26
|
|
|
25
27
|
# cache for analyzer objects -- caches both by module and file name
|
|
26
|
-
cache: dict[tuple[
|
|
28
|
+
cache: dict[tuple[Literal['file', 'module'], str | _StrPath], Any] = {}
|
|
27
29
|
|
|
28
30
|
@staticmethod
|
|
29
|
-
def get_module_source(modname: str) -> tuple[
|
|
31
|
+
def get_module_source(modname: str) -> tuple[_StrPath | None, str | None]:
|
|
30
32
|
"""Try to find the source code for a module.
|
|
31
33
|
|
|
32
34
|
Returns ('filename', 'source'). One of it can be None if
|
|
@@ -37,14 +39,15 @@ class ModuleAnalyzer:
|
|
|
37
39
|
except Exception as err:
|
|
38
40
|
raise PycodeError('error importing %r' % modname, err) from err
|
|
39
41
|
loader = getattr(mod, '__loader__', None)
|
|
40
|
-
filename = getattr(mod, '__file__', None)
|
|
42
|
+
filename: str | None = getattr(mod, '__file__', None)
|
|
41
43
|
if loader and getattr(loader, 'get_source', None):
|
|
42
44
|
# prefer Native loader, as it respects #coding directive
|
|
43
45
|
try:
|
|
44
46
|
source = loader.get_source(modname)
|
|
45
47
|
if source:
|
|
48
|
+
mod_path = None if filename is None else _StrPath(filename)
|
|
46
49
|
# no exception and not None - it must be module source
|
|
47
|
-
return
|
|
50
|
+
return mod_path, source
|
|
48
51
|
except ImportError:
|
|
49
52
|
pass # Try other "source-mining" methods
|
|
50
53
|
if filename is None and loader and getattr(loader, 'get_filename', None):
|
|
@@ -58,31 +61,36 @@ class ModuleAnalyzer:
|
|
|
58
61
|
if filename is None:
|
|
59
62
|
# all methods for getting filename failed, so raise...
|
|
60
63
|
raise PycodeError('no source found for module %r' % modname)
|
|
61
|
-
|
|
62
|
-
if
|
|
63
|
-
|
|
64
|
-
if not
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
raise PycodeError(
|
|
71
|
-
|
|
64
|
+
mod_path = _StrPath(filename).resolve()
|
|
65
|
+
if mod_path.suffix in {'.pyo', '.pyc'}:
|
|
66
|
+
mod_path_pyw = mod_path.with_suffix('.pyw')
|
|
67
|
+
if not mod_path.is_file() and mod_path_pyw.is_file():
|
|
68
|
+
mod_path = mod_path_pyw
|
|
69
|
+
else:
|
|
70
|
+
mod_path = mod_path.with_suffix('.py')
|
|
71
|
+
elif mod_path.suffix not in {'.py', '.pyw'}:
|
|
72
|
+
msg = f'source is not a .py file: {mod_path!r}'
|
|
73
|
+
raise PycodeError(msg)
|
|
74
|
+
|
|
75
|
+
if not mod_path.is_file():
|
|
76
|
+
msg = f'source file is not present: {mod_path!r}'
|
|
77
|
+
raise PycodeError(msg)
|
|
78
|
+
return mod_path, None
|
|
72
79
|
|
|
73
80
|
@classmethod
|
|
74
81
|
def for_string(
|
|
75
82
|
cls: type[ModuleAnalyzer],
|
|
76
83
|
string: str,
|
|
77
84
|
modname: str,
|
|
78
|
-
srcname: str = '<string>',
|
|
85
|
+
srcname: str | os.PathLike[str] = '<string>',
|
|
79
86
|
) -> ModuleAnalyzer:
|
|
80
87
|
return cls(string, modname, srcname)
|
|
81
88
|
|
|
82
89
|
@classmethod
|
|
83
90
|
def for_file(
|
|
84
|
-
cls: type[ModuleAnalyzer], filename: str, modname: str
|
|
91
|
+
cls: type[ModuleAnalyzer], filename: str | os.PathLike[str], modname: str
|
|
85
92
|
) -> ModuleAnalyzer:
|
|
93
|
+
filename = _StrPath(filename)
|
|
86
94
|
if ('file', filename) in cls.cache:
|
|
87
95
|
return cls.cache['file', filename]
|
|
88
96
|
try:
|
|
@@ -114,9 +122,11 @@ class ModuleAnalyzer:
|
|
|
114
122
|
cls.cache['module', modname] = obj
|
|
115
123
|
return obj
|
|
116
124
|
|
|
117
|
-
def __init__(
|
|
125
|
+
def __init__(
|
|
126
|
+
self, source: str, modname: str, srcname: str | os.PathLike[str]
|
|
127
|
+
) -> None:
|
|
118
128
|
self.modname = modname # name of the module
|
|
119
|
-
self.srcname = srcname # name of the source file
|
|
129
|
+
self.srcname = str(srcname) # name of the source file
|
|
120
130
|
|
|
121
131
|
# cache the source code as well
|
|
122
132
|
self.code = source
|
sphinx/pycode/ast.py
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import ast
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import TYPE_CHECKING, overload
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from typing import NoReturn
|
|
7
10
|
|
|
8
11
|
OPERATORS: dict[type[ast.AST], str] = {
|
|
9
12
|
ast.Add: '+',
|
|
@@ -29,11 +32,11 @@ OPERATORS: dict[type[ast.AST], str] = {
|
|
|
29
32
|
|
|
30
33
|
|
|
31
34
|
@overload
|
|
32
|
-
def unparse(node: None, code: str = '') -> None: ...
|
|
35
|
+
def unparse(node: None, code: str = '') -> None: ...
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
@overload
|
|
36
|
-
def unparse(node: ast.AST, code: str = '') -> str: ...
|
|
39
|
+
def unparse(node: ast.AST, code: str = '') -> str: ...
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
def unparse(node: ast.AST | None, code: str = '') -> str | None:
|
sphinx/pycode/parser.py
CHANGED
|
@@ -10,13 +10,16 @@ import itertools
|
|
|
10
10
|
import operator
|
|
11
11
|
import re
|
|
12
12
|
import tokenize
|
|
13
|
-
from inspect import Signature
|
|
14
13
|
from token import DEDENT, INDENT, NAME, NEWLINE, NUMBER, OP, STRING
|
|
15
14
|
from tokenize import COMMENT, NL
|
|
16
|
-
from typing import
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
17
16
|
|
|
18
17
|
from sphinx.pycode.ast import unparse as ast_unparse
|
|
19
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from inspect import Signature
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
20
23
|
comment_re = re.compile('^\\s*#: ?(.*)\r?\n?$')
|
|
21
24
|
indent_re = re.compile('^\\s*$')
|
|
22
25
|
emptyline_re = re.compile('^\\s*(#.*)?$')
|
|
@@ -40,21 +43,21 @@ def get_lvar_names(node: ast.AST, self: ast.arg | None = None) -> list[str]:
|
|
|
40
43
|
This raises `TypeError` if the assignment does not create new variable::
|
|
41
44
|
|
|
42
45
|
ary[0] = 'foo'
|
|
43
|
-
dic[
|
|
46
|
+
dic['bar'] = 'baz'
|
|
44
47
|
# => TypeError
|
|
45
48
|
"""
|
|
46
49
|
if self:
|
|
47
50
|
self_id = self.arg
|
|
48
51
|
|
|
49
52
|
node_name = node.__class__.__name__
|
|
50
|
-
if node_name in
|
|
53
|
+
if node_name in {'Constant', 'Index', 'Slice', 'Subscript'}:
|
|
51
54
|
raise TypeError('%r does not create new variable' % node)
|
|
52
55
|
if node_name == 'Name':
|
|
53
56
|
if self is None or node.id == self_id: # type: ignore[attr-defined]
|
|
54
57
|
return [node.id] # type: ignore[attr-defined]
|
|
55
58
|
else:
|
|
56
59
|
raise TypeError('The assignment %r is not instance variable' % node)
|
|
57
|
-
elif node_name in
|
|
60
|
+
elif node_name in {'Tuple', 'List'}:
|
|
58
61
|
members = []
|
|
59
62
|
for elt in node.elts: # type: ignore[attr-defined]
|
|
60
63
|
with contextlib.suppress(TypeError):
|
|
@@ -111,7 +114,7 @@ class Token:
|
|
|
111
114
|
self.end = end
|
|
112
115
|
self.source = source
|
|
113
116
|
|
|
114
|
-
def __eq__(self, other:
|
|
117
|
+
def __eq__(self, other: object) -> bool:
|
|
115
118
|
if isinstance(other, int):
|
|
116
119
|
return self.kind == other
|
|
117
120
|
elif isinstance(other, str):
|
|
@@ -123,6 +126,9 @@ class Token:
|
|
|
123
126
|
else:
|
|
124
127
|
raise ValueError('Unknown value: %r' % other)
|
|
125
128
|
|
|
129
|
+
def __hash__(self) -> int:
|
|
130
|
+
return hash((self.kind, self.value, self.start, self.end, self.source))
|
|
131
|
+
|
|
126
132
|
def match(self, *conditions: Any) -> bool:
|
|
127
133
|
return any(self == candidate for candidate in conditions)
|
|
128
134
|
|
|
@@ -280,13 +286,13 @@ class VariableCommentPicker(ast.NodeVisitor):
|
|
|
280
286
|
qualname = self.get_qualname_for(name)
|
|
281
287
|
if qualname:
|
|
282
288
|
basename = '.'.join(qualname[:-1])
|
|
283
|
-
self.comments[
|
|
289
|
+
self.comments[basename, name] = comment
|
|
284
290
|
|
|
285
291
|
def add_variable_annotation(self, name: str, annotation: ast.AST) -> None:
|
|
286
292
|
qualname = self.get_qualname_for(name)
|
|
287
293
|
if qualname:
|
|
288
294
|
basename = '.'.join(qualname[:-1])
|
|
289
|
-
self.annotations[
|
|
295
|
+
self.annotations[basename, name] = ast_unparse(annotation)
|
|
290
296
|
|
|
291
297
|
def is_final(self, decorators: list[ast.expr]) -> bool:
|
|
292
298
|
final = []
|
sphinx/pygments_styles.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Sphinx theme specific highlighting styles."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
from pygments.style import Style
|
|
4
6
|
from pygments.styles.friendly import FriendlyStyle
|
|
5
7
|
from pygments.token import (
|
|
@@ -20,8 +22,7 @@ class NoneStyle(Style):
|
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class SphinxStyle(Style):
|
|
23
|
-
"""
|
|
24
|
-
Like friendly, but a bit darker to enhance contrast on the green
|
|
25
|
+
"""Like friendly, but a bit darker to enhance contrast on the green
|
|
25
26
|
background.
|
|
26
27
|
"""
|
|
27
28
|
|
|
@@ -37,9 +38,7 @@ class SphinxStyle(Style):
|
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
class PyramidStyle(Style):
|
|
40
|
-
"""
|
|
41
|
-
Pylons/pyramid pygments style based on friendly style, by Blaise Laflamme.
|
|
42
|
-
"""
|
|
41
|
+
"""Pylons/pyramid pygments style based on friendly style, by Blaise Laflamme."""
|
|
43
42
|
|
|
44
43
|
# work in progress...
|
|
45
44
|
|