8000 gh-132493: Remove __annotations__ usage in inspect._signature_is_func… · python/cpython@cb6596c · GitHub
[go: up one dir, main page]

Skip to content

Commit cb6596c

Browse files
gh-132493: Remove __annotations__ usage in inspect._signature_is_functionlike (#133415)
This check is potentially problematic because it could force evaluation of annotations unnecessarily. This doesn't trigger for builtin objects (functions, classes, or modules) with annotations, but it could trigger for third-party objects. The check was not particularly useful anyway, because it succeeds if ``__annotations__`` is a dict or None, so the only thing this did was guard against objects that have an ``__annotations__`` attribute that is of some other type. That doesn't seem particularly useful, so I just removed the check.
1 parent 1978904 commit cb6596c

File tree

3 files changed

+34
-3
lines changed

3 files changed

+34
-3
lines changed

Lib/inspect.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,13 +2074,11 @@ def _signature_is_functionlike(obj):
20742074
code = getattr(obj, '__code__', None)
20752075
defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
20762076
kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
2077-
annotations = getattr(obj, '__annotations__', None)
20782077

20792078
return (isinstance(code, types.CodeType) and
20802079
isinstance(name, str) and
20812080
(defaults is None or isinstance(defaults, tuple)) and
2082-
(kwdefaults is None or isinstance(kwdefaults, dict)) and
2083-
(isinstance(annotations, (dict)) or annotations is None) )
2081+
(kwdefaults is None or isinstance(kwdefaults, dict)))
20842082

20852083

20862084
def _signature_strip_non_python_syntax(signature):

Lib/test/test_inspect/test_inspect.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4997,6 +4997,37 @@ def test_signature_annotation_format(self):
49974997
with self.assertRaisesRegex(NameError, "undefined"):
49984998
signature_func(ida.f)
49994999

5000+
def test_signature_deferred_annotations(self):
5001+
def f(x: undef):
5002+
pass
5003+
5004+
class C:
5005+
x: undef
5006+
5007+
def __init__(self, x: undef):
5008+
self.x = x
5009+
5010+
sig = inspect.signature(f, annotation_format=Format.FORWARDREF)
5011+
self.assertEqual(list(sig.parameters), ['x'])
5012+
sig = inspect.signature(C, annotation_format=Format.FORWARDREF)
5013+
self.assertEqual(list(sig.parameters), ['x'])
5014+
5015+
class CallableWrapper:
5016+
def __init__(self, func):
5017+
self.func = func
5018+
self.__annotate__ = func.__annotate__
5019+
5020+
def __call__(self, *args, **kwargs):
5021+
return self.func(*args, **kwargs)
5022+
5023+
@property
5024+
def __annotations__(self):
5025+
return self.__annotate__(Format.VALUE)
5026+
5027+
cw = CallableWrapper(f)
5028+
sig = inspect.signature(cw, annotation_format=Format.FORWARDREF)
5029+
self.assertEqual(list(sig.parameters), ['args', 'kwargs'])
5030+
50005031
def test_signature_none_annotation(self):
50015032
class funclike:
50025033
# Has to be callable, and have correct
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid accessing ``__annotations__`` unnecessarily in
2+
:func:`inspect.signature`.

0 commit comments

Comments
 (0)
0