gh-101552: Allow pydoc to display signatures in source format (#124669)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
b502573f7f
commit
78406382c9
@ -694,7 +694,7 @@ and its return annotation. To retrieve a :class:`!Signature` object,
|
|||||||
use the :func:`!signature`
|
use the :func:`!signature`
|
||||||
function.
|
function.
|
||||||
|
|
||||||
.. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False)
|
.. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False, annotation_format=Format.VALUE)
|
||||||
|
|
||||||
Return a :class:`Signature` object for the given *callable*:
|
Return a :class:`Signature` object for the given *callable*:
|
||||||
|
|
||||||
@ -725,7 +725,12 @@ function.
|
|||||||
*globals*, *locals*, and *eval_str* parameters are passed
|
*globals*, *locals*, and *eval_str* parameters are passed
|
||||||
into :func:`!annotationlib.get_annotations` when resolving the
|
into :func:`!annotationlib.get_annotations` when resolving the
|
||||||
annotations; see the documentation for :func:`!annotationlib.get_annotations`
|
annotations; see the documentation for :func:`!annotationlib.get_annotations`
|
||||||
for instructions on how to use these parameters.
|
for instructions on how to use these parameters. A member of the
|
||||||
|
:class:`annotationlib.Format` enum can be passed to the
|
||||||
|
*annotation_format* parameter to control the format of the returned
|
||||||
|
annotations. For example, use
|
||||||
|
``annotation_format=annotationlib.Format.STRING`` to return annotations in string
|
||||||
|
format.
|
||||||
|
|
||||||
Raises :exc:`ValueError` if no signature can be provided, and
|
Raises :exc:`ValueError` if no signature can be provided, and
|
||||||
:exc:`TypeError` if that type of object is not supported. Also,
|
:exc:`TypeError` if that type of object is not supported. Also,
|
||||||
@ -733,7 +738,7 @@ function.
|
|||||||
the ``eval()`` call(s) to un-stringize the annotations in :func:`annotationlib.get_annotations`
|
the ``eval()`` call(s) to un-stringize the annotations in :func:`annotationlib.get_annotations`
|
||||||
could potentially raise any kind of exception.
|
could potentially raise any kind of exception.
|
||||||
|
|
||||||
A slash(/) in the signature of a function denotes that the parameters prior
|
A slash (/) in the signature of a function denotes that the parameters prior
|
||||||
to it are positional-only. For more info, see
|
to it are positional-only. For more info, see
|
||||||
:ref:`the FAQ entry on positional-only parameters <faq-positional-only-arguments>`.
|
:ref:`the FAQ entry on positional-only parameters <faq-positional-only-arguments>`.
|
||||||
|
|
||||||
@ -746,6 +751,9 @@ function.
|
|||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.10
|
||||||
The *globals*, *locals*, and *eval_str* parameters were added.
|
The *globals*, *locals*, and *eval_str* parameters were added.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
The *annotation_format* parameter was added.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Some callables may not be introspectable in certain implementations of
|
Some callables may not be introspectable in certain implementations of
|
||||||
@ -838,7 +846,7 @@ function.
|
|||||||
:class:`Signature` objects are also supported by the generic function
|
:class:`Signature` objects are also supported by the generic function
|
||||||
:func:`copy.replace`.
|
:func:`copy.replace`.
|
||||||
|
|
||||||
.. method:: format(*, max_width=None)
|
.. method:: format(*, max_width=None, quote_annotation_strings=True)
|
||||||
|
|
||||||
Create a string representation of the :class:`Signature` object.
|
Create a string representation of the :class:`Signature` object.
|
||||||
|
|
||||||
@ -847,8 +855,17 @@ function.
|
|||||||
If the signature is longer than *max_width*,
|
If the signature is longer than *max_width*,
|
||||||
all parameters will be on separate lines.
|
all parameters will be on separate lines.
|
||||||
|
|
||||||
|
If *quote_annotation_strings* is False, :term:`annotations <annotation>`
|
||||||
|
in the signature are displayed without opening and closing quotation
|
||||||
|
marks if they are strings. This is useful if the signature was created with the
|
||||||
|
:attr:`~annotationlib.Format.STRING` format or if
|
||||||
|
``from __future__ import annotations`` was used.
|
||||||
|
|
||||||
.. versionadded:: 3.13
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
The *unquote_annotations* parameter was added.
|
||||||
|
|
||||||
.. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False)
|
.. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False)
|
||||||
|
|
||||||
Return a :class:`Signature` (or its subclass) object for a given callable
|
Return a :class:`Signature` (or its subclass) object for a given callable
|
||||||
|
@ -281,6 +281,18 @@ http
|
|||||||
(Contributed by Yorik Hansen in :gh:`123430`.)
|
(Contributed by Yorik Hansen in :gh:`123430`.)
|
||||||
|
|
||||||
|
|
||||||
|
inspect
|
||||||
|
-------
|
||||||
|
|
||||||
|
* :func:`inspect.signature` takes a new argument *annotation_format* to control
|
||||||
|
the :class:`annotationlib.Format` used for representing annotations.
|
||||||
|
(Contributed by Jelle Zijlstra in :gh:`101552`.)
|
||||||
|
|
||||||
|
* :meth:`inspect.Signature.format` takes a new argument *unquote_annotations*.
|
||||||
|
If true, string :term:`annotations <annotation>` are displayed without surrounding quotes.
|
||||||
|
(Contributed by Jelle Zijlstra in :gh:`101552`.)
|
||||||
|
|
||||||
|
|
||||||
json
|
json
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -356,6 +368,14 @@ pickle
|
|||||||
of the error.
|
of the error.
|
||||||
(Contributed by Serhiy Storchaka in :gh:`122213`.)
|
(Contributed by Serhiy Storchaka in :gh:`122213`.)
|
||||||
|
|
||||||
|
pydoc
|
||||||
|
-----
|
||||||
|
|
||||||
|
* :term:`Annotations <annotation>` in help output are now usually
|
||||||
|
displayed in a format closer to that in the original source.
|
||||||
|
(Contributed by Jelle Zijlstra in :gh:`101552`.)
|
||||||
|
|
||||||
|
|
||||||
symtable
|
symtable
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ __all__ = [
|
|||||||
|
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
from annotationlib import Format
|
||||||
from annotationlib import get_annotations # re-exported
|
from annotationlib import get_annotations # re-exported
|
||||||
import ast
|
import ast
|
||||||
import dis
|
import dis
|
||||||
@ -1319,7 +1320,9 @@ def getargvalues(frame):
|
|||||||
args, varargs, varkw = getargs(frame.f_code)
|
args, varargs, varkw = getargs(frame.f_code)
|
||||||
return ArgInfo(args, varargs, varkw, frame.f_locals)
|
return ArgInfo(args, varargs, varkw, frame.f_locals)
|
||||||
|
|
||||||
def formatannotation(annotation, base_module=None):
|
def formatannotation(annotation, base_module=None, *, quote_annotation_strings=True):
|
||||||
|
if not quote_annotation_strings and isinstance(annotation, str):
|
||||||
|
return annotation
|
||||||
if getattr(annotation, '__module__', None) == 'typing':
|
if getattr(annotation, '__module__', None) == 'typing':
|
||||||
def repl(match):
|
def repl(match):
|
||||||
text = match.group()
|
text = match.group()
|
||||||
@ -2270,7 +2273,8 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True):
|
|||||||
|
|
||||||
|
|
||||||
def _signature_from_function(cls, func, skip_bound_arg=True,
|
def _signature_from_function(cls, func, skip_bound_arg=True,
|
||||||
globals=None, locals=None, eval_str=False):
|
globals=None, locals=None, eval_str=False,
|
||||||
|
*, annotation_format=Format.VALUE):
|
||||||
"""Private helper: constructs Signature for the given python function."""
|
"""Private helper: constructs Signature for the given python function."""
|
||||||
|
|
||||||
is_duck_function = False
|
is_duck_function = False
|
||||||
@ -2296,7 +2300,8 @@ def _signature_from_function(cls, func, skip_bound_arg=True,
|
|||||||
positional = arg_names[:pos_count]
|
positional = arg_names[:pos_count]
|
||||||
keyword_only_count = func_code.co_kwonlyargcount
|
keyword_only_count = func_code.co_kwonlyargcount
|
||||||
keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
|
keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
|
||||||
annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str)
|
annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str,
|
||||||
|
format=annotation_format)
|
||||||
defaults = func.__defaults__
|
defaults = func.__defaults__
|
||||||
kwdefaults = func.__kwdefaults__
|
kwdefaults = func.__kwdefaults__
|
||||||
|
|
||||||
@ -2379,7 +2384,8 @@ def _signature_from_callable(obj, *,
|
|||||||
globals=None,
|
globals=None,
|
||||||
locals=None,
|
locals=None,
|
||||||
eval_str=False,
|
eval_str=False,
|
||||||
sigcls):
|
sigcls,
|
||||||
|
annotation_format=Format.VALUE):
|
||||||
|
|
||||||
"""Private helper function to get signature for arbitrary
|
"""Private helper function to get signature for arbitrary
|
||||||
callable objects.
|
callable objects.
|
||||||
@ -2391,7 +2397,8 @@ def _signature_from_callable(obj, *,
|
|||||||
globals=globals,
|
globals=globals,
|
||||||
locals=locals,
|
locals=locals,
|
||||||
sigcls=sigcls,
|
sigcls=sigcls,
|
||||||
eval_str=eval_str)
|
eval_str=eval_str,
|
||||||
|
annotation_format=annotation_format)
|
||||||
|
|
||||||
if not callable(obj):
|
if not callable(obj):
|
||||||
raise TypeError('{!r} is not a callable object'.format(obj))
|
raise TypeError('{!r} is not a callable object'.format(obj))
|
||||||
@ -2472,7 +2479,8 @@ def _signature_from_callable(obj, *,
|
|||||||
# of a Python function (Cython functions, for instance), then:
|
# of a Python function (Cython functions, for instance), then:
|
||||||
return _signature_from_function(sigcls, obj,
|
return _signature_from_function(sigcls, obj,
|
||||||
skip_bound_arg=skip_bound_arg,
|
skip_bound_arg=skip_bound_arg,
|
||||||
globals=globals, locals=locals, eval_str=eval_str)
|
globals=globals, locals=locals, eval_str=eval_str,
|
||||||
|
annotation_format=annotation_format)
|
||||||
|
|
||||||
if _signature_is_builtin(obj):
|
if _signature_is_builtin(obj):
|
||||||
return _signature_from_builtin(sigcls, obj,
|
return _signature_from_builtin(sigcls, obj,
|
||||||
@ -2707,13 +2715,17 @@ class Parameter:
|
|||||||
return type(self)(name, kind, default=default, annotation=annotation)
|
return type(self)(name, kind, default=default, annotation=annotation)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
return self._format()
|
||||||
|
|
||||||
|
def _format(self, *, quote_annotation_strings=True):
|
||||||
kind = self.kind
|
kind = self.kind
|
||||||
formatted = self._name
|
formatted = self._name
|
||||||
|
|
||||||
# Add annotation and default value
|
# Add annotation and default value
|
||||||
if self._annotation is not _empty:
|
if self._annotation is not _empty:
|
||||||
formatted = '{}: {}'.format(formatted,
|
annotation = formatannotation(self._annotation,
|
||||||
formatannotation(self._annotation))
|
quote_annotation_strings=quote_annotation_strings)
|
||||||
|
formatted = '{}: {}'.format(formatted, annotation)
|
||||||
|
|
||||||
if self._default is not _empty:
|
if self._default is not _empty:
|
||||||
if self._annotation is not _empty:
|
if self._annotation is not _empty:
|
||||||
@ -2961,11 +2973,13 @@ class Signature:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_callable(cls, obj, *,
|
def from_callable(cls, obj, *,
|
||||||
follow_wrapped=True, globals=None, locals=None, eval_str=False):
|
follow_wrapped=True, globals=None, locals=None, eval_str=False,
|
||||||
|
annotation_format=Format.VALUE):
|
||||||
"""Constructs Signature for the given callable object."""
|
"""Constructs Signature for the given callable object."""
|
||||||
return _signature_from_callable(obj, sigcls=cls,
|
return _signature_from_callable(obj, sigcls=cls,
|
||||||
follow_wrapper_chains=follow_wrapped,
|
follow_wrapper_chains=follow_wrapped,
|
||||||
globals=globals, locals=locals, eval_str=eval_str)
|
globals=globals, locals=locals, eval_str=eval_str,
|
||||||
|
annotation_format=annotation_format)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parameters(self):
|
def parameters(self):
|
||||||
@ -3180,19 +3194,24 @@ class Signature:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.format()
|
return self.format()
|
||||||
|
|
||||||
def format(self, *, max_width=None):
|
def format(self, *, max_width=None, quote_annotation_strings=True):
|
||||||
"""Create a string representation of the Signature object.
|
"""Create a string representation of the Signature object.
|
||||||
|
|
||||||
If *max_width* integer is passed,
|
If *max_width* integer is passed,
|
||||||
signature will try to fit into the *max_width*.
|
signature will try to fit into the *max_width*.
|
||||||
If signature is longer than *max_width*,
|
If signature is longer than *max_width*,
|
||||||
all parameters will be on separate lines.
|
all parameters will be on separate lines.
|
||||||
|
|
||||||
|
If *quote_annotation_strings* is False, annotations
|
||||||
|
in the signature are displayed without opening and closing quotation
|
||||||
|
marks. This is useful when the signature was created with the
|
||||||
|
STRING format or when ``from __future__ import annotations`` was used.
|
||||||
"""
|
"""
|
||||||
result = []
|
result = []
|
||||||
render_pos_only_separator = False
|
render_pos_only_separator = False
|
||||||
render_kw_only_separator = True
|
render_kw_only_separator = True
|
||||||
for param in self.parameters.values():
|
for param in self.parameters.values():
|
||||||
formatted = str(param)
|
formatted = param._format(quote_annotation_strings=quote_annotation_strings)
|
||||||
|
|
||||||
kind = param.kind
|
kind = param.kind
|
||||||
|
|
||||||
@ -3229,16 +3248,19 @@ class Signature:
|
|||||||
rendered = '(\n {}\n)'.format(',\n '.join(result))
|
rendered = '(\n {}\n)'.format(',\n '.join(result))
|
||||||
|
|
||||||
if self.return_annotation is not _empty:
|
if self.return_annotation is not _empty:
|
||||||
anno = formatannotation(self.return_annotation)
|
anno = formatannotation(self.return_annotation,
|
||||||
|
quote_annotation_strings=quote_annotation_strings)
|
||||||
rendered += ' -> {}'.format(anno)
|
rendered += ' -> {}'.format(anno)
|
||||||
|
|
||||||
return rendered
|
return rendered
|
||||||
|
|
||||||
|
|
||||||
def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False):
|
def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False,
|
||||||
|
annotation_format=Format.VALUE):
|
||||||
"""Get a signature object for the passed callable."""
|
"""Get a signature object for the passed callable."""
|
||||||
return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
|
return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
|
||||||
globals=globals, locals=locals, eval_str=eval_str)
|
globals=globals, locals=locals, eval_str=eval_str,
|
||||||
|
annotation_format=annotation_format)
|
||||||
|
|
||||||
|
|
||||||
class BufferFlags(enum.IntFlag):
|
class BufferFlags(enum.IntFlag):
|
||||||
|
@ -71,6 +71,7 @@ import time
|
|||||||
import tokenize
|
import tokenize
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import warnings
|
import warnings
|
||||||
|
from annotationlib import Format
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from reprlib import Repr
|
from reprlib import Repr
|
||||||
from traceback import format_exception_only
|
from traceback import format_exception_only
|
||||||
@ -212,12 +213,12 @@ def splitdoc(doc):
|
|||||||
|
|
||||||
def _getargspec(object):
|
def _getargspec(object):
|
||||||
try:
|
try:
|
||||||
signature = inspect.signature(object)
|
signature = inspect.signature(object, annotation_format=Format.STRING)
|
||||||
if signature:
|
if signature:
|
||||||
name = getattr(object, '__name__', '')
|
name = getattr(object, '__name__', '')
|
||||||
# <lambda> function are always single-line and should not be formatted
|
# <lambda> function are always single-line and should not be formatted
|
||||||
max_width = (80 - len(name)) if name != '<lambda>' else None
|
max_width = (80 - len(name)) if name != '<lambda>' else None
|
||||||
return signature.format(max_width=max_width)
|
return signature.format(max_width=max_width, quote_annotation_strings=False)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
argspec = getattr(object, '__text_signature__', None)
|
argspec = getattr(object, '__text_signature__', None)
|
||||||
if argspec:
|
if argspec:
|
||||||
|
2
Lib/test/test_inspect/inspect_deferred_annotations.py
Normal file
2
Lib/test/test_inspect/inspect_deferred_annotations.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
def f(x: undefined):
|
||||||
|
pass
|
@ -1,3 +1,4 @@
|
|||||||
|
from annotationlib import Format, ForwardRef
|
||||||
import asyncio
|
import asyncio
|
||||||
import builtins
|
import builtins
|
||||||
import collections
|
import collections
|
||||||
@ -22,7 +23,6 @@ import time
|
|||||||
import types
|
import types
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
from typing import Unpack
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import unittest
|
import unittest
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
@ -46,6 +46,7 @@ from test import support
|
|||||||
from test.test_inspect import inspect_fodder as mod
|
from test.test_inspect import inspect_fodder as mod
|
||||||
from test.test_inspect import inspect_fodder2 as mod2
|
from test.test_inspect import inspect_fodder2 as mod2
|
||||||
from test.test_inspect import inspect_stringized_annotations
|
from test.test_inspect import inspect_stringized_annotations
|
||||||
|
from test.test_inspect import inspect_deferred_annotations
|
||||||
|
|
||||||
|
|
||||||
# Functions tested in this suite:
|
# Functions tested in this suite:
|
||||||
@ -4622,6 +4623,18 @@ class TestSignatureObject(unittest.TestCase):
|
|||||||
expected_multiline,
|
expected_multiline,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_signature_format_unquote(self):
|
||||||
|
def func(x: 'int') -> 'str': ...
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
inspect.signature(func).format(),
|
||||||
|
"(x: 'int') -> 'str'"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
inspect.signature(func).format(quote_annotation_strings=False),
|
||||||
|
"(x: int) -> str"
|
||||||
|
)
|
||||||
|
|
||||||
def test_signature_replace_parameters(self):
|
def test_signature_replace_parameters(self):
|
||||||
def test(a, b) -> 42:
|
def test(a, b) -> 42:
|
||||||
pass
|
pass
|
||||||
@ -4854,6 +4867,26 @@ class TestSignatureObject(unittest.TestCase):
|
|||||||
par('b', PORK, annotation=tuple),
|
par('b', PORK, annotation=tuple),
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
def test_signature_annotation_format(self):
|
||||||
|
ida = inspect_deferred_annotations
|
||||||
|
sig = inspect.Signature
|
||||||
|
par = inspect.Parameter
|
||||||
|
PORK = inspect.Parameter.POSITIONAL_OR_KEYWORD
|
||||||
|
for signature_func in (inspect.signature, inspect.Signature.from_callable):
|
||||||
|
with self.subTest(signature_func=signature_func):
|
||||||
|
self.assertEqual(
|
||||||
|
signature_func(ida.f, annotation_format=Format.STRING),
|
||||||
|
sig([par("x", PORK, annotation="undefined")])
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
signature_func(ida.f, annotation_format=Format.FORWARDREF),
|
||||||
|
sig([par("x", PORK, annotation=ForwardRef("undefined"))])
|
||||||
|
)
|
||||||
|
with self.assertRaisesRegex(NameError, "undefined"):
|
||||||
|
signature_func(ida.f, annotation_format=Format.VALUE)
|
||||||
|
with self.assertRaisesRegex(NameError, "undefined"):
|
||||||
|
signature_func(ida.f)
|
||||||
|
|
||||||
def test_signature_none_annotation(self):
|
def test_signature_none_annotation(self):
|
||||||
class funclike:
|
class funclike:
|
||||||
# Has to be callable, and have correct
|
# Has to be callable, and have correct
|
||||||
|
@ -1073,7 +1073,7 @@ class B(A)
|
|||||||
|
|
||||||
class A(builtins.object)
|
class A(builtins.object)
|
||||||
| A(
|
| A(
|
||||||
| arg1: collections.abc.Callable[[int, int, int], str],
|
| arg1: Callable[[int, int, int], str],
|
||||||
| arg2: Literal['some value', 'other value'],
|
| arg2: Literal['some value', 'other value'],
|
||||||
| arg3: Annotated[int, 'some docs about this type']
|
| arg3: Annotated[int, 'some docs about this type']
|
||||||
| ) -> None
|
| ) -> None
|
||||||
@ -1082,7 +1082,7 @@ class A(builtins.object)
|
|||||||
|
|
|
|
||||||
| __init__(
|
| __init__(
|
||||||
| self,
|
| self,
|
||||||
| arg1: collections.abc.Callable[[int, int, int], str],
|
| arg1: Callable[[int, int, int], str],
|
||||||
| arg2: Literal['some value', 'other value'],
|
| arg2: Literal['some value', 'other value'],
|
||||||
| arg3: Annotated[int, 'some docs about this type']
|
| arg3: Annotated[int, 'some docs about this type']
|
||||||
| ) -> None
|
| ) -> None
|
||||||
@ -1109,7 +1109,7 @@ class A(builtins.object)
|
|||||||
self.assertEqual(doc, '''Python Library Documentation: function func in module %s
|
self.assertEqual(doc, '''Python Library Documentation: function func in module %s
|
||||||
|
|
||||||
func(
|
func(
|
||||||
arg1: collections.abc.Callable[[typing.Annotated[int, 'Some doc']], str],
|
arg1: Callable[[Annotated[int, 'Some doc']], str],
|
||||||
arg2: Literal[1, 2, 3, 4, 5, 6, 7, 8]
|
arg2: Literal[1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
) -> Annotated[int, 'Some other']
|
) -> Annotated[int, 'Some other']
|
||||||
''' % __name__)
|
''' % __name__)
|
||||||
@ -1394,8 +1394,8 @@ class TestDescriptions(unittest.TestCase):
|
|||||||
T = typing.TypeVar('T')
|
T = typing.TypeVar('T')
|
||||||
class C(typing.Generic[T], typing.Mapping[int, str]): ...
|
class C(typing.Generic[T], typing.Mapping[int, str]): ...
|
||||||
self.assertEqual(pydoc.render_doc(foo).splitlines()[-1],
|
self.assertEqual(pydoc.render_doc(foo).splitlines()[-1],
|
||||||
'f\x08fo\x08oo\x08o(data: List[Any], x: int)'
|
'f\x08fo\x08oo\x08o(data: typing.List[typing.Any], x: int)'
|
||||||
' -> Iterator[Tuple[int, Any]]')
|
' -> typing.Iterator[typing.Tuple[int, typing.Any]]')
|
||||||
self.assertEqual(pydoc.render_doc(C).splitlines()[2],
|
self.assertEqual(pydoc.render_doc(C).splitlines()[2],
|
||||||
'class C\x08C(collections.abc.Mapping, typing.Generic)')
|
'class C\x08C(collections.abc.Mapping, typing.Generic)')
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
Add an *annoation_format* parameter to :func:`inspect.signature`. Add an
|
||||||
|
*quote_annotation_strings* parameter to :meth:`inspect.Signature.format`. Use the
|
||||||
|
new functionality to improve the display of annotations in signatures in
|
||||||
|
:mod:`pydoc`. Patch by Jelle Zijlstra.
|
Loading…
x
Reference in New Issue
Block a user