Sphinx 7.4.6__py3-none-any.whl → 8.0.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 +2 -2
- sphinx/_cli/__init__.py +4 -4
- sphinx/application.py +7 -7
- sphinx/builders/__init__.py +2 -3
- sphinx/builders/_epub_base.py +33 -12
- sphinx/builders/changes.py +13 -5
- sphinx/builders/epub3.py +6 -2
- sphinx/builders/html/__init__.py +90 -59
- sphinx/builders/latex/__init__.py +38 -12
- sphinx/builders/latex/transforms.py +1 -1
- sphinx/builders/linkcheck.py +8 -49
- sphinx/builders/texinfo.py +12 -6
- sphinx/builders/text.py +7 -3
- sphinx/builders/xml.py +7 -3
- sphinx/cmd/quickstart.py +10 -20
- sphinx/config.py +12 -12
- sphinx/deprecation.py +8 -8
- sphinx/directives/__init__.py +14 -9
- sphinx/directives/other.py +2 -3
- sphinx/directives/patches.py +2 -2
- sphinx/domains/__init__.py +4 -2
- sphinx/domains/c/__init__.py +2 -2
- sphinx/domains/c/_ast.py +3 -2
- sphinx/domains/c/_parser.py +4 -3
- sphinx/domains/cpp/__init__.py +2 -2
- sphinx/domains/cpp/_ast.py +1 -2
- sphinx/domains/cpp/_parser.py +2 -2
- sphinx/domains/cpp/_symbol.py +2 -2
- sphinx/domains/javascript.py +1 -1
- sphinx/domains/math.py +1 -1
- sphinx/domains/python/__init__.py +1 -1
- sphinx/domains/python/_annotations.py +23 -1
- sphinx/domains/python/_object.py +0 -1
- sphinx/domains/std/__init__.py +7 -8
- sphinx/environment/__init__.py +14 -32
- sphinx/environment/adapters/indexentries.py +4 -6
- sphinx/environment/adapters/toctree.py +4 -4
- sphinx/environment/collectors/title.py +1 -1
- sphinx/environment/collectors/toctree.py +1 -1
- sphinx/events.py +3 -1
- sphinx/ext/autodoc/__init__.py +25 -67
- sphinx/ext/autodoc/directive.py +7 -5
- sphinx/ext/autodoc/importer.py +2 -1
- sphinx/ext/autodoc/preserve_defaults.py +2 -2
- sphinx/ext/autosummary/__init__.py +15 -7
- sphinx/ext/autosummary/generate.py +5 -4
- sphinx/ext/doctest.py +5 -5
- sphinx/ext/graphviz.py +1 -1
- sphinx/ext/imgmath.py +1 -1
- sphinx/ext/inheritance_diagram.py +1 -1
- sphinx/ext/intersphinx/__init__.py +25 -5
- sphinx/ext/intersphinx/_cli.py +7 -6
- sphinx/ext/intersphinx/_load.py +240 -115
- sphinx/ext/intersphinx/_resolve.py +12 -11
- sphinx/ext/intersphinx/_shared.py +102 -9
- sphinx/ext/mathjax.py +1 -1
- sphinx/ext/napoleon/docstring.py +2 -2
- sphinx/ext/todo.py +2 -2
- sphinx/ext/viewcode.py +2 -1
- sphinx/highlighting.py +3 -3
- sphinx/io.py +2 -2
- sphinx/jinja2glue.py +13 -6
- sphinx/locale/__init__.py +4 -3
- sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
- sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ta/LC_MESSAGES/sphinx.po +1578 -1843
- sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +496 -704
- sphinx/project.py +23 -19
- sphinx/pycode/ast.py +2 -2
- sphinx/pycode/parser.py +2 -2
- sphinx/pygments_styles.py +3 -3
- sphinx/registry.py +3 -8
- sphinx/search/__init__.py +1 -1
- sphinx/testing/path.py +2 -1
- sphinx/testing/util.py +1 -1
- sphinx/texinputs/Makefile.jinja +2 -1
- sphinx/texinputs_win/Makefile.jinja +2 -1
- sphinx/theming.py +3 -12
- sphinx/transforms/__init__.py +5 -5
- sphinx/transforms/references.py +1 -1
- sphinx/util/__init__.py +11 -35
- sphinx/util/_timestamps.py +12 -0
- sphinx/util/cfamily.py +5 -5
- sphinx/util/console.py +4 -3
- sphinx/util/display.py +3 -3
- sphinx/util/docfields.py +1 -1
- sphinx/util/docutils.py +44 -10
- sphinx/util/fileutil.py +41 -9
- sphinx/util/i18n.py +9 -4
- sphinx/util/images.py +3 -2
- sphinx/util/inspect.py +29 -44
- sphinx/util/inventory.py +2 -2
- sphinx/util/matching.py +2 -2
- sphinx/util/math.py +1 -1
- sphinx/util/nodes.py +8 -8
- sphinx/util/osutil.py +46 -23
- sphinx/util/parallel.py +2 -2
- sphinx/util/requests.py +1 -1
- sphinx/util/template.py +3 -3
- sphinx/util/typing.py +67 -70
- sphinx/writers/html.py +1 -1
- sphinx/writers/html5.py +1 -1
- sphinx/writers/latex.py +4 -4
- sphinx/writers/manpage.py +2 -2
- sphinx/writers/texinfo.py +5 -5
- sphinx/writers/text.py +4 -4
- sphinx/writers/xml.py +2 -2
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/METADATA +10 -9
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/RECORD +112 -114
- sphinx/templates/quickstart/Makefile.jinja +0 -98
- sphinx/templates/quickstart/make.bat.jinja +0 -110
- sphinx/util/_pathlib.py +0 -120
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/LICENSE.rst +0 -0
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/WHEEL +0 -0
- {sphinx-7.4.6.dist-info → sphinx-8.0.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/util/typing.py
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import dataclasses
|
|
5
6
|
import sys
|
|
6
7
|
import types
|
|
7
8
|
import typing
|
|
8
|
-
from collections.abc import Sequence
|
|
9
|
+
from collections.abc import Callable, Sequence
|
|
9
10
|
from contextvars import Context, ContextVar, Token
|
|
10
11
|
from struct import Struct
|
|
11
12
|
from typing import (
|
|
12
13
|
TYPE_CHECKING,
|
|
13
14
|
Annotated,
|
|
14
15
|
Any,
|
|
15
|
-
Callable,
|
|
16
16
|
ForwardRef,
|
|
17
|
+
NewType,
|
|
17
18
|
TypedDict,
|
|
18
19
|
TypeVar,
|
|
19
20
|
Union,
|
|
@@ -24,9 +25,9 @@ from docutils.parsers.rst.states import Inliner
|
|
|
24
25
|
|
|
25
26
|
if TYPE_CHECKING:
|
|
26
27
|
from collections.abc import Mapping
|
|
27
|
-
from typing import Final, Literal, Protocol
|
|
28
|
+
from typing import Final, Literal, Protocol, TypeAlias
|
|
28
29
|
|
|
29
|
-
from typing_extensions import
|
|
30
|
+
from typing_extensions import TypeIs
|
|
30
31
|
|
|
31
32
|
from sphinx.application import Sphinx
|
|
32
33
|
|
|
@@ -40,10 +41,6 @@ if TYPE_CHECKING:
|
|
|
40
41
|
'smart',
|
|
41
42
|
]
|
|
42
43
|
|
|
43
|
-
if sys.version_info >= (3, 10):
|
|
44
|
-
from types import UnionType
|
|
45
|
-
else:
|
|
46
|
-
UnionType = None
|
|
47
44
|
|
|
48
45
|
# classes that have an incorrect .__module__ attribute
|
|
49
46
|
_INVALID_BUILTIN_CLASSES: Final[Mapping[object, str]] = {
|
|
@@ -84,13 +81,10 @@ def is_invalid_builtin_class(obj: Any) -> bool:
|
|
|
84
81
|
|
|
85
82
|
|
|
86
83
|
# Text like nodes which are initialized with text and rawsource
|
|
87
|
-
TextlikeNode =
|
|
88
|
-
|
|
89
|
-
# type of None
|
|
90
|
-
NoneType = type(None)
|
|
84
|
+
TextlikeNode: TypeAlias = nodes.Text | nodes.TextElement
|
|
91
85
|
|
|
92
86
|
# path matcher
|
|
93
|
-
PathMatcher = Callable[[str], bool]
|
|
87
|
+
PathMatcher: TypeAlias = Callable[[str], bool]
|
|
94
88
|
|
|
95
89
|
# common role functions
|
|
96
90
|
if TYPE_CHECKING:
|
|
@@ -108,25 +102,25 @@ if TYPE_CHECKING:
|
|
|
108
102
|
) -> tuple[list[nodes.Node], list[nodes.system_message]]:
|
|
109
103
|
...
|
|
110
104
|
else:
|
|
111
|
-
RoleFunction = Callable[
|
|
105
|
+
RoleFunction: TypeAlias = Callable[
|
|
112
106
|
[str, str, str, int, Inliner, dict[str, Any], Sequence[str]],
|
|
113
107
|
tuple[list[nodes.Node], list[nodes.system_message]],
|
|
114
108
|
]
|
|
115
109
|
|
|
116
110
|
# A option spec for directive
|
|
117
|
-
OptionSpec = dict[str, Callable[[str], Any]]
|
|
111
|
+
OptionSpec: TypeAlias = dict[str, Callable[[str], Any]]
|
|
118
112
|
|
|
119
113
|
# title getter functions for enumerable nodes (see sphinx.domains.std)
|
|
120
|
-
TitleGetter = Callable[[nodes.Node], str]
|
|
114
|
+
TitleGetter: TypeAlias = Callable[[nodes.Node], str]
|
|
121
115
|
|
|
122
116
|
# inventory data on memory
|
|
123
|
-
InventoryItem = tuple[
|
|
117
|
+
InventoryItem: TypeAlias = tuple[
|
|
124
118
|
str, # project name
|
|
125
119
|
str, # project version
|
|
126
120
|
str, # URL
|
|
127
121
|
str, # display name
|
|
128
122
|
]
|
|
129
|
-
Inventory = dict[str, dict[str, InventoryItem]]
|
|
123
|
+
Inventory: TypeAlias = dict[str, dict[str, InventoryItem]]
|
|
130
124
|
|
|
131
125
|
|
|
132
126
|
class ExtensionMetadata(TypedDict, total=False):
|
|
@@ -150,13 +144,14 @@ class ExtensionMetadata(TypedDict, total=False):
|
|
|
150
144
|
|
|
151
145
|
|
|
152
146
|
if TYPE_CHECKING:
|
|
153
|
-
_ExtensionSetupFunc = Callable[[Sphinx], ExtensionMetadata]
|
|
147
|
+
_ExtensionSetupFunc: TypeAlias = Callable[[Sphinx], ExtensionMetadata]
|
|
154
148
|
|
|
155
149
|
|
|
156
150
|
def get_type_hints(
|
|
157
151
|
obj: Any,
|
|
158
152
|
globalns: dict[str, Any] | None = None,
|
|
159
153
|
localns: dict[str, Any] | None = None,
|
|
154
|
+
include_extras: bool = False,
|
|
160
155
|
) -> dict[str, Any]:
|
|
161
156
|
"""Return a dictionary containing type hints for a function, method, module or class
|
|
162
157
|
object.
|
|
@@ -167,7 +162,7 @@ def get_type_hints(
|
|
|
167
162
|
from sphinx.util.inspect import safe_getattr # lazy loading
|
|
168
163
|
|
|
169
164
|
try:
|
|
170
|
-
return typing.get_type_hints(obj, globalns, localns)
|
|
165
|
+
return typing.get_type_hints(obj, globalns, localns, include_extras=include_extras)
|
|
171
166
|
except NameError:
|
|
172
167
|
# Failed to evaluate ForwardRef (maybe TYPE_CHECKING)
|
|
173
168
|
return safe_getattr(obj, '__annotations__', {})
|
|
@@ -202,24 +197,14 @@ def _is_unpack_form(obj: Any) -> bool:
|
|
|
202
197
|
# that typing_extensions.Unpack should not be used in that case
|
|
203
198
|
return typing.get_origin(obj) is Unpack
|
|
204
199
|
|
|
205
|
-
#
|
|
200
|
+
# Python 3.10 requires typing_extensions.Unpack
|
|
206
201
|
origin = typing.get_origin(obj)
|
|
207
202
|
return (
|
|
208
203
|
getattr(origin, '__module__', None) == 'typing_extensions'
|
|
209
|
-
and
|
|
204
|
+
and origin.__name__ == 'Unpack'
|
|
210
205
|
)
|
|
211
206
|
|
|
212
207
|
|
|
213
|
-
def _typing_internal_name(obj: Any) -> str | None:
|
|
214
|
-
if sys.version_info[:2] >= (3, 10):
|
|
215
|
-
try:
|
|
216
|
-
return obj.__name__
|
|
217
|
-
except AttributeError:
|
|
218
|
-
# e.g. ParamSpecArgs, ParamSpecKwargs
|
|
219
|
-
return ''
|
|
220
|
-
return getattr(obj, '_name', None)
|
|
221
|
-
|
|
222
|
-
|
|
223
208
|
def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> str:
|
|
224
209
|
"""Convert a type-like object to a reST reference.
|
|
225
210
|
|
|
@@ -232,7 +217,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
232
217
|
Show the name of the annotation.
|
|
233
218
|
"""
|
|
234
219
|
from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
|
|
235
|
-
from sphinx.util import
|
|
220
|
+
from sphinx.util.inspect import isgenericalias, object_description # lazy loading
|
|
236
221
|
|
|
237
222
|
valid_modes = {'fully-qualified-except-typing', 'smart'}
|
|
238
223
|
if mode not in valid_modes:
|
|
@@ -241,7 +226,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
241
226
|
raise ValueError(msg)
|
|
242
227
|
|
|
243
228
|
# things that are not types
|
|
244
|
-
if cls is None or cls == NoneType:
|
|
229
|
+
if cls is None or cls == types.NoneType:
|
|
245
230
|
return ':py:obj:`None`'
|
|
246
231
|
if cls is Ellipsis:
|
|
247
232
|
return '...'
|
|
@@ -267,18 +252,28 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
267
252
|
return f':py:class:`{module_prefix}{_INVALID_BUILTIN_CLASSES[cls]}`'
|
|
268
253
|
elif _is_annotated_form(cls):
|
|
269
254
|
args = restify(cls.__args__[0], mode)
|
|
270
|
-
|
|
255
|
+
meta_args = []
|
|
256
|
+
for m in cls.__metadata__:
|
|
257
|
+
if isinstance(m, type):
|
|
258
|
+
meta_args.append(restify(m, mode))
|
|
259
|
+
elif dataclasses.is_dataclass(m):
|
|
260
|
+
# use restify for the repr of field values rather than repr
|
|
261
|
+
d_fields = ', '.join([
|
|
262
|
+
fr"{f.name}=\ {restify(getattr(m, f.name), mode)}"
|
|
263
|
+
for f in dataclasses.fields(m) if f.repr
|
|
264
|
+
])
|
|
265
|
+
meta_args.append(fr'{restify(type(m), mode)}\ ({d_fields})')
|
|
266
|
+
else:
|
|
267
|
+
meta_args.append(repr(m))
|
|
268
|
+
meta = ', '.join(meta_args)
|
|
271
269
|
if sys.version_info[:2] <= (3, 11):
|
|
272
270
|
# Hardcoded to fix errors on Python 3.11 and earlier.
|
|
273
271
|
return fr':py:class:`~typing.Annotated`\ [{args}, {meta}]'
|
|
274
272
|
return (f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
275
273
|
fr'\ [{args}, {meta}]')
|
|
276
|
-
elif
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
280
|
-
return f':py:class:`{cls.__name__}`'
|
|
281
|
-
elif UnionType and isinstance(cls, UnionType):
|
|
274
|
+
elif isinstance(cls, NewType):
|
|
275
|
+
return f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`' # type: ignore[attr-defined]
|
|
276
|
+
elif isinstance(cls, types.UnionType):
|
|
282
277
|
# Union types (PEP 585) retain their definition order when they
|
|
283
278
|
# are printed natively and ``None``-like types are kept as is.
|
|
284
279
|
return ' | '.join(restify(a, mode) for a in cls.__args__)
|
|
@@ -290,23 +285,18 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
290
285
|
concatenated_args = ', '.join(restify(arg, mode) for arg in cls.__args__)
|
|
291
286
|
return fr':py:class:`{cls.__name__}`\ [{concatenated_args}]'
|
|
292
287
|
return f':py:class:`{cls.__name__}`'
|
|
293
|
-
elif (
|
|
288
|
+
elif (isgenericalias(cls)
|
|
294
289
|
and cls_module_is_typing
|
|
295
290
|
and cls.__origin__ is Union):
|
|
296
291
|
# *cls* is defined in ``typing``, and thus ``__args__`` must exist
|
|
297
292
|
return ' | '.join(restify(a, mode) for a in cls.__args__)
|
|
298
|
-
elif
|
|
299
|
-
# A generic alias always has an __origin__, but it is difficult to
|
|
300
|
-
# use a type guard on inspect.isgenericalias()
|
|
301
|
-
# (ideally, we would use ``TypeIs`` introduced in Python 3.13).
|
|
302
|
-
cls_name = _typing_internal_name(cls)
|
|
303
|
-
|
|
293
|
+
elif isgenericalias(cls):
|
|
304
294
|
if isinstance(cls.__origin__, typing._SpecialForm):
|
|
305
295
|
# ClassVar; Concatenate; Final; Literal; Unpack; TypeGuard; TypeIs
|
|
306
296
|
# Required/NotRequired
|
|
307
297
|
text = restify(cls.__origin__, mode)
|
|
308
|
-
elif
|
|
309
|
-
text = f':py:class:`{module_prefix}{cls.__module__}.{
|
|
298
|
+
elif cls.__name__:
|
|
299
|
+
text = f':py:class:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
310
300
|
else:
|
|
311
301
|
text = restify(cls.__origin__, mode)
|
|
312
302
|
|
|
@@ -319,14 +309,14 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
319
309
|
|
|
320
310
|
# Callable has special formatting
|
|
321
311
|
if (
|
|
322
|
-
(cls_module_is_typing and
|
|
312
|
+
(cls_module_is_typing and cls.__name__ == 'Callable')
|
|
323
313
|
or (cls.__module__ == 'collections.abc' and cls.__name__ == 'Callable')
|
|
324
314
|
):
|
|
325
315
|
args = ', '.join(restify(a, mode) for a in __args__[:-1])
|
|
326
316
|
returns = restify(__args__[-1], mode)
|
|
327
317
|
return fr'{text}\ [[{args}], {returns}]'
|
|
328
318
|
|
|
329
|
-
if cls_module_is_typing and
|
|
319
|
+
if cls_module_is_typing and cls.__origin__.__name__ == 'Literal':
|
|
330
320
|
args = ', '.join(_format_literal_arg_restify(a, mode=mode)
|
|
331
321
|
for a in cls.__args__)
|
|
332
322
|
return fr'{text}\ [{args}]'
|
|
@@ -335,8 +325,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
335
325
|
args = ', '.join(restify(a, mode) for a in __args__)
|
|
336
326
|
return fr'{text}\ [{args}]'
|
|
337
327
|
elif isinstance(cls, typing._SpecialForm):
|
|
338
|
-
|
|
339
|
-
return f':py:obj:`~{cls.__module__}.{cls_name}`'
|
|
328
|
+
return f':py:obj:`~{cls.__module__}.{cls.__name__}`' # type: ignore[attr-defined]
|
|
340
329
|
elif sys.version_info[:2] >= (3, 11) and cls is typing.Any:
|
|
341
330
|
# handle bpo-46998
|
|
342
331
|
return f':py:obj:`~{cls.__module__}.{cls.__name__}`'
|
|
@@ -348,7 +337,7 @@ def restify(cls: Any, mode: _RestifyMode = 'fully-qualified-except-typing') -> s
|
|
|
348
337
|
# not a class (ex. TypeVar) but should have a __name__
|
|
349
338
|
return f':py:obj:`{module_prefix}{cls.__module__}.{cls.__name__}`'
|
|
350
339
|
except (AttributeError, TypeError):
|
|
351
|
-
return
|
|
340
|
+
return object_description(cls)
|
|
352
341
|
|
|
353
342
|
|
|
354
343
|
def _format_literal_arg_restify(arg: Any, /, *, mode: str) -> str:
|
|
@@ -383,7 +372,6 @@ def stringify_annotation(
|
|
|
383
372
|
Show the module name and qualified name of the annotation.
|
|
384
373
|
"""
|
|
385
374
|
from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading
|
|
386
|
-
from sphinx.util.inspect import isNewType # lazy loading
|
|
387
375
|
|
|
388
376
|
valid_modes = {'fully-qualified-except-typing', 'fully-qualified', 'smart'}
|
|
389
377
|
if mode not in valid_modes:
|
|
@@ -392,7 +380,7 @@ def stringify_annotation(
|
|
|
392
380
|
raise ValueError(msg)
|
|
393
381
|
|
|
394
382
|
# things that are not types
|
|
395
|
-
if annotation is None or annotation == NoneType:
|
|
383
|
+
if annotation is None or annotation == types.NoneType:
|
|
396
384
|
return 'None'
|
|
397
385
|
if annotation is Ellipsis:
|
|
398
386
|
return '...'
|
|
@@ -418,18 +406,15 @@ def stringify_annotation(
|
|
|
418
406
|
if annotation_module_is_typing and mode in {'fully-qualified-except-typing', 'smart'}:
|
|
419
407
|
return annotation_name
|
|
420
408
|
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
421
|
-
elif
|
|
422
|
-
|
|
423
|
-
# newtypes have correct module info since Python 3.10+
|
|
424
|
-
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
425
|
-
return annotation_name
|
|
409
|
+
elif isinstance(annotation, NewType):
|
|
410
|
+
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
426
411
|
elif ismockmodule(annotation):
|
|
427
412
|
return module_prefix + annotation_name
|
|
428
413
|
elif ismock(annotation):
|
|
429
414
|
return module_prefix + f'{annotation_module}.{annotation_name}'
|
|
430
415
|
elif is_invalid_builtin_class(annotation):
|
|
431
416
|
return module_prefix + _INVALID_BUILTIN_CLASSES[annotation]
|
|
432
|
-
elif _is_annotated_form(annotation): # for
|
|
417
|
+
elif _is_annotated_form(annotation): # for py310+
|
|
433
418
|
pass
|
|
434
419
|
elif annotation_module == 'builtins' and annotation_qualname:
|
|
435
420
|
args = getattr(annotation, '__args__', None)
|
|
@@ -463,8 +448,8 @@ def stringify_annotation(
|
|
|
463
448
|
# handle ForwardRefs
|
|
464
449
|
qualname = annotation_forward_arg
|
|
465
450
|
else:
|
|
466
|
-
if
|
|
467
|
-
qualname =
|
|
451
|
+
if annotation_name:
|
|
452
|
+
qualname = annotation_name
|
|
468
453
|
elif annotation_qualname:
|
|
469
454
|
qualname = annotation_qualname
|
|
470
455
|
else:
|
|
@@ -478,7 +463,7 @@ def stringify_annotation(
|
|
|
478
463
|
elif hasattr(annotation, '__origin__'):
|
|
479
464
|
# instantiated generic provided by a user
|
|
480
465
|
qualname = stringify_annotation(annotation.__origin__, mode)
|
|
481
|
-
elif
|
|
466
|
+
elif isinstance(annotation, types.UnionType):
|
|
482
467
|
qualname = 'types.UnionType'
|
|
483
468
|
else:
|
|
484
469
|
# we weren't able to extract the base type, appending arguments would
|
|
@@ -488,7 +473,7 @@ def stringify_annotation(
|
|
|
488
473
|
# Process the generic arguments (if any).
|
|
489
474
|
# They must be a list or a tuple, otherwise they are considered 'broken'.
|
|
490
475
|
annotation_args = getattr(annotation, '__args__', ())
|
|
491
|
-
if annotation_args and isinstance(annotation_args,
|
|
476
|
+
if annotation_args and isinstance(annotation_args, list | tuple):
|
|
492
477
|
if (
|
|
493
478
|
qualname in {'Union', 'types.UnionType'}
|
|
494
479
|
and all(getattr(a, '__origin__', ...) is typing.Literal for a in annotation_args)
|
|
@@ -508,9 +493,22 @@ def stringify_annotation(
|
|
|
508
493
|
args = ', '.join(_format_literal_arg_stringify(a, mode=mode)
|
|
509
494
|
for a in annotation_args)
|
|
510
495
|
return f'{module_prefix}Literal[{args}]'
|
|
511
|
-
elif _is_annotated_form(annotation): # for
|
|
496
|
+
elif _is_annotated_form(annotation): # for py310+
|
|
512
497
|
args = stringify_annotation(annotation_args[0], mode)
|
|
513
|
-
|
|
498
|
+
meta_args = []
|
|
499
|
+
for m in annotation.__metadata__:
|
|
500
|
+
if isinstance(m, type):
|
|
501
|
+
meta_args.append(stringify_annotation(m, mode))
|
|
502
|
+
elif dataclasses.is_dataclass(m):
|
|
503
|
+
# use stringify_annotation for the repr of field values rather than repr
|
|
504
|
+
d_fields = ', '.join([
|
|
505
|
+
f"{f.name}={stringify_annotation(getattr(m, f.name), mode)}"
|
|
506
|
+
for f in dataclasses.fields(m) if f.repr
|
|
507
|
+
])
|
|
508
|
+
meta_args.append(f'{stringify_annotation(type(m), mode)}({d_fields})')
|
|
509
|
+
else:
|
|
510
|
+
meta_args.append(repr(m))
|
|
511
|
+
meta = ', '.join(meta_args)
|
|
514
512
|
if sys.version_info[:2] <= (3, 11):
|
|
515
513
|
if mode == 'fully-qualified-except-typing':
|
|
516
514
|
return f'Annotated[{args}, {meta}]'
|
|
@@ -542,7 +540,6 @@ def _format_literal_arg_stringify(arg: Any, /, *, mode: str) -> str:
|
|
|
542
540
|
|
|
543
541
|
# deprecated name -> (object to return, canonical path or empty string, removal version)
|
|
544
542
|
_DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = {
|
|
545
|
-
'stringify': (stringify_annotation, 'sphinx.util.typing.stringify_annotation', (8, 0)),
|
|
546
543
|
}
|
|
547
544
|
|
|
548
545
|
|
sphinx/writers/html.py
CHANGED
|
@@ -20,7 +20,7 @@ HTMLTranslator = HTML5Translator
|
|
|
20
20
|
# https://www.arnebrodowski.de/blog/write-your-own-restructuredtext-writer.html
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
class HTMLWriter(Writer):
|
|
23
|
+
class HTMLWriter(Writer): # type: ignore[misc]
|
|
24
24
|
|
|
25
25
|
# override embed-stylesheet default value to False.
|
|
26
26
|
settings_default_overrides = {"embed_stylesheet": False}
|
sphinx/writers/html5.py
CHANGED
|
@@ -43,7 +43,7 @@ def multiply_length(length: str, scale: int) -> str:
|
|
|
43
43
|
return f"{int(result)}{unit}"
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class HTML5Translator(SphinxTranslator, BaseTranslator):
|
|
46
|
+
class HTML5Translator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
47
47
|
"""
|
|
48
48
|
Our custom HTML translator.
|
|
49
49
|
"""
|
sphinx/writers/latex.py
CHANGED
|
@@ -66,7 +66,7 @@ class UnsupportedError(SphinxError):
|
|
|
66
66
|
category = 'Markup is unsupported in LaTeX'
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class LaTeXWriter(writers.Writer):
|
|
69
|
+
class LaTeXWriter(writers.Writer): # type: ignore[misc]
|
|
70
70
|
|
|
71
71
|
supported = ('sphinxlatex',)
|
|
72
72
|
|
|
@@ -1369,7 +1369,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
1369
1369
|
not isinstance(node.parent[index - 1], nodes.compound)):
|
|
1370
1370
|
# insert blank line, if the paragraph follows a non-paragraph node in a compound
|
|
1371
1371
|
self.body.append(r'\noindent' + CR)
|
|
1372
|
-
elif index == 1 and isinstance(node.parent,
|
|
1372
|
+
elif index == 1 and isinstance(node.parent, nodes.footnote | footnotetext):
|
|
1373
1373
|
# don't insert blank line, if the paragraph is second child of a footnote
|
|
1374
1374
|
# (first one is label node)
|
|
1375
1375
|
pass
|
|
@@ -2081,7 +2081,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2081
2081
|
done = 0
|
|
2082
2082
|
if len(node.children) == 1:
|
|
2083
2083
|
child = node.children[0]
|
|
2084
|
-
if isinstance(child,
|
|
2084
|
+
if isinstance(child, nodes.bullet_list | nodes.enumerated_list):
|
|
2085
2085
|
done = 1
|
|
2086
2086
|
if not done:
|
|
2087
2087
|
self.body.append(r'\begin{quote}' + CR)
|
|
@@ -2092,7 +2092,7 @@ class LaTeXTranslator(SphinxTranslator):
|
|
|
2092
2092
|
done = 0
|
|
2093
2093
|
if len(node.children) == 1:
|
|
2094
2094
|
child = node.children[0]
|
|
2095
|
-
if isinstance(child,
|
|
2095
|
+
if isinstance(child, nodes.bullet_list | nodes.enumerated_list):
|
|
2096
2096
|
done = 1
|
|
2097
2097
|
if not done:
|
|
2098
2098
|
self.body.append(r'\end{quote}' + CR)
|
sphinx/writers/manpage.py
CHANGED
|
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class ManualPageWriter(Writer):
|
|
27
|
+
class ManualPageWriter(Writer): # type: ignore[misc]
|
|
28
28
|
def __init__(self, builder: Builder) -> None:
|
|
29
29
|
super().__init__()
|
|
30
30
|
self.builder = builder
|
|
@@ -70,7 +70,7 @@ class NestedInlineTransform:
|
|
|
70
70
|
node.parent.remove(node)
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
class ManualPageTranslator(SphinxTranslator, BaseTranslator):
|
|
73
|
+
class ManualPageTranslator(SphinxTranslator, BaseTranslator): # type: ignore[misc]
|
|
74
74
|
"""
|
|
75
75
|
Custom man page translator.
|
|
76
76
|
"""
|
sphinx/writers/texinfo.py
CHANGED
|
@@ -105,7 +105,7 @@ def smart_capwords(s: str, sep: str | None = None) -> str:
|
|
|
105
105
|
return (sep or ' ').join(words)
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
class TexinfoWriter(writers.Writer):
|
|
108
|
+
class TexinfoWriter(writers.Writer): # type: ignore[misc]
|
|
109
109
|
"""Texinfo writer for generating Texinfo documents."""
|
|
110
110
|
|
|
111
111
|
supported = ('texinfo', 'texi')
|
|
@@ -297,7 +297,7 @@ class TexinfoTranslator(SphinxTranslator):
|
|
|
297
297
|
# try to find a suitable "Top" node
|
|
298
298
|
title = self.document.next_node(nodes.title)
|
|
299
299
|
top = title.parent if title else self.document
|
|
300
|
-
if not isinstance(top,
|
|
300
|
+
if not isinstance(top, nodes.document | nodes.section):
|
|
301
301
|
top = self.document
|
|
302
302
|
if top is not self.document:
|
|
303
303
|
entries = node_menus[top['node_name']]
|
|
@@ -625,7 +625,7 @@ class TexinfoTranslator(SphinxTranslator):
|
|
|
625
625
|
parent = node.parent
|
|
626
626
|
if isinstance(parent, nodes.table):
|
|
627
627
|
return
|
|
628
|
-
if isinstance(parent,
|
|
628
|
+
if isinstance(parent, nodes.Admonition | nodes.sidebar | nodes.topic):
|
|
629
629
|
raise nodes.SkipNode
|
|
630
630
|
if not isinstance(parent, nodes.section):
|
|
631
631
|
logger.warning(__('encountered title node not in section, topic, table, '
|
|
@@ -694,7 +694,7 @@ class TexinfoTranslator(SphinxTranslator):
|
|
|
694
694
|
def visit_reference(self, node: Element) -> None:
|
|
695
695
|
# an xref's target is displayed in Info so we ignore a few
|
|
696
696
|
# cases for the sake of appearance
|
|
697
|
-
if isinstance(node.parent,
|
|
697
|
+
if isinstance(node.parent, nodes.title | addnodes.desc_type):
|
|
698
698
|
return
|
|
699
699
|
if len(node) != 0 and isinstance(node[0], nodes.image):
|
|
700
700
|
return
|
|
@@ -987,7 +987,7 @@ class TexinfoTranslator(SphinxTranslator):
|
|
|
987
987
|
self.add_anchor(id, node)
|
|
988
988
|
# anchors and indexes need to go in front
|
|
989
989
|
for n in node[::]:
|
|
990
|
-
if isinstance(n,
|
|
990
|
+
if isinstance(n, addnodes.index | nodes.target):
|
|
991
991
|
n.walkabout(self)
|
|
992
992
|
node.remove(n)
|
|
993
993
|
self.body.append('\n%s ' % self.at_item_x)
|
sphinx/writers/text.py
CHANGED
|
@@ -6,7 +6,7 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import textwrap
|
|
8
8
|
from collections.abc import Iterable, Iterator, Sequence
|
|
9
|
-
from itertools import chain, groupby
|
|
9
|
+
from itertools import chain, groupby, pairwise
|
|
10
10
|
from typing import TYPE_CHECKING, Any, cast
|
|
11
11
|
|
|
12
12
|
from docutils import nodes, writers
|
|
@@ -221,10 +221,10 @@ class Table:
|
|
|
221
221
|
tail = "+" if out[-1][0] == "-" else "|"
|
|
222
222
|
glue = [
|
|
223
223
|
"+" if left[0] == "-" or right[0] == "-" else "|"
|
|
224
|
-
for left, right in
|
|
224
|
+
for left, right in pairwise(out)
|
|
225
225
|
]
|
|
226
226
|
glue.append(tail)
|
|
227
|
-
return head + "".join(chain.from_iterable(zip(out, glue)))
|
|
227
|
+
return head + "".join(chain.from_iterable(zip(out, glue, strict=False)))
|
|
228
228
|
|
|
229
229
|
for lineno, line in enumerate(self.lines):
|
|
230
230
|
if self.separator and lineno == self.separator:
|
|
@@ -356,7 +356,7 @@ def my_wrap(text: str, width: int = MAXWIDTH, **kwargs: Any) -> list[str]:
|
|
|
356
356
|
return w.wrap(text)
|
|
357
357
|
|
|
358
358
|
|
|
359
|
-
class TextWriter(writers.Writer):
|
|
359
|
+
class TextWriter(writers.Writer): # type: ignore[misc]
|
|
360
360
|
supported = ('text',)
|
|
361
361
|
settings_spec = ('No options here.', '', ())
|
|
362
362
|
settings_defaults: dict[str, Any] = {}
|
sphinx/writers/xml.py
CHANGED
|
@@ -10,7 +10,7 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from sphinx.builders import Builder
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class XMLWriter(BaseXMLWriter):
|
|
13
|
+
class XMLWriter(BaseXMLWriter): # type: ignore[misc]
|
|
14
14
|
output: str
|
|
15
15
|
|
|
16
16
|
def __init__(self, builder: Builder) -> None:
|
|
@@ -29,7 +29,7 @@ class XMLWriter(BaseXMLWriter):
|
|
|
29
29
|
return super().translate()
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
class PseudoXMLWriter(BaseXMLWriter):
|
|
32
|
+
class PseudoXMLWriter(BaseXMLWriter): # type: ignore[misc]
|
|
33
33
|
|
|
34
34
|
supported = ('pprint', 'pformat', 'pseudoxml')
|
|
35
35
|
"""Formats this writer supports."""
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: Sphinx
|
|
3
|
-
Version:
|
|
3
|
+
Version: 8.0.0rc1
|
|
4
4
|
Summary: Python documentation generator
|
|
5
5
|
Author-email: Georg Brandl <georg@python.org>
|
|
6
|
-
Requires-Python: >=3.
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/x-rst
|
|
8
8
|
Classifier: Development Status :: 5 - Production/Stable
|
|
9
9
|
Classifier: Environment :: Console
|
|
@@ -18,7 +18,6 @@ Classifier: Operating System :: OS Independent
|
|
|
18
18
|
Classifier: Programming Language :: Python
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -57,17 +56,19 @@ Requires-Dist: alabaster~=0.7.14
|
|
|
57
56
|
Requires-Dist: imagesize>=1.3
|
|
58
57
|
Requires-Dist: requests>=2.30.0
|
|
59
58
|
Requires-Dist: packaging>=23.0
|
|
60
|
-
Requires-Dist: importlib-metadata>=6.0; python_version < '3.10'
|
|
61
59
|
Requires-Dist: tomli>=2; python_version < '3.11'
|
|
62
60
|
Requires-Dist: colorama>=0.4.6; sys_platform == 'win32'
|
|
63
61
|
Requires-Dist: sphinxcontrib-websupport ; extra == "docs"
|
|
64
62
|
Requires-Dist: flake8>=6.0 ; extra == "lint"
|
|
65
|
-
Requires-Dist: ruff==0.5.
|
|
66
|
-
Requires-Dist: mypy==1.
|
|
63
|
+
Requires-Dist: ruff==0.5.4 ; extra == "lint"
|
|
64
|
+
Requires-Dist: mypy==1.11.0 ; extra == "lint"
|
|
67
65
|
Requires-Dist: sphinx-lint>=0.9 ; extra == "lint"
|
|
68
|
-
Requires-Dist: types-
|
|
66
|
+
Requires-Dist: types-colorama==0.4.15.20240311 ; extra == "lint"
|
|
67
|
+
Requires-Dist: types-defusedxml==0.7.0.20240218 ; extra == "lint"
|
|
68
|
+
Requires-Dist: types-docutils==0.21.0.20240724 ; extra == "lint"
|
|
69
|
+
Requires-Dist: types-Pillow==10.2.0.20240520 ; extra == "lint"
|
|
70
|
+
Requires-Dist: types-Pygments==2.18.0.20240506 ; extra == "lint"
|
|
69
71
|
Requires-Dist: types-requests>=2.30.0 ; extra == "lint"
|
|
70
|
-
Requires-Dist: importlib-metadata>=6.0 ; extra == "lint"
|
|
71
72
|
Requires-Dist: tomli>=2 ; extra == "lint"
|
|
72
73
|
Requires-Dist: pytest>=6.0 ; extra == "lint"
|
|
73
74
|
Requires-Dist: pytest>=8.0 ; extra == "test"
|
|
@@ -134,7 +135,7 @@ Installation
|
|
|
134
135
|
The following command installs Sphinx from the `Python Package Index`_. You will
|
|
135
136
|
need a working installation of Python and pip.
|
|
136
137
|
|
|
137
|
-
.. code-block::
|
|
138
|
+
.. code-block:: shell
|
|
138
139
|
|
|
139
140
|
pip install -U sphinx
|
|
140
141
|
|