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.

Files changed (193) hide show
  1. sphinx/__init__.py +8 -4
  2. sphinx/__main__.py +2 -0
  3. sphinx/_cli/__init__.py +2 -5
  4. sphinx/_cli/util/colour.py +34 -11
  5. sphinx/_cli/util/errors.py +128 -61
  6. sphinx/addnodes.py +51 -35
  7. sphinx/application.py +362 -230
  8. sphinx/builders/__init__.py +87 -64
  9. sphinx/builders/_epub_base.py +65 -56
  10. sphinx/builders/changes.py +17 -23
  11. sphinx/builders/dirhtml.py +8 -13
  12. sphinx/builders/epub3.py +70 -38
  13. sphinx/builders/gettext.py +93 -73
  14. sphinx/builders/html/__init__.py +240 -186
  15. sphinx/builders/html/_assets.py +9 -2
  16. sphinx/builders/html/_build_info.py +3 -0
  17. sphinx/builders/latex/__init__.py +64 -54
  18. sphinx/builders/latex/constants.py +14 -11
  19. sphinx/builders/latex/nodes.py +2 -0
  20. sphinx/builders/latex/theming.py +8 -9
  21. sphinx/builders/latex/transforms.py +7 -5
  22. sphinx/builders/linkcheck.py +193 -149
  23. sphinx/builders/manpage.py +17 -17
  24. sphinx/builders/singlehtml.py +28 -16
  25. sphinx/builders/texinfo.py +28 -21
  26. sphinx/builders/text.py +10 -15
  27. sphinx/builders/xml.py +10 -19
  28. sphinx/cmd/build.py +49 -119
  29. sphinx/cmd/make_mode.py +35 -31
  30. sphinx/cmd/quickstart.py +78 -62
  31. sphinx/config.py +265 -163
  32. sphinx/directives/__init__.py +51 -54
  33. sphinx/directives/admonitions.py +107 -0
  34. sphinx/directives/code.py +24 -19
  35. sphinx/directives/other.py +21 -42
  36. sphinx/directives/patches.py +28 -16
  37. sphinx/domains/__init__.py +54 -31
  38. sphinx/domains/_domains_container.py +22 -17
  39. sphinx/domains/_index.py +5 -8
  40. sphinx/domains/c/__init__.py +366 -245
  41. sphinx/domains/c/_ast.py +378 -256
  42. sphinx/domains/c/_ids.py +89 -31
  43. sphinx/domains/c/_parser.py +283 -214
  44. sphinx/domains/c/_symbol.py +269 -198
  45. sphinx/domains/changeset.py +39 -24
  46. sphinx/domains/citation.py +54 -24
  47. sphinx/domains/cpp/__init__.py +517 -362
  48. sphinx/domains/cpp/_ast.py +999 -682
  49. sphinx/domains/cpp/_ids.py +133 -65
  50. sphinx/domains/cpp/_parser.py +746 -588
  51. sphinx/domains/cpp/_symbol.py +692 -489
  52. sphinx/domains/index.py +10 -8
  53. sphinx/domains/javascript.py +152 -74
  54. sphinx/domains/math.py +48 -40
  55. sphinx/domains/python/__init__.py +402 -211
  56. sphinx/domains/python/_annotations.py +114 -57
  57. sphinx/domains/python/_object.py +151 -67
  58. sphinx/domains/rst.py +94 -49
  59. sphinx/domains/std/__init__.py +510 -249
  60. sphinx/environment/__init__.py +345 -61
  61. sphinx/environment/adapters/asset.py +7 -1
  62. sphinx/environment/adapters/indexentries.py +15 -20
  63. sphinx/environment/adapters/toctree.py +19 -9
  64. sphinx/environment/collectors/__init__.py +3 -1
  65. sphinx/environment/collectors/asset.py +18 -15
  66. sphinx/environment/collectors/dependencies.py +8 -10
  67. sphinx/environment/collectors/metadata.py +6 -4
  68. sphinx/environment/collectors/title.py +3 -1
  69. sphinx/environment/collectors/toctree.py +4 -4
  70. sphinx/errors.py +1 -3
  71. sphinx/events.py +4 -4
  72. sphinx/ext/apidoc/__init__.py +21 -0
  73. sphinx/ext/apidoc/__main__.py +9 -0
  74. sphinx/ext/apidoc/_cli.py +356 -0
  75. sphinx/ext/apidoc/_generate.py +356 -0
  76. sphinx/ext/apidoc/_shared.py +66 -0
  77. sphinx/ext/autodoc/__init__.py +829 -480
  78. sphinx/ext/autodoc/directive.py +57 -21
  79. sphinx/ext/autodoc/importer.py +184 -67
  80. sphinx/ext/autodoc/mock.py +25 -10
  81. sphinx/ext/autodoc/preserve_defaults.py +17 -9
  82. sphinx/ext/autodoc/type_comment.py +56 -29
  83. sphinx/ext/autodoc/typehints.py +49 -26
  84. sphinx/ext/autosectionlabel.py +28 -11
  85. sphinx/ext/autosummary/__init__.py +271 -143
  86. sphinx/ext/autosummary/generate.py +121 -51
  87. sphinx/ext/coverage.py +152 -91
  88. sphinx/ext/doctest.py +169 -101
  89. sphinx/ext/duration.py +12 -6
  90. sphinx/ext/extlinks.py +33 -21
  91. sphinx/ext/githubpages.py +8 -8
  92. sphinx/ext/graphviz.py +175 -109
  93. sphinx/ext/ifconfig.py +11 -6
  94. sphinx/ext/imgconverter.py +48 -25
  95. sphinx/ext/imgmath.py +127 -97
  96. sphinx/ext/inheritance_diagram.py +177 -103
  97. sphinx/ext/intersphinx/__init__.py +22 -13
  98. sphinx/ext/intersphinx/__main__.py +3 -1
  99. sphinx/ext/intersphinx/_cli.py +18 -14
  100. sphinx/ext/intersphinx/_load.py +91 -82
  101. sphinx/ext/intersphinx/_resolve.py +108 -74
  102. sphinx/ext/intersphinx/_shared.py +2 -2
  103. sphinx/ext/linkcode.py +28 -12
  104. sphinx/ext/mathjax.py +60 -29
  105. sphinx/ext/napoleon/__init__.py +19 -7
  106. sphinx/ext/napoleon/docstring.py +229 -231
  107. sphinx/ext/todo.py +44 -49
  108. sphinx/ext/viewcode.py +105 -57
  109. sphinx/extension.py +3 -1
  110. sphinx/highlighting.py +13 -7
  111. sphinx/io.py +9 -13
  112. sphinx/jinja2glue.py +29 -26
  113. sphinx/locale/__init__.py +8 -9
  114. sphinx/parsers.py +8 -7
  115. sphinx/project.py +2 -2
  116. sphinx/pycode/__init__.py +31 -21
  117. sphinx/pycode/ast.py +6 -3
  118. sphinx/pycode/parser.py +14 -8
  119. sphinx/pygments_styles.py +4 -5
  120. sphinx/registry.py +192 -92
  121. sphinx/roles.py +58 -7
  122. sphinx/search/__init__.py +75 -54
  123. sphinx/search/en.py +11 -13
  124. sphinx/search/fi.py +1 -1
  125. sphinx/search/ja.py +8 -6
  126. sphinx/search/nl.py +1 -1
  127. sphinx/search/zh.py +19 -21
  128. sphinx/testing/fixtures.py +26 -29
  129. sphinx/testing/path.py +26 -62
  130. sphinx/testing/restructuredtext.py +14 -8
  131. sphinx/testing/util.py +21 -19
  132. sphinx/texinputs/make.bat.jinja +50 -50
  133. sphinx/texinputs/sphinx.sty +4 -3
  134. sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
  135. sphinx/texinputs/sphinxlatexobjects.sty +29 -10
  136. sphinx/themes/basic/static/searchtools.js +8 -5
  137. sphinx/theming.py +49 -61
  138. sphinx/transforms/__init__.py +17 -38
  139. sphinx/transforms/compact_bullet_list.py +5 -3
  140. sphinx/transforms/i18n.py +8 -21
  141. sphinx/transforms/post_transforms/__init__.py +142 -93
  142. sphinx/transforms/post_transforms/code.py +5 -5
  143. sphinx/transforms/post_transforms/images.py +28 -24
  144. sphinx/transforms/references.py +3 -1
  145. sphinx/util/__init__.py +109 -60
  146. sphinx/util/_files.py +39 -23
  147. sphinx/util/_importer.py +4 -1
  148. sphinx/util/_inventory_file_reader.py +76 -0
  149. sphinx/util/_io.py +2 -2
  150. sphinx/util/_lines.py +6 -3
  151. sphinx/util/_pathlib.py +40 -2
  152. sphinx/util/build_phase.py +2 -0
  153. sphinx/util/cfamily.py +19 -14
  154. sphinx/util/console.py +44 -179
  155. sphinx/util/display.py +9 -10
  156. sphinx/util/docfields.py +140 -122
  157. sphinx/util/docstrings.py +1 -1
  158. sphinx/util/docutils.py +118 -77
  159. sphinx/util/fileutil.py +25 -26
  160. sphinx/util/http_date.py +2 -0
  161. sphinx/util/i18n.py +77 -64
  162. sphinx/util/images.py +8 -6
  163. sphinx/util/inspect.py +147 -38
  164. sphinx/util/inventory.py +215 -116
  165. sphinx/util/logging.py +33 -33
  166. sphinx/util/matching.py +12 -4
  167. sphinx/util/nodes.py +18 -13
  168. sphinx/util/osutil.py +38 -39
  169. sphinx/util/parallel.py +22 -13
  170. sphinx/util/parsing.py +2 -1
  171. sphinx/util/png.py +6 -2
  172. sphinx/util/requests.py +33 -2
  173. sphinx/util/rst.py +3 -2
  174. sphinx/util/tags.py +1 -1
  175. sphinx/util/template.py +18 -10
  176. sphinx/util/texescape.py +8 -6
  177. sphinx/util/typing.py +148 -122
  178. sphinx/versioning.py +3 -3
  179. sphinx/writers/html.py +3 -1
  180. sphinx/writers/html5.py +61 -50
  181. sphinx/writers/latex.py +80 -65
  182. sphinx/writers/manpage.py +19 -38
  183. sphinx/writers/texinfo.py +44 -45
  184. sphinx/writers/text.py +48 -30
  185. sphinx/writers/xml.py +11 -8
  186. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/LICENSE.rst +1 -1
  187. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/METADATA +23 -15
  188. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/RECORD +190 -186
  189. {sphinx-8.1.3.dist-info → sphinx-8.2.0rc1.dist-info}/WHEEL +1 -1
  190. sphinx/builders/html/transforms.py +0 -90
  191. sphinx/ext/apidoc.py +0 -721
  192. sphinx/util/exceptions.py +0 -74
  193. {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, __instance: Any, __owner: type | None = ...) -> Any: ... # NoQA: E704
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, __instance: Any, __value: Any) -> None: ... # NoQA: E704
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, __instance: Any) -> None: ... # NoQA: E704
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 = Callable[..., Any] | staticmethod | classmethod
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
- # refs: https://github.com/sphinx-doc/sphinx/issues/9607
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
- cls: Any = None,
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
- cls: Any = None,
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(obj: Any) -> TypeIs[Callable[..., types.CoroutineType]]:
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: Any) -> bool:
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(dict[str, Any]):
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: str) -> Any:
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
- if bound_method:
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
- # refs: https://github.com/sphinx-doc/sphinx/issues/7935
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(globalns, localns, {}, recursive_guard=frozenset()) # type: ignore[arg-type, misc]
719
- return ref._evaluate(globalns, localns, frozenset())
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, True)
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, True)
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(stringify_annotation(param.annotation, mode)) # type: ignore[arg-type]
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(sig.return_annotation, mode) # type: ignore[arg-type]
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: Callable = safe_getattr,
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 isclassmethod(obj, cls, name):
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 meth and hasattr(meth, '__func__'):
913
- doc: str | None = getdoc(meth.__func__)
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