]> granicus.if.org Git - python/commitdiff
inspect.Signature: Make from_builtin to raise an exception if no signature can
authorYury Selivanov <yselivanov@sprymix.com>
Wed, 29 Jan 2014 15:46:14 +0000 (10:46 -0500)
committerYury Selivanov <yselivanov@sprymix.com>
Wed, 29 Jan 2014 15:46:14 +0000 (10:46 -0500)
be provided #20422

Lib/inspect.py
Lib/test/test_inspect.py

index 00728206019834282700771fc3ebf7bba9c02504..fefcddb85cbdb3002cb0b7c735649b9ae49a3ecc 100644 (file)
@@ -1514,18 +1514,24 @@ def _signature_bound_method(sig):
     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):
     '''Get a signature object for the passed callable.'''
 
     if not callable(obj):
         raise TypeError('{!r} is not a callable object'.format(obj))
 
-    if (isinstance(obj, _NonUserDefinedCallables) or
-       ismethoddescriptor(obj) or
-       isinstance(obj, type)):
-        sig = Signature.from_builtin(obj)
-        if sig:
-            return sig
+    if _signature_is_builtin(obj):
+        return Signature.from_builtin(obj)
 
     if isinstance(obj, types.MethodType):
         # In this case we skip the first parameter of the underlying
@@ -2017,9 +2023,13 @@ class Signature:
 
     @classmethod
     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)
         if not s:
-            return None
+            raise ValueError("no signature found for builtin {!r}".format(func))
 
         Parameter = cls._parameter_cls
 
@@ -2038,9 +2048,10 @@ class Signature:
         try:
             module = ast.parse(s)
         except SyntaxError:
-            return None
+            module = None
+
         if not isinstance(module, ast.Module):
-            return None
+            raise ValueError("{!r} builtin has invalid signature".format(func))
 
         f = module.body[0]
 
@@ -2149,7 +2160,6 @@ class Signature:
 
         return cls(parameters, return_annotation=cls.empty)
 
-
     @property
     def parameters(self):
         return self._parameters
index 1325c7a9511e14201da5907d9c694b645f7f8ff5..2ef3ca2270fa6f738a12d4e0a0537ad209572e17 100644 (file)
@@ -1667,6 +1667,10 @@ class TestSignatureObject(unittest.TestCase):
         with self.assertRaisesRegex(TypeError, 'is not a Python function'):
             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):
         class Test:
             def __init__(*args):