]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-105080: Fixed inconsistent signature on derived classes (#105217)
authorTian Gao <gaogaotiantian@hotmail.com>
Fri, 2 Jun 2023 22:22:33 +0000 (06:22 +0800)
committerGitHub <noreply@github.com>
Fri, 2 Jun 2023 22:22:33 +0000 (16:22 -0600)
Lib/inspect.py
Lib/test/test_inspect.py
Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst [new file with mode: 0644]

index 15eefdb6570be489746ee05d2c3fff1bec599479..a550202bb0d49bf539d649ca865820348dafb032 100644 (file)
@@ -2581,17 +2581,18 @@ def _signature_from_callable(obj, *,
             factory_method = None
             new = _signature_get_user_defined_method(obj, '__new__')
             init = _signature_get_user_defined_method(obj, '__init__')
-            # Now we check if the 'obj' class has an own '__new__' method
-            if '__new__' in obj.__dict__:
-                factory_method = new
-            # or an own '__init__' method
-            elif '__init__' in obj.__dict__:
-                factory_method = init
-            # If not, we take inherited '__new__' or '__init__', if present
-            elif new is not None:
-                factory_method = new
-            elif init is not None:
-                factory_method = init
+
+            # Go through the MRO and see if any class has user-defined
+            # pure Python __new__ or __init__ method
+            for base in obj.__mro__:
+                # Now we check if the 'obj' class has an own '__new__' method
+                if new is not None and '__new__' in base.__dict__:
+                    factory_method = new
+                    break
+                # or an own '__init__' method
+                elif init is not None and '__init__' in base.__dict__:
+                    factory_method = init
+                    break
 
             if factory_method is not None:
                 sig = _get_signature_of(factory_method)
index 6a49e3b5530e1635bf0e1f4dd1f3338191b72041..d89953ab60f02205ffc5d498fcafeb0b8ab0aa38 100644 (file)
@@ -3927,6 +3927,24 @@ class TestSignatureObject(unittest.TestCase):
                            ('b', 2, ..., 'positional_or_keyword')),
                           ...))
 
+    def test_signature_on_derived_classes(self):
+        # gh-105080: Make sure that signatures are consistent on derived classes
+
+        class B:
+            def __new__(self, *args, **kwargs):
+                return super().__new__(self)
+            def __init__(self, value):
+                self.value = value
+
+        class D1(B):
+            def __init__(self, value):
+                super().__init__(value)
+
+        class D2(D1):
+            pass
+
+        self.assertEqual(inspect.signature(D2), inspect.signature(D1))
+
 
 class TestParameterObject(unittest.TestCase):
     def test_signature_parameter_kinds(self):
diff --git a/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst b/Misc/NEWS.d/next/Library/2023-06-02-02-38-26.gh-issue-105080.2imGMg.rst
new file mode 100644 (file)
index 0000000..efe8365
--- /dev/null
@@ -0,0 +1 @@
+Fixed inconsistent signature on derived classes for :func:`inspect.signature`