Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cb6596c

Browse filesBrowse 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
Copy full SHA for cb6596c

File tree

3 files changed

+34
-3
lines changed
Filter options

3 files changed

+34
-3
lines changed

‎Lib/inspect.py

Copy file name to clipboardExpand all lines: Lib/inspect.py
+1-3Lines 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

Copy file name to clipboardExpand all lines: Lib/test/test_inspect/test_inspect.py
+31Lines 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
+2Lines 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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.