Skip to content

Commit a23ed8b

Browse files
authored
gh-132284: Don't wrap base PyCFunction slots on class creation if not overridden (#132329)
1 parent 5707837 commit a23ed8b

File tree

4 files changed

+30
-1
lines changed

4 files changed

+30
-1
lines changed

Doc/whatsnew/3.14.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,10 @@ Other language changes
469469
of HMAC is not available.
470470
(Contributed by Bénédikt Tran in :gh:`99108`.)
471471

472+
* When subclassing from a pure C type, the C slots for the new type are no
473+
longer replaced with a wrapped version on class creation if they are not
474+
explicitly overridden in the subclass.
475+
(Contributed by Tomasz Pytel in :gh:`132329`.)
472476

473477
.. _whatsnew314-pep765:
474478

Lib/test/test_types.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,23 @@ class Model(metaclass=ModelBase):
18381838
with self.assertRaises(RuntimeWarning):
18391839
type("SouthPonies", (Model,), {})
18401840

1841+
def test_subclass_inherited_slot_update(self):
1842+
# gh-132284: Make sure slot update still works after fix.
1843+
# Note that after assignment to D.__getitem__ the actual C slot will
1844+
# never go back to dict_subscript as it was on class type creation but
1845+
# rather be set to slot_mp_subscript, unfortunately there is no way to
1846+
# check that here.
1847+
1848+
class D(dict):
1849+
pass
1850+
1851+
d = D({None: None})
1852+
self.assertIs(d[None], None)
1853+
D.__getitem__ = lambda self, item: 42
1854+
self.assertEqual(d[None], 42)
1855+
D.__getitem__ = dict.__getitem__
1856+
self.assertIs(d[None], None)
1857+
18411858
def test_tuple_subclass_as_bases(self):
18421859
# gh-132176: it used to crash on using
18431860
# tuple subclass for as base classes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't wrap base ``PyCFunction`` slots on class creation if not overridden.

Objects/typeobject.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11233,7 +11233,14 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p)
1123311233
}
1123411234
else {
1123511235
use_generic = 1;
11236-
generic = p->function;
11236+
if (generic == NULL && Py_IS_TYPE(descr, &PyMethodDescr_Type) &&
11237+
*ptr == ((PyMethodDescrObject *)descr)->d_method->ml_meth)
11238+
{
11239+
generic = *ptr;
11240+
}
11241+
else {
11242+
generic = p->function;
11243+
}
1123711244
if (p->function == slot_tp_call) {
1123811245
/* A generic __call__ is incompatible with vectorcall */
1123911246
type_clear_flags(type, Py_TPFLAGS_HAVE_VECTORCALL);

0 commit comments

Comments
 (0)