Skip to content

Commit 966d579

Browse files
committed
bpo-39990: add option to resolve annotation strings in inspect
Signed-off-by: Filipe Laíns <[email protected]>
1 parent 9d74658 commit 966d579

File tree

3 files changed

+33
-9
lines changed

3 files changed

+33
-9
lines changed

Doc/library/inspect.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ The Signature object represents the call signature of a callable object and its
559559
return annotation. To retrieve a Signature object, use the :func:`signature`
560560
function.
561561

562-
.. function:: signature(callable, \*, follow_wrapped=True)
562+
.. function:: signature(callable, \*, follow_wrapped=True, resolve_type_hints=False)
563563

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

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

591+
.. versionadded:: 3.9
592+
``resolve_type_hints`` parameter. Pass ``True`` to resolve the type annotations.
593+
591594
.. versionadded:: 3.5
592595
``follow_wrapped`` parameter. Pass ``False`` to get a signature of
593596
``callable`` specifically (``callable.__wrapped__`` will not be used to
@@ -671,7 +674,7 @@ function.
671674
>>> str(new_sig)
672675
"(a, b) -> 'new return anno'"
673676

674-
.. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True)
677+
.. classmethod:: Signature.from_callable(obj, \*, follow_wrapped=True, resolve_type_hints=False)
675678

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

690+
.. versionadded:: 3.9
691+
``resolve_type_hints`` parameter. Pass ``True`` to resolve the type annotations.
692+
687693
.. versionadded:: 3.5
688694

689695

Lib/inspect.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,7 +2136,7 @@ def _signature_from_builtin(cls, func, skip_bound_arg=True):
21362136
return _signature_fromstr(cls, func, s, skip_bound_arg)
21372137

21382138

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

21422142
is_duck_function = False
@@ -2162,10 +2162,15 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
21622162
positional = arg_names[:pos_count]
21632163
keyword_only_count = func_code.co_kwonlyargcount
21642164
keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
2165-
annotations = func.__annotations__
21662165
defaults = func.__defaults__
21672166
kwdefaults = func.__kwdefaults__
21682167

2168+
if resolve_type_hints:
2169+
import typing
2170+
annotations = typing.get_type_hints(func)
2171+
else:
2172+
annotations = func.__annotations__
2173+
21692174
if defaults:
21702175
pos_default_count = len(defaults)
21712176
else:
@@ -2233,6 +2238,7 @@ def _signature_from_function(cls, func, skip_bound_arg=True):
22332238
def _signature_from_callable(obj, *,
22342239
follow_wrapper_chains=True,
22352240
skip_bound_arg=True,
2241+
resolve_type_hints=False,
22362242
sigcls):
22372243

22382244
"""Private helper function to get signature for arbitrary
@@ -2249,6 +2255,7 @@ def _signature_from_callable(obj, *,
22492255
obj.__func__,
22502256
follow_wrapper_chains=follow_wrapper_chains,
22512257
skip_bound_arg=skip_bound_arg,
2258+
resolve_type_hints=resolve_type_hints,
22522259
sigcls=sigcls)
22532260

22542261
if skip_bound_arg:
@@ -2267,6 +2274,7 @@ def _signature_from_callable(obj, *,
22672274
obj,
22682275
follow_wrapper_chains=follow_wrapper_chains,
22692276
skip_bound_arg=skip_bound_arg,
2277+
resolve_type_hints=resolve_type_hints,
22702278
sigcls=sigcls)
22712279

22722280
try:
@@ -2298,6 +2306,7 @@ def _signature_from_callable(obj, *,
22982306
partialmethod.func,
22992307
follow_wrapper_chains=follow_wrapper_chains,
23002308
skip_bound_arg=skip_bound_arg,
2309+
resolve_type_hints=resolve_type_hints,
23012310
sigcls=sigcls)
23022311

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

23222332
if _signature_is_builtin(obj):
23232333
return _signature_from_builtin(sigcls, obj,
@@ -2328,6 +2338,7 @@ def _signature_from_callable(obj, *,
23282338
obj.func,
23292339
follow_wrapper_chains=follow_wrapper_chains,
23302340
skip_bound_arg=skip_bound_arg,
2341+
resolve_type_hints=resolve_type_hints,
23312342
sigcls=sigcls)
23322343
return _signature_get_partial(wrapped_sig, obj)
23332344

@@ -2343,6 +2354,7 @@ def _signature_from_callable(obj, *,
23432354
call,
23442355
follow_wrapper_chains=follow_wrapper_chains,
23452356
skip_bound_arg=skip_bound_arg,
2357+
resolve_type_hints=resolve_type_hints,
23462358
sigcls=sigcls)
23472359
else:
23482360
# Now we check if the 'obj' class has a '__new__' method
@@ -2352,6 +2364,7 @@ def _signature_from_callable(obj, *,
23522364
new,
23532365
follow_wrapper_chains=follow_wrapper_chains,
23542366
skip_bound_arg=skip_bound_arg,
2367+
resolve_type_hints=resolve_type_hints,
23552368
sigcls=sigcls)
23562369
else:
23572370
# Finally, we should have at least __init__ implemented
@@ -2361,6 +2374,7 @@ def _signature_from_callable(obj, *,
23612374
init,
23622375
follow_wrapper_chains=follow_wrapper_chains,
23632376
skip_bound_arg=skip_bound_arg,
2377+
resolve_type_hints=resolve_type_hints,
23642378
sigcls=sigcls)
23652379

23662380
if sig is None:
@@ -2411,6 +2425,7 @@ def _signature_from_callable(obj, *,
24112425
call,
24122426
follow_wrapper_chains=follow_wrapper_chains,
24132427
skip_bound_arg=skip_bound_arg,
2428+
resolve_type_hints=resolve_type_hints,
24142429
sigcls=sigcls)
24152430
except ValueError as ex:
24162431
msg = 'no signature found for {!r}'.format(obj)
@@ -2863,10 +2878,11 @@ def from_builtin(cls, func):
28632878
return _signature_from_builtin(cls, func)
28642879

28652880
@classmethod
2866-
def from_callable(cls, obj, *, follow_wrapped=True):
2881+
def from_callable(cls, obj, *, follow_wrapped=True, resolve_type_hints=False):
28672882
"""Constructs Signature for the given callable object."""
28682883
return _signature_from_callable(obj, sigcls=cls,
2869-
follow_wrapper_chains=follow_wrapped)
2884+
follow_wrapper_chains=follow_wrapped,
2885+
resolve_type_hints=resolve_type_hints)
28702886

28712887
@property
28722888
def parameters(self):
@@ -3114,9 +3130,10 @@ def __str__(self):
31143130
return rendered
31153131

31163132

3117-
def signature(obj, *, follow_wrapped=True):
3133+
def signature(obj, *, follow_wrapped=True, resolve_type_hints=False):
31183134
"""Get a signature object for the passed callable."""
3119-
return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
3135+
return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
3136+
resolve_type_hints=resolve_type_hints)
31203137

31213138

31223139
def _main():
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add option to resolve annotation strings when creating a inspect.Signature from function/callable.

0 commit comments

Comments
 (0)