Skip to content

Commit ecb14da

Browse files
Preserve the behavior for explicitly inherited slots.
1 parent 1a6a50e commit ecb14da

File tree

1 file changed

+70
-2
lines changed

1 file changed

+70
-2
lines changed

Objects/typeobject.c

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11033,6 +11033,63 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
1103311033
return 0;
1103411034
}
1103511035

11036+
static int
11037+
expect_manually_inherited(PyTypeObject *type, void **slot)
11038+
{
11039+
PyObject *typeobj = (PyObject *)type;
11040+
if (slot == (void *)&type->tp_init) {
11041+
if (typeobj != PyExc_BaseException
11042+
&& typeobj != PyExc_BaseExceptionGroup
11043+
&& typeobj != PyExc_ImportError
11044+
&& typeobj != PyExc_NameError
11045+
&& typeobj != PyExc_OSError
11046+
&& typeobj != PyExc_StopIteration
11047+
&& typeobj != PyExc_SyntaxError
11048+
&& typeobj != PyExc_UnicodeDecodeError
11049+
&& typeobj != PyExc_UnicodeEncodeError)
11050+
{
11051+
return 1;
11052+
}
11053+
}
11054+
else if (slot == (void *)&type->tp_str) {
11055+
if (typeobj == PyExc_AttributeError || typeobj == PyExc_NameError) {
11056+
return 1;
11057+
}
11058+
}
11059+
else if (slot == (void *)&type->tp_getattr
11060+
|| slot == (void *)&type->tp_getattro)
11061+
{
11062+
if (typeobj == PyExc_BaseException
11063+
|| type == &PyBool_Type
11064+
|| type == &PyByteArray_Type
11065+
|| type == &PyBytes_Type
11066+
|| type == &PyClassMethod_Type
11067+
|| type == &PyComplex_Type
11068+
|| type == &PyDict_Type
11069+
|| type == &PyEnum_Type
11070+
|| type == &PyFilter_Type
11071+
|| type == &PyLong_Type
11072+
|| type == &PyList_Type
11073+
|| type == &PyMap_Type
11074+
|| type == &PyMemoryView_Type
11075+
|| type == &PyProperty_Type
11076+
|| type == &PyRange_Type
11077+
|| type == &PyReversed_Type
11078+
|| type == &PySet_Type
11079+
|| type == &PySlice_Type
11080+
|| type == &PyStaticMethod_Type
11081+
|| type == &PySuper_Type
11082+
|| type == &PyTuple_Type
11083+
|| type == &PyZip_Type)
11084+
{
11085+
return 1;
11086+
}
11087+
}
11088+
11089+
/* It must be inherited (see type_ready_inherit()).. */
11090+
return 0;
11091+
}
11092+
1103611093
/* This function is called by PyType_Ready() to populate the type's
1103711094
dictionary with method descriptors for function slots. For each
1103811095
function slot (like tp_repr) that's defined in the type, one or more
@@ -11080,10 +11137,21 @@ add_operators(PyTypeObject *type)
1108011137
if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN
1108111138
&& type->tp_base != NULL)
1108211139
{
11140+
/* Also ignore when the type slot has been inherited. */
1108311141
void **ptr_base = slotptr(type->tp_base, p->offset);
1108411142
if (ptr_base && *ptr == *ptr_base) {
11085-
/* It must have been inherited (see type_ready_inherit()).. */
11086-
continue;
11143+
/* Ideally we would always ignore any manually inherited
11144+
slots, Which would mean inheriting the slot wrapper
11145+
using normal attribute lookup rather than keeping
11146+
a distinct copy. However, that would introduce
11147+
a slight change in behavior that could break
11148+
existing code.
11149+
11150+
In the meantime, look the other way when the definition
11151+
explicitly inherits the slot. */
11152+
if (!expect_manually_inherited(type, ptr)) {
11153+
continue;
11154+
}
1108711155
}
1108811156
}
1108911157
int r = PyDict_Contains(dict, p->name_strobj);

0 commit comments

Comments
 (0)