diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index c50d1669fef84c..7d469e83dc27ad 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -469,6 +469,10 @@ Other language changes of HMAC is not available. (Contributed by Bénédikt Tran in :gh:`99108`.) +* When subclassing from a pure C type, the C slots for the new type are no + longer replaced with a wrapped version on class creation if they are not + explicitly overridden in the subclass. + (Contributed by Tomasz Pytel in :gh:`132329`.) .. _whatsnew314-pep765: diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 87081a6db4ea48..e5d80ee8eb7aca 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -1838,6 +1838,23 @@ class Model(metaclass=ModelBase): with self.assertRaises(RuntimeWarning): type("SouthPonies", (Model,), {}) + def test_subclass_inherited_slot_update(self): + # gh-132284: Make sure slot update still works after fix. + # Note that after assignment to D.__getitem__ the actual C slot will + # never go back to dict_subscript as it was on class type creation but + # rather be set to slot_mp_subscript, unfortunately there is no way to + # check that here. + + class D(dict): + pass + + d = D({None: None}) + self.assertIs(d[None], None) + D.__getitem__ = lambda self, item: 42 + self.assertEqual(d[None], 42) + D.__getitem__ = dict.__getitem__ + self.assertIs(d[None], None) + def test_tuple_subclass_as_bases(self): # gh-132176: it used to crash on using # tuple subclass for as base classes. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-20-49-04.gh-issue-132284.TxTNka.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-20-49-04.gh-issue-132284.TxTNka.rst new file mode 100644 index 00000000000000..b63a75f1e7e058 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-09-20-49-04.gh-issue-132284.TxTNka.rst @@ -0,0 +1 @@ +Don't wrap base ``PyCFunction`` slots on class creation if not overridden. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 63e153e6715c17..d4d96b958489cf 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -11237,7 +11237,14 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p) } else { use_generic = 1; - generic = p->function; + if (generic == NULL && Py_IS_TYPE(descr, &PyMethodDescr_Type) && + *ptr == ((PyMethodDescrObject *)descr)->d_method->ml_meth) + { + generic = *ptr; + } + else { + generic = p->function; + } if (p->function == slot_tp_call) { /* A generic __call__ is incompatible with vectorcall */ type_clear_flags(type, Py_TPFLAGS_HAVE_VECTORCALL);