Commit 1864754c authored by Yury Selivanov's avatar Yury Selivanov

inspect.Signature: Make from_builtin to raise an exception if no signature can

be provided #20422
parent 8843d56e
...@@ -1514,18 +1514,24 @@ def _signature_bound_method(sig): ...@@ -1514,18 +1514,24 @@ def _signature_bound_method(sig):
return sig.replace(parameters=params) return sig.replace(parameters=params)
def _signature_is_builtin(obj):
# Internal helper to test if `obj` is a callable that might
# support Argument Clinic's __text_signature__ protocol.
return (isinstance(obj, _NonUserDefinedCallables) or
ismethoddescriptor(obj) or
# Can't test 'isinstance(type)' here, as it would
# also be True for regular python classes
obj in (type, object))
def signature(obj): def signature(obj):
'''Get a signature object for the passed callable.''' '''Get a signature object for the passed callable.'''
if not callable(obj): if not callable(obj):
raise TypeError('{!r} is not a callable object'.format(obj)) raise TypeError('{!r} is not a callable object'.format(obj))
if (isinstance(obj, _NonUserDefinedCallables) or if _signature_is_builtin(obj):
ismethoddescriptor(obj) or return Signature.from_builtin(obj)
isinstance(obj, type)):
sig = Signature.from_builtin(obj)
if sig:
return sig
if isinstance(obj, types.MethodType): if isinstance(obj, types.MethodType):
# In this case we skip the first parameter of the underlying # In this case we skip the first parameter of the underlying
...@@ -2017,9 +2023,13 @@ class Signature: ...@@ -2017,9 +2023,13 @@ class Signature:
@classmethod @classmethod
def from_builtin(cls, func): def from_builtin(cls, func):
if not _signature_is_builtin(func):
raise TypeError("{!r} is not a Python builtin "
"function".format(func))
s = getattr(func, "__text_signature__", None) s = getattr(func, "__text_signature__", None)
if not s: if not s:
return None raise ValueError("no signature found for builtin {!r}".format(func))
Parameter = cls._parameter_cls Parameter = cls._parameter_cls
...@@ -2038,9 +2048,10 @@ class Signature: ...@@ -2038,9 +2048,10 @@ class Signature:
try: try:
module = ast.parse(s) module = ast.parse(s)
except SyntaxError: except SyntaxError:
return None module = None
if not isinstance(module, ast.Module): if not isinstance(module, ast.Module):
return None raise ValueError("{!r} builtin has invalid signature".format(func))
f = module.body[0] f = module.body[0]
...@@ -2149,7 +2160,6 @@ class Signature: ...@@ -2149,7 +2160,6 @@ class Signature:
return cls(parameters, return_annotation=cls.empty) return cls(parameters, return_annotation=cls.empty)
@property @property
def parameters(self): def parameters(self):
return self._parameters return self._parameters
......
...@@ -1667,6 +1667,10 @@ class TestSignatureObject(unittest.TestCase): ...@@ -1667,6 +1667,10 @@ class TestSignatureObject(unittest.TestCase):
with self.assertRaisesRegex(TypeError, 'is not a Python function'): with self.assertRaisesRegex(TypeError, 'is not a Python function'):
inspect.Signature.from_function(42) inspect.Signature.from_function(42)
def test_signature_from_builtin_errors(self):
with self.assertRaisesRegex(TypeError, 'is not a Python builtin'):
inspect.Signature.from_builtin(42)
def test_signature_on_method(self): def test_signature_on_method(self):
class Test: class Test:
def __init__(*args): def __init__(*args):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment