Sphinx 8.1.3__py3-none-any.whl → 8.2.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +48 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +114 -57
- sphinx/domains/python/_object.py +151 -67
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +21 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +66 -0
- sphinx/ext/autodoc/__init__.py +829 -480
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +271 -143
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +61 -50
- sphinx/writers/latex.py +80 -65
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +44 -45
- sphinx/writers/text.py +48 -30
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/entry_points.txt +0 -0
sphinx/util/inspect.py
CHANGED
|
@@ -24,23 +24,28 @@ from sphinx.util import logging
|
|
|
24
24
|
from sphinx.util.typing import stringify_annotation
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
|
-
from collections.abc import Callable, Sequence
|
|
27
|
+
from collections.abc import Callable, Iterator, Sequence
|
|
28
28
|
from inspect import _ParameterKind
|
|
29
29
|
from types import MethodType, ModuleType
|
|
30
30
|
from typing import Final, Protocol, TypeAlias
|
|
31
31
|
|
|
32
32
|
from typing_extensions import TypeIs
|
|
33
33
|
|
|
34
|
+
from sphinx.util.typing import _StringifyMode
|
|
35
|
+
|
|
34
36
|
class _SupportsGet(Protocol):
|
|
35
|
-
def __get__(self,
|
|
37
|
+
def __get__(self, instance: Any, owner: type | None = ..., /) -> Any: ...
|
|
36
38
|
|
|
37
39
|
class _SupportsSet(Protocol):
|
|
38
40
|
# instance and value are contravariants but we do not need that precision
|
|
39
|
-
def __set__(self,
|
|
41
|
+
def __set__(self, instance: Any, value: Any, /) -> None: ...
|
|
40
42
|
|
|
41
43
|
class _SupportsDelete(Protocol):
|
|
42
44
|
# instance is contravariant but we do not need that precision
|
|
43
|
-
def __delete__(self,
|
|
45
|
+
def __delete__(self, instance: Any, /) -> None: ...
|
|
46
|
+
|
|
47
|
+
class _AttrGetter(Protocol):
|
|
48
|
+
def __call__(self, obj: Any, name: str, default: Any = ..., /) -> Any: ...
|
|
44
49
|
|
|
45
50
|
_RoutineType: TypeAlias = (
|
|
46
51
|
types.FunctionType
|
|
@@ -52,7 +57,9 @@ if TYPE_CHECKING:
|
|
|
52
57
|
| types.MethodDescriptorType
|
|
53
58
|
| types.ClassMethodDescriptorType
|
|
54
59
|
)
|
|
55
|
-
_SignatureType: TypeAlias =
|
|
60
|
+
_SignatureType: TypeAlias = (
|
|
61
|
+
Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any]
|
|
62
|
+
)
|
|
56
63
|
|
|
57
64
|
logger = logging.getLogger(__name__)
|
|
58
65
|
|
|
@@ -163,7 +170,7 @@ def getorigbases(obj: Any) -> tuple[Any, ...] | None:
|
|
|
163
170
|
return None
|
|
164
171
|
|
|
165
172
|
# Get __orig_bases__ from obj.__dict__ to avoid accessing the parent's __orig_bases__.
|
|
166
|
-
#
|
|
173
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/9607
|
|
167
174
|
__dict__ = safe_getattr(obj, '__dict__', {})
|
|
168
175
|
__orig_bases__ = __dict__.get('__orig_bases__')
|
|
169
176
|
if isinstance(__orig_bases__, tuple) and len(__orig_bases__) > 0:
|
|
@@ -216,16 +223,14 @@ def unpartial(obj: Any) -> Any:
|
|
|
216
223
|
return obj
|
|
217
224
|
|
|
218
225
|
|
|
219
|
-
def ispartial(obj: Any) -> TypeIs[partial | partialmethod]:
|
|
226
|
+
def ispartial(obj: Any) -> TypeIs[partial[Any] | partialmethod[Any]]:
|
|
220
227
|
"""Check if the object is a partial function or method."""
|
|
221
228
|
return isinstance(obj, partial | partialmethod)
|
|
222
229
|
|
|
223
230
|
|
|
224
231
|
def isclassmethod(
|
|
225
|
-
obj: Any,
|
|
226
|
-
|
|
227
|
-
name: str | None = None,
|
|
228
|
-
) -> TypeIs[classmethod]:
|
|
232
|
+
obj: Any, cls: Any = None, name: str | None = None
|
|
233
|
+
) -> TypeIs[classmethod[Any, Any, Any]]:
|
|
229
234
|
"""Check if the object is a :class:`classmethod`."""
|
|
230
235
|
if isinstance(obj, classmethod):
|
|
231
236
|
return True
|
|
@@ -241,14 +246,71 @@ def isclassmethod(
|
|
|
241
246
|
return False
|
|
242
247
|
|
|
243
248
|
|
|
249
|
+
def is_classmethod_descriptor(
|
|
250
|
+
obj: Any, cls: Any = None, name: str | None = None
|
|
251
|
+
) -> TypeIs[types.ClassMethodDescriptorType]:
|
|
252
|
+
"""Check if the object is a :class:`~types.ClassMethodDescriptorType`.
|
|
253
|
+
|
|
254
|
+
This check is stricter than :func:`is_builtin_classmethod_like` as
|
|
255
|
+
a classmethod descriptor does not have a ``__func__`` attribute.
|
|
256
|
+
"""
|
|
257
|
+
if isinstance(obj, types.ClassMethodDescriptorType):
|
|
258
|
+
return True
|
|
259
|
+
if cls and name:
|
|
260
|
+
# trace __mro__ if the method is defined in parent class
|
|
261
|
+
sentinel = object()
|
|
262
|
+
for basecls in getmro(cls):
|
|
263
|
+
meth = basecls.__dict__.get(name, sentinel)
|
|
264
|
+
if meth is not sentinel:
|
|
265
|
+
return isinstance(meth, types.ClassMethodDescriptorType)
|
|
266
|
+
return False
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def is_builtin_classmethod_like(
|
|
270
|
+
obj: Any, cls: Any = None, name: str | None = None
|
|
271
|
+
) -> bool:
|
|
272
|
+
"""Check if the object looks like a class method implemented in C.
|
|
273
|
+
|
|
274
|
+
This is equivalent to test that *obj* is a class method descriptor
|
|
275
|
+
or is a built-in object with a ``__self__`` attribute that is a type,
|
|
276
|
+
or that ``parent_class.__dict__[name]`` satisfies those properties
|
|
277
|
+
for some parent class in *cls* MRO.
|
|
278
|
+
"""
|
|
279
|
+
if is_classmethod_descriptor(obj, cls, name):
|
|
280
|
+
return True
|
|
281
|
+
if (
|
|
282
|
+
isbuiltin(obj)
|
|
283
|
+
and getattr(obj, '__self__', None) is not None
|
|
284
|
+
and isclass(obj.__self__)
|
|
285
|
+
):
|
|
286
|
+
return True
|
|
287
|
+
if cls and name:
|
|
288
|
+
# trace __mro__ if the method is defined in parent class
|
|
289
|
+
sentinel = object()
|
|
290
|
+
for basecls in getmro(cls):
|
|
291
|
+
meth = basecls.__dict__.get(name, sentinel)
|
|
292
|
+
if meth is not sentinel:
|
|
293
|
+
return is_classmethod_descriptor(meth, None, None) or (
|
|
294
|
+
isbuiltin(meth)
|
|
295
|
+
and getattr(meth, '__self__', None) is not None
|
|
296
|
+
and isclass(meth.__self__)
|
|
297
|
+
)
|
|
298
|
+
return False
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def is_classmethod_like(obj: Any, cls: Any = None, name: str | None = None) -> bool:
|
|
302
|
+
"""Check if the object looks like a class method."""
|
|
303
|
+
return isclassmethod(obj, cls, name) or is_builtin_classmethod_like(obj, cls, name)
|
|
304
|
+
|
|
305
|
+
|
|
244
306
|
def isstaticmethod(
|
|
245
|
-
obj: Any,
|
|
246
|
-
|
|
247
|
-
name: str | None = None,
|
|
248
|
-
) -> TypeIs[staticmethod]:
|
|
307
|
+
obj: Any, cls: Any = None, name: str | None = None
|
|
308
|
+
) -> TypeIs[staticmethod[Any, Any]]:
|
|
249
309
|
"""Check if the object is a :class:`staticmethod`."""
|
|
250
310
|
if isinstance(obj, staticmethod):
|
|
251
311
|
return True
|
|
312
|
+
# Unlike built-in class methods, built-in static methods
|
|
313
|
+
# satisfy "isinstance(cls.__dict__[name], staticmethod)".
|
|
252
314
|
if cls and name:
|
|
253
315
|
# trace __mro__ if the method is defined in parent class
|
|
254
316
|
sentinel = object()
|
|
@@ -327,7 +389,7 @@ def is_singledispatch_function(obj: Any) -> bool:
|
|
|
327
389
|
)
|
|
328
390
|
|
|
329
391
|
|
|
330
|
-
def is_singledispatch_method(obj: Any) -> TypeIs[singledispatchmethod]:
|
|
392
|
+
def is_singledispatch_method(obj: Any) -> TypeIs[singledispatchmethod[Any]]:
|
|
331
393
|
"""Check if the object is a :class:`~functools.singledispatchmethod`."""
|
|
332
394
|
return isinstance(obj, singledispatchmethod)
|
|
333
395
|
|
|
@@ -362,7 +424,9 @@ def isroutine(obj: Any) -> TypeIs[_RoutineType]:
|
|
|
362
424
|
return inspect.isroutine(unpartial(obj))
|
|
363
425
|
|
|
364
426
|
|
|
365
|
-
def iscoroutinefunction(
|
|
427
|
+
def iscoroutinefunction(
|
|
428
|
+
obj: Any,
|
|
429
|
+
) -> TypeIs[Callable[..., types.CoroutineType[Any, Any, Any]]]:
|
|
366
430
|
"""Check if the object is a :external+python:term:`coroutine` function."""
|
|
367
431
|
obj = unwrap_all(obj, stop=_is_wrapped_coroutine)
|
|
368
432
|
return inspect.iscoroutinefunction(obj)
|
|
@@ -377,7 +441,7 @@ def _is_wrapped_coroutine(obj: Any) -> bool:
|
|
|
377
441
|
return hasattr(obj, '__wrapped__')
|
|
378
442
|
|
|
379
443
|
|
|
380
|
-
def isproperty(obj: Any) -> TypeIs[property | cached_property]:
|
|
444
|
+
def isproperty(obj: Any) -> TypeIs[property | cached_property[Any]]:
|
|
381
445
|
"""Check if the object is property (possibly cached)."""
|
|
382
446
|
return isinstance(obj, property | cached_property)
|
|
383
447
|
|
|
@@ -523,6 +587,9 @@ class DefaultValue:
|
|
|
523
587
|
def __eq__(self, other: object) -> bool:
|
|
524
588
|
return self.value == other
|
|
525
589
|
|
|
590
|
+
def __hash__(self) -> int:
|
|
591
|
+
return hash(self.value)
|
|
592
|
+
|
|
526
593
|
def __repr__(self) -> str:
|
|
527
594
|
return self.value
|
|
528
595
|
|
|
@@ -540,14 +607,14 @@ class TypeAliasForwardRef:
|
|
|
540
607
|
# Dummy method to imitate special typing classes
|
|
541
608
|
pass
|
|
542
609
|
|
|
543
|
-
def __eq__(self, other:
|
|
610
|
+
def __eq__(self, other: object) -> bool:
|
|
544
611
|
return self.name == other
|
|
545
612
|
|
|
546
613
|
def __hash__(self) -> int:
|
|
547
614
|
return hash(self.name)
|
|
548
615
|
|
|
549
616
|
def __repr__(self) -> str:
|
|
550
|
-
return self.name
|
|
617
|
+
return f'{self.__class__.__name__}({self.name!r})'
|
|
551
618
|
|
|
552
619
|
|
|
553
620
|
class TypeAliasModule:
|
|
@@ -583,7 +650,7 @@ class TypeAliasModule:
|
|
|
583
650
|
return getattr(self.__module, name)
|
|
584
651
|
|
|
585
652
|
|
|
586
|
-
class TypeAliasNamespace(
|
|
653
|
+
class TypeAliasNamespace(Mapping[str, Any]):
|
|
587
654
|
"""Pseudo namespace class for :confval:`autodoc_type_aliases`.
|
|
588
655
|
|
|
589
656
|
Useful for looking up nested objects via ``namespace.foo.bar.Class``.
|
|
@@ -593,7 +660,9 @@ class TypeAliasNamespace(dict[str, Any]):
|
|
|
593
660
|
super().__init__()
|
|
594
661
|
self.__mapping = mapping
|
|
595
662
|
|
|
596
|
-
def __getitem__(self, key:
|
|
663
|
+
def __getitem__(self, key: object) -> Any:
|
|
664
|
+
if not isinstance(key, str):
|
|
665
|
+
raise KeyError
|
|
597
666
|
if key in self.__mapping:
|
|
598
667
|
# exactly matched
|
|
599
668
|
return TypeAliasForwardRef(self.__mapping[key])
|
|
@@ -606,6 +675,22 @@ class TypeAliasNamespace(dict[str, Any]):
|
|
|
606
675
|
else:
|
|
607
676
|
raise KeyError
|
|
608
677
|
|
|
678
|
+
def __contains__(self, key: object) -> bool:
|
|
679
|
+
if not isinstance(key, str):
|
|
680
|
+
return False
|
|
681
|
+
ns = self.__mapping
|
|
682
|
+
prefix = f'{key}.'
|
|
683
|
+
return key in ns or any(k.startswith(prefix) for k in ns)
|
|
684
|
+
|
|
685
|
+
def __iter__(self) -> Iterator[str]:
|
|
686
|
+
for k in self.__mapping:
|
|
687
|
+
yield k
|
|
688
|
+
for i in range(k.count('.')):
|
|
689
|
+
yield k.rsplit('.', i + 1)[0]
|
|
690
|
+
|
|
691
|
+
def __len__(self) -> int:
|
|
692
|
+
return sum(k.count('.') + 1 for k in self.__mapping)
|
|
693
|
+
|
|
609
694
|
|
|
610
695
|
def _should_unwrap(subject: _SignatureType) -> bool:
|
|
611
696
|
"""Check the function should be unwrapped on getting signature."""
|
|
@@ -624,7 +709,9 @@ def signature(
|
|
|
624
709
|
) -> Signature:
|
|
625
710
|
"""Return a Signature object for the given *subject*.
|
|
626
711
|
|
|
627
|
-
:param bound_method: Specify *subject* is a bound method or not
|
|
712
|
+
:param bound_method: Specify *subject* is a bound method or not.
|
|
713
|
+
|
|
714
|
+
When *subject* is a built-in callable, *bound_method* is ignored.
|
|
628
715
|
"""
|
|
629
716
|
if type_aliases is None:
|
|
630
717
|
type_aliases = {}
|
|
@@ -660,7 +747,10 @@ def signature(
|
|
|
660
747
|
# ForwardRef and so on.
|
|
661
748
|
pass
|
|
662
749
|
|
|
663
|
-
|
|
750
|
+
# For built-in objects, we use the signature that was specified
|
|
751
|
+
# by the extension module even if we detected the subject to be
|
|
752
|
+
# a possible bound method.
|
|
753
|
+
if bound_method and not inspect.isbuiltin(subject):
|
|
664
754
|
if inspect.ismethod(subject):
|
|
665
755
|
# ``inspect.signature()`` considers the subject is a bound method and removes
|
|
666
756
|
# first argument from signature. Therefore no skips are needed here.
|
|
@@ -673,7 +763,7 @@ def signature(
|
|
|
673
763
|
# pass an internal parameter __validate_parameters__=False to Signature
|
|
674
764
|
#
|
|
675
765
|
# For example, this helps a function having a default value `inspect._empty`.
|
|
676
|
-
#
|
|
766
|
+
# See: https://github.com/sphinx-doc/sphinx/issues/7935
|
|
677
767
|
return Signature(
|
|
678
768
|
parameters, return_annotation=return_annotation, __validate_parameters__=False
|
|
679
769
|
)
|
|
@@ -709,14 +799,20 @@ def _evaluate_forwardref(
|
|
|
709
799
|
localns: dict[str, Any] | None,
|
|
710
800
|
) -> Any:
|
|
711
801
|
"""Evaluate a forward reference."""
|
|
802
|
+
if sys.version_info[:2] >= (3, 14):
|
|
803
|
+
# https://docs.python.org/dev/library/annotationlib.html#annotationlib.ForwardRef.evaluate
|
|
804
|
+
# https://docs.python.org/dev/library/typing.html#typing.evaluate_forward_ref
|
|
805
|
+
return typing.evaluate_forward_ref(ref, globals=globalns, locals=localns)
|
|
712
806
|
if sys.version_info >= (3, 12, 4):
|
|
713
807
|
# ``type_params`` were added in 3.13 and the signature of _evaluate()
|
|
714
808
|
# is not backward-compatible (it was backported to 3.12.4, so anything
|
|
715
809
|
# before 3.12.4 still has the old signature).
|
|
716
810
|
#
|
|
717
811
|
# See: https://github.com/python/cpython/pull/118104.
|
|
718
|
-
return ref._evaluate(
|
|
719
|
-
|
|
812
|
+
return ref._evaluate(
|
|
813
|
+
globalns, localns, type_params=(), recursive_guard=frozenset()
|
|
814
|
+
) # type: ignore[call-arg]
|
|
815
|
+
return ref._evaluate(globalns, localns, recursive_guard=frozenset())
|
|
720
816
|
|
|
721
817
|
|
|
722
818
|
def _evaluate(
|
|
@@ -727,14 +823,14 @@ def _evaluate(
|
|
|
727
823
|
"""Evaluate unresolved type annotation."""
|
|
728
824
|
try:
|
|
729
825
|
if isinstance(annotation, str):
|
|
730
|
-
ref = ForwardRef(annotation
|
|
826
|
+
ref = ForwardRef(annotation)
|
|
731
827
|
annotation = _evaluate_forwardref(ref, globalns, localns)
|
|
732
828
|
|
|
733
829
|
if isinstance(annotation, ForwardRef):
|
|
734
830
|
annotation = _evaluate_forwardref(ref, globalns, localns)
|
|
735
831
|
elif isinstance(annotation, str):
|
|
736
832
|
# might be a ForwardRef'ed annotation in overloaded functions
|
|
737
|
-
ref = ForwardRef(annotation
|
|
833
|
+
ref = ForwardRef(annotation)
|
|
738
834
|
annotation = _evaluate_forwardref(ref, globalns, localns)
|
|
739
835
|
except (NameError, TypeError):
|
|
740
836
|
# failed to evaluate type. skipped.
|
|
@@ -748,6 +844,7 @@ def stringify_signature(
|
|
|
748
844
|
show_annotation: bool = True,
|
|
749
845
|
show_return_annotation: bool = True,
|
|
750
846
|
unqualified_typehints: bool = False,
|
|
847
|
+
short_literals: bool = False,
|
|
751
848
|
) -> str:
|
|
752
849
|
"""Stringify a :class:`~inspect.Signature` object.
|
|
753
850
|
|
|
@@ -755,7 +852,9 @@ def stringify_signature(
|
|
|
755
852
|
:param show_return_annotation: If enabled, show annotation of the return value
|
|
756
853
|
:param unqualified_typehints: If enabled, show annotations as unqualified
|
|
757
854
|
(ex. io.StringIO -> StringIO)
|
|
855
|
+
:param short_literals: If enabled, use short literal types.
|
|
758
856
|
"""
|
|
857
|
+
mode: _StringifyMode
|
|
759
858
|
if unqualified_typehints:
|
|
760
859
|
mode = 'smart'
|
|
761
860
|
else:
|
|
@@ -772,11 +871,11 @@ def stringify_signature(
|
|
|
772
871
|
):
|
|
773
872
|
# PEP-570: Separator for Positional Only Parameter: /
|
|
774
873
|
args.append('/')
|
|
775
|
-
if param.kind == Parameter.KEYWORD_ONLY and last_kind in
|
|
874
|
+
if param.kind == Parameter.KEYWORD_ONLY and last_kind in {
|
|
776
875
|
Parameter.POSITIONAL_OR_KEYWORD,
|
|
777
876
|
Parameter.POSITIONAL_ONLY,
|
|
778
877
|
None,
|
|
779
|
-
|
|
878
|
+
}:
|
|
780
879
|
# PEP-3102: Separator for Keyword Only Parameter: *
|
|
781
880
|
args.append('*')
|
|
782
881
|
|
|
@@ -790,7 +889,11 @@ def stringify_signature(
|
|
|
790
889
|
|
|
791
890
|
if show_annotation and param.annotation is not EMPTY:
|
|
792
891
|
arg.write(': ')
|
|
793
|
-
arg.write(
|
|
892
|
+
arg.write(
|
|
893
|
+
stringify_annotation(
|
|
894
|
+
param.annotation, mode, short_literals=short_literals
|
|
895
|
+
)
|
|
896
|
+
)
|
|
794
897
|
if param.default is not EMPTY:
|
|
795
898
|
if show_annotation and param.annotation is not EMPTY:
|
|
796
899
|
arg.write(' = ')
|
|
@@ -813,7 +916,9 @@ def stringify_signature(
|
|
|
813
916
|
):
|
|
814
917
|
return f'({concatenated_args})'
|
|
815
918
|
else:
|
|
816
|
-
retann = stringify_annotation(
|
|
919
|
+
retann = stringify_annotation(
|
|
920
|
+
sig.return_annotation, mode, short_literals=short_literals
|
|
921
|
+
)
|
|
817
922
|
return f'({concatenated_args}) -> {retann}'
|
|
818
923
|
|
|
819
924
|
|
|
@@ -821,7 +926,7 @@ def signature_from_str(signature: str) -> Signature:
|
|
|
821
926
|
"""Create a :class:`~inspect.Signature` object from a string."""
|
|
822
927
|
code = 'def func' + signature + ': pass'
|
|
823
928
|
module = ast.parse(code)
|
|
824
|
-
function = typing.cast(ast.FunctionDef, module.body[0])
|
|
929
|
+
function = typing.cast('ast.FunctionDef', module.body[0])
|
|
825
930
|
|
|
826
931
|
return signature_from_ast(function, code)
|
|
827
932
|
|
|
@@ -893,7 +998,7 @@ def _define(
|
|
|
893
998
|
|
|
894
999
|
def getdoc(
|
|
895
1000
|
obj: Any,
|
|
896
|
-
attrgetter:
|
|
1001
|
+
attrgetter: _AttrGetter = safe_getattr,
|
|
897
1002
|
allow_inherited: bool = False,
|
|
898
1003
|
cls: Any = None,
|
|
899
1004
|
name: str | None = None,
|
|
@@ -906,11 +1011,15 @@ def getdoc(
|
|
|
906
1011
|
* inherited docstring
|
|
907
1012
|
* inherited decorated methods
|
|
908
1013
|
"""
|
|
909
|
-
if cls and name and
|
|
1014
|
+
if cls and name and is_classmethod_like(obj, cls, name):
|
|
910
1015
|
for basecls in getmro(cls):
|
|
911
1016
|
meth = basecls.__dict__.get(name)
|
|
912
|
-
if
|
|
913
|
-
|
|
1017
|
+
if not meth:
|
|
1018
|
+
continue
|
|
1019
|
+
# Built-in class methods do not have '__func__'
|
|
1020
|
+
# but they may have a docstring.
|
|
1021
|
+
if hasattr(meth, '__func__') or is_classmethod_descriptor(meth):
|
|
1022
|
+
doc: str | None = getdoc(getattr(meth, '__func__', meth))
|
|
914
1023
|
if doc is not None or not allow_inherited:
|
|
915
1024
|
return doc
|
|
916
1025
|
|