]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-106917: fix super classmethod calls to non-classmethods (#106977)
authorCarl Meyer <carl@oddbird.net>
Mon, 24 Jul 2023 20:14:56 +0000 (14:14 -0600)
committerGitHub <noreply@github.com>
Mon, 24 Jul 2023 20:14:56 +0000 (13:14 -0700)
Lib/test/test_super.py
Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst [new file with mode: 0644]
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h

index 664cf70b3cf0faf6f4f303201578025e86f80f44..43162c540b55aef8870cf8aa1b4929ea9e9045c3 100644 (file)
@@ -5,6 +5,9 @@ from unittest.mock import patch
 from test import shadowed_super
 
 
+ADAPTIVE_WARMUP_DELAY = 2
+
+
 class A:
     def f(self):
         return 'A'
@@ -419,8 +422,47 @@ class TestSuper(unittest.TestCase):
             super(MyType, type(mytype)).__setattr__(mytype, "bar", 1)
             self.assertEqual(mytype.bar, 1)
 
-        test("foo1")
-        test("foo2")
+        for _ in range(ADAPTIVE_WARMUP_DELAY):
+            test("foo1")
+
+    def test_reassigned_new(self):
+        class A:
+            def __new__(cls):
+                pass
+
+            def __init_subclass__(cls):
+                if "__new__" not in cls.__dict__:
+                    cls.__new__ = cls.__new__
+
+        class B(A):
+            pass
+
+        class C(B):
+            def __new__(cls):
+                return super().__new__(cls)
+
+        for _ in range(ADAPTIVE_WARMUP_DELAY):
+            C()
+
+    def test_mixed_staticmethod_hierarchy(self):
+        # This test is just a desugared version of `test_reassigned_new`
+        class A:
+            @staticmethod
+            def some(cls, *args, **kwargs):
+                self.assertFalse(args)
+                self.assertFalse(kwargs)
+
+        class B(A):
+            def some(cls, *args, **kwargs):
+                return super().some(cls, *args, **kwargs)
+
+        class C(B):
+            @staticmethod
+            def some(cls):
+                return super().some(cls)
+
+        for _ in range(ADAPTIVE_WARMUP_DELAY):
+            C.some(C)
 
 
 if __name__ == "__main__":
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-21-14-37-48.gh-issue-106917.1jWp_m.rst
new file mode 100644 (file)
index 0000000..82c74d5
--- /dev/null
@@ -0,0 +1,4 @@
+Fix classmethod-style :func:`super` method calls (i.e., where the second
+argument to :func:`super`, or the implied second argument drawn from
+``self/cls`` in the case of zero-arg super, is a type) when the target of
+the call is not a classmethod.
index 7ce8978e998b97bd6880fc2f068b6117491ee576..0705f5b0aac431f8bcf3cd3bb635783435f50523 100644 (file)
@@ -1721,7 +1721,7 @@ dummy_func(
             PyTypeObject *cls = (PyTypeObject *)class;
             int method_found = 0;
             res2 = _PySuper_Lookup(cls, self, name,
-                                   cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
+                                   Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
             Py_DECREF(global_super);
             Py_DECREF(class);
             if (res2 == NULL) {
index 064965a1a1ae7b67cd36df0e6fac0be517797dc5..0f04b428ba80580fcc8b430f486fcbe5e94b09fb 100644 (file)
             PyTypeObject *cls = (PyTypeObject *)class;
             int method_found = 0;
             res2 = _PySuper_Lookup(cls, self, name,
-                                   cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
+                                   Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
             Py_DECREF(global_super);
             Py_DECREF(class);
             if (res2 == NULL) {
index 9d25fc604314a83c91f95c8cfff6921fbd235441..02ad69a6bc4daf792fbedeca09f882f978c192c5 100644 (file)
             PyTypeObject *cls = (PyTypeObject *)class;
             int method_found = 0;
             res2 = _PySuper_Lookup(cls, self, name,
-                                   cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
+                                   Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL);
             Py_DECREF(global_super);
             Py_DECREF(class);
             if (res2 == NULL) {