gh-132284: Don't wrap base PyCFunction slots on class creation if not overridden (#132329)

This commit is contained in:
Tomasz Pytel 2025-04-17 13:08:59 -04:00 committed by GitHub
parent 5707837049
commit a23ed8b379
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 1 deletions

View File

@ -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:

View File

@ -1838,6 +1838,23 @@ class ClassCreationTests(unittest.TestCase):
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.

View File

@ -0,0 +1 @@
Don't wrap base ``PyCFunction`` slots on class creation if not overridden.

View File

@ -11233,7 +11233,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);