diff --git a/Lib/inspect.py b/Lib/inspect.py index d6bd8cd..020a263 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1528,6 +1528,20 @@ def signature(obj): init = _get_user_defined_method(obj, '__init__') if init is not None: sig = signature(init) + + if sig is None and obj not in (object, type): + # We have a class, but no user-defined + # __init__ or __new__ for it + if type in obj.__mro__: + # It's a metaclass. Return signature of 'type.__new__': + # (name, bases, dct) + return Signature([Parameter('name', _POSITIONAL_ONLY), + Parameter('bases', _POSITIONAL_ONLY), + Parameter('dct', _POSITIONAL_ONLY)]) + else: + # It's a class, return empty signature + return Signature() + elif not isinstance(obj, _NonUserDefinedCallables): # An object with __call__ # We also check that the 'obj' is not an instance of diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 1bfe724..81791f3 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1964,6 +1964,22 @@ class TestSignatureObject(unittest.TestCase): ('bar', 2, ..., "keyword_only")), ...)) + # Test classes without user-defined __init__ or __new__ + class C: pass + self.assertEqual(self.signature(C), ((), ...)) + class D(C): pass + self.assertEqual(self.signature(D), self.signature(C)) + + # Test meta classes without user-defined __init__ or __new__ + class CM(type): pass + class DM(CM): pass + self.assertEqual(self.signature(CM), + ((('name', ..., ..., 'positional_only'), + ('bases', ..., ..., 'positional_only'), + ('dct', ..., ..., 'positional_only')), + ...)) + self.assertEqual(self.signature(CM), self.signature(DM)) + def test_signature_on_callable_objects(self): class Foo: def __call__(self, a):