mirror of
https://github.com/python/cpython.git
synced 2025-07-07 11:25:30 +00:00
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.
This commit is contained in:
parent
1978904a2f
commit
cb6596c6aa
3 changed files with 34 additions and 3 deletions
|
@ -2074,13 +2074,11 @@ def _signature_is_functionlike(obj):
|
|||
code = getattr(obj, '__code__', None)
|
||||
defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
|
||||
kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
|
||||
annotations = getattr(obj, '__annotations__', None)
|
||||
|
||||
return (isinstance(code, types.CodeType) and
|
||||
isinstance(name, str) and
|
||||
(defaults is None or isinstance(defaults, tuple)) and
|
||||
(kwdefaults is None or isinstance(kwdefaults, dict)) and
|
||||
(isinstance(annotations, (dict)) or annotations is None) )
|
||||
(kwdefaults is None or isinstance(kwdefaults, dict)))
|
||||
|
||||
|
||||
def _signature_strip_non_python_syntax(signature):
|
||||
|
|
|
@ -4997,6 +4997,37 @@ class TestSignatureObject(unittest.TestCase):
|
|||
with self.assertRaisesRegex(NameError, "undefined"):
|
||||
signature_func(ida.f)
|
||||
|
||||
def test_signature_deferred_annotations(self):
|
||||
def f(x: undef):
|
||||
pass
|
||||
|
||||
class C:
|
||||
x: undef
|
||||
|
||||
def __init__(self, x: undef):
|
||||
self.x = x
|
||||
|
||||
sig = inspect.signature(f, annotation_format=Format.FORWARDREF)
|
||||
self.assertEqual(list(sig.parameters), ['x'])
|
||||
sig = inspect.signature(C, annotation_format=Format.FORWARDREF)
|
||||
self.assertEqual(list(sig.parameters), ['x'])
|
||||
|
||||
class CallableWrapper:
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
self.__annotate__ = func.__annotate__
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.func(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def __annotations__(self):
|
||||
return self.__annotate__(Format.VALUE)
|
||||
|
||||
cw = CallableWrapper(f)
|
||||
sig = inspect.signature(cw, annotation_format=Format.FORWARDREF)
|
||||
self.assertEqual(list(sig.parameters), ['args', 'kwargs'])
|
||||
|
||||
def test_signature_none_annotation(self):
|
||||
class funclike:
|
||||
# Has to be callable, and have correct
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Avoid accessing ``__annotations__`` unnecessarily in
|
||||
:func:`inspect.signature`.
|
Loading…
Add table
Add a link
Reference in a new issue