@@ -11033,6 +11033,63 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name,
11033
11033
return 0 ;
11034
11034
}
11035
11035
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
+
11036
11093
/* This function is called by PyType_Ready() to populate the type's
11037
11094
dictionary with method descriptors for function slots. For each
11038
11095
function slot (like tp_repr) that's defined in the type, one or more
@@ -11080,10 +11137,21 @@ add_operators(PyTypeObject *type)
11080
11137
if (type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN
11081
11138
&& type -> tp_base != NULL )
11082
11139
{
11140
+ /* Also ignore when the type slot has been inherited. */
11083
11141
void * * ptr_base = slotptr (type -> tp_base , p -> offset );
11084
11142
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
+ }
11087
11155
}
11088
11156
}
11089
11157
int r = PyDict_Contains (dict , p -> name_strobj );
0 commit comments