Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ 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.

.. _whatsnew314-pep765:

Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Don't wrap base ``PyCFunction`` slots on class creation if not overridden.
9 changes: 8 additions & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -11204,7 +11204,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);
Expand Down
Loading