Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Doc/library/inspect.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -559,7 +559,7 @@ The Signature object represents the call signature of a callable object and its
return annotation. To retrieve a Signature object, use the :func:`signature`
function.

.. function:: signature(callable, \*, follow_wrapped=True)
.. function:: signature(callable, \*, follow_wrapped=True, resolve_type_hints=False)

Return a :class:`Signature` object for the given ``callable``::

Expand DownExpand Up@@ -588,6 +588,9 @@ function.
to it are positional-only. For more info, see
:ref:`the FAQ entry on positional-only parameters <faq-positional-only-arguments>`.

.. versionadded:: 3.9
``resolve_type_hints`` parameter. Pass ``True`` to resolve the type annotations.

.. versionadded:: 3.5
``follow_wrapped`` parameter. Pass ``False`` to get a signature of
``callable`` specifically (``callable.__wrapped__`` will not be used to
Expand DownExpand Up@@ -671,7 +674,7 @@ function.
>>> str(new_sig)
"(a, b) -> 'new return anno'"

.. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True)
.. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True, resolve_type_hints=False)

Return a :class:`Signature` (or its subclass) object for a given callable
``obj``. Pass ``follow_wrapped=False`` to get a signature of ``obj``
Expand All@@ -684,6 +687,9 @@ function.
sig = MySignature.from_callable(min)
assert isinstance(sig, MySignature)

.. versionadded:: 3.9
``resolve_type_hints`` parameter. Pass ``True`` to resolve the type annotations.

.. versionadded:: 3.5


Expand Down
31 changes: 24 additions & 7 deletions Lib/inspect.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2136,7 +2136,7 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True):
return _signature_fromstr(cls, func, s, skip_bound_arg)


def _signature_from_function(cls, func, skip_bound_arg=True):
def _signature_from_function(cls, func, skip_bound_arg=True, resolve_type_hints=False):
"""Private helper: constructs Signature for the given python function."""

is_duck_function = False
Expand All@@ -2162,10 +2162,15 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
positional = arg_names[:pos_count]
keyword_only_count = func_code.co_kwonlyargcount
keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
annotations = func.__annotations__
defaults = func.__defaults__
kwdefaults = func.__kwdefaults__

if resolve_type_hints:
import typing
annotations = typing.get_type_hints(func)
else:
annotations = func.__annotations__

if defaults:
pos_default_count = len(defaults)
else:
Expand DownExpand Up@@ -2233,6 +2238,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
def _signature_from_callable(obj, *,
follow_wrapper_chains=True,
skip_bound_arg=True,
resolve_type_hints=False,
sigcls):

"""Private helper function to get signature for arbitrary
Expand All@@ -2249,6 +2255,7 @@ def _signature_from_callable(obj, *,
obj.__func__,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)

if skip_bound_arg:
Expand All@@ -2267,6 +2274,7 @@ def _signature_from_callable(obj, *,
obj,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)

try:
Expand DownExpand Up@@ -2298,6 +2306,7 @@ def _signature_from_callable(obj, *,
partialmethod.func,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)

sig = _signature_get_partial(wrapped_sig, partialmethod, (None,))
Expand All@@ -2317,7 +2326,8 @@ def _signature_from_callable(obj, *,
# If it's a pure Python function, or an object that is duck type
# of a Python function (Cython functions, for instance), then:
return _signature_from_function(sigcls, obj,
skip_bound_arg=skip_bound_arg)
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints)

if _signature_is_builtin(obj):
return _signature_from_builtin(sigcls, obj,
Expand All@@ -2328,6 +2338,7 @@ def _signature_from_callable(obj, *,
obj.func,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)
return _signature_get_partial(wrapped_sig, obj)

Expand All@@ -2343,6 +2354,7 @@ def _signature_from_callable(obj, *,
call,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)
else:
# Now we check if the 'obj' class has a '__new__' method
Expand All@@ -2352,6 +2364,7 @@ def _signature_from_callable(obj, *,
new,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)
else:
# Finally, we should have at least __init__ implemented
Expand All@@ -2361,6 +2374,7 @@ def _signature_from_callable(obj, *,
init,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)

if sig is None:
Expand DownExpand Up@@ -2411,6 +2425,7 @@ def _signature_from_callable(obj, *,
call,
follow_wrapper_chains=follow_wrapper_chains,
skip_bound_arg=skip_bound_arg,
resolve_type_hints=resolve_type_hints,
sigcls=sigcls)
except ValueError as ex:
msg = 'no signature found for{!r}'.format(obj)
Expand DownExpand Up@@ -2863,10 +2878,11 @@ def from_builtin(cls, func):
return _signature_from_builtin(cls, func)

@classmethod
def from_callable(cls, obj, *, follow_wrapped=True):
def from_callable(cls, obj, *, follow_wrapped=True, resolve_type_hints=False):
"""Constructs Signature for the given callable object."""
return _signature_from_callable(obj, sigcls=cls,
follow_wrapper_chains=follow_wrapped)
follow_wrapper_chains=follow_wrapped,
resolve_type_hints=resolve_type_hints)

@property
def parameters(self):
Expand DownExpand Up@@ -3114,9 +3130,10 @@ def __str__(self):
return rendered


def signature(obj, *, follow_wrapped=True):
def signature(obj, *, follow_wrapped=True, resolve_type_hints=False):
"""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,
resolve_type_hints=resolve_type_hints)


def _main():
Expand Down
36 changes: 24 additions & 12 deletions Lib/pydoc.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -907,9 +907,12 @@ def spilldata(msg, attrs, predicate):

decl = ''
try:
signature = inspect.signature(object)
except (ValueError, TypeError):
signature = None
signature = inspect.signature(object, resolve_type_hints=True)
except (NameError, AttributeError, SyntaxError, TypeError, ValueError):
try:
signature = inspect.signature(object, resolve_type_hints=False)
except (ValueError, TypeError):
signature = None
if signature:
argspec = str(signature)
if argspec and argspec != '()':
Expand DownExpand Up@@ -967,9 +970,12 @@ def docroutine(self, object, name=None, mod=None,
argspec = None
if inspect.isroutine(object):
try:
signature = inspect.signature(object)
except (ValueError, TypeError):
signature = None
signature = inspect.signature(object, resolve_type_hints=True)
except (NameError, AttributeError, SyntaxError, TypeError, ValueError):
try:
signature = inspect.signature(object, resolve_type_hints=False)
except (ValueError, TypeError):
signature = None
if signature:
argspec = str(signature)
if realname == '<lambda>':
Expand DownExpand Up@@ -1226,9 +1232,12 @@ def makename(c, m=object.__module__):
push = contents.append

try:
signature = inspect.signature(object)
except (ValueError, TypeError):
signature = None
signature = inspect.signature(object, resolve_type_hints=True)
except (NameError, AttributeError, SyntaxError, TypeError, ValueError):
try:
signature = inspect.signature(object, resolve_type_hints=False)
except (ValueError, TypeError):
signature = None
if signature:
argspec = str(signature)
if argspec and argspec != '()':
Expand DownExpand Up@@ -1397,9 +1406,12 @@ def docroutine(self, object, name=None, mod=None, cl=None):

if inspect.isroutine(object):
try:
signature = inspect.signature(object)
except (ValueError, TypeError):
signature = None
signature = inspect.signature(object, resolve_type_hints=True)
except (NameError, AttributeError, SyntaxError, TypeError, ValueError):
try:
signature = inspect.signature(object, resolve_type_hints=False)
except (ValueError, TypeError):
signature = None
if signature:
argspec = str(signature)
if realname == '<lambda>':
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Add option to resolve annotation strings when creating a inspect.Signature from function/callable.