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