Halfway checkin. This is still messy, but it's beginning to address

the problem that slots weren't inherited properly.  override_slots()
no longer exists; in its place comes fixup_slot_dispatchers() which
does more and different work and is table-based.  (Eventually I want
this table also to replace all the little tab_foo tables.)

Also add a wrapper for __delslice__; this required a change in
test_descrtut.py.
This commit is contained in:
Guido van Rossum 2001-10-09 19:39:46 +00:00
parent dca939899d
commit 7b9144b2ee
2 changed files with 299 additions and 137 deletions

View File

@ -190,6 +190,7 @@ Instead, you can get the same information from the list type:
'__contains__',
'__delattr__',
'__delitem__',
'__delslice__',
'__eq__',
'__ge__',
'__getattribute__',

View File

@ -299,7 +299,6 @@ subtype_dealloc(PyObject *self)
}
}
staticforward void override_slots(PyTypeObject *type, PyObject *dict);
staticforward PyTypeObject *solid_base(PyTypeObject *type);
typedef struct {
@ -677,6 +676,8 @@ solid_base(PyTypeObject *type)
staticforward void object_dealloc(PyObject *);
staticforward int object_init(PyObject *, PyObject *, PyObject *);
staticforward int update_slot(PyTypeObject *, PyObject *, PyObject *);
staticforward void fixup_slot_dispatchers(PyTypeObject *);
static PyObject *
subtype_dict(PyObject *obj, void *context)
@ -1011,9 +1012,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
return NULL;
}
/* Override slots that deserve it */
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE))
override_slots(type, type->tp_defined);
/* Put the proper slots in place */
fixup_slot_dispatchers(type);
return (PyObject *)type;
}
@ -1104,9 +1104,12 @@ type_getattro(PyTypeObject *type, PyObject *name)
static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)
return PyObject_GenericSetAttr((PyObject *)type, name, value);
PyErr_SetString(PyExc_TypeError, "can't set type attributes");
if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1;
return update_slot(type, name, value);
}
PyErr_SetString(PyExc_TypeError, "can't set static type attributes");
return -1;
}
@ -1857,11 +1860,7 @@ PyType_Ready(PyTypeObject *type)
inherit_special(type, type->tp_base);
/* Initialize tp_dict properly */
if (PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
/* For a dynamic type, all slots are overridden */
override_slots(type, NULL);
}
else {
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
/* For a static type, tp_dict is the consolidation
of the tp_defined of its bases in MRO. */
Py_DECREF(type->tp_dict);
@ -1881,6 +1880,18 @@ PyType_Ready(PyTypeObject *type)
inherit_slots(type, base);
}
}
else {
/* For a dynamic type, we simply inherit the base slots. */
bases = type->tp_mro;
assert(bases != NULL);
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
for (i = 1; i < n; i++) {
base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
assert(PyType_Check(base));
inherit_slots(type, base);
}
}
/* Some more special stuff */
base = type->tp_base;
@ -1987,7 +1998,7 @@ wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped)
if (!PyArg_ParseTuple(args, "O", &other))
return NULL;
if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
self->ob_type != other->ob_type) {
!PyType_IsSubtype(other->ob_type, self->ob_type)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
@ -2003,7 +2014,7 @@ wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
if (!PyArg_ParseTuple(args, "O", &other))
return NULL;
if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
self->ob_type != other->ob_type) {
!PyType_IsSubtype(other->ob_type, self->ob_type)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
@ -2332,9 +2343,26 @@ wrap_intintobjargproc(PyObject *self, PyObject *args, void *wrapped)
return Py_None;
}
static PyObject *
wrap_delslice(PyObject *self, PyObject *args, void *wrapped)
{
intintobjargproc func = (intintobjargproc)wrapped;
int i, j, res;
if (!PyArg_ParseTuple(args, "ii", &i, &j))
return NULL;
res = (*func)(self, i, j, NULL);
if (res == -1 && PyErr_Occurred())
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static struct wrapperbase tab_setslice[] = {
{"__setslice__", (wrapperfunc)wrap_intintobjargproc,
"x.__setslice__(i, j, y) <==> x[i:j]=y"},
{"__delslice__", (wrapperfunc)wrap_delslice,
"x.__delslice__(i, j) <==> del x[i:j]"},
{0}
};
@ -2609,7 +2637,7 @@ static struct wrapperbase tab_descr_get[] = {
};
static PyObject *
wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
{
descrsetfunc func = (descrsetfunc)wrapped;
PyObject *obj, *value;
@ -2625,7 +2653,7 @@ wrap_descrsetfunc(PyObject *self, PyObject *args, void *wrapped)
}
static struct wrapperbase tab_descr_set[] = {
{"__set__", (wrapperfunc)wrap_descrsetfunc,
{"__set__", (wrapperfunc)wrap_descr_set,
"descr.__set__(obj, value)"},
{0}
};
@ -3638,133 +3666,266 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return x;
}
/* This is called at the very end of type_new() (even after
PyType_Ready()) to complete the initialization of dynamic types.
The dict argument is the dictionary argument passed to type_new(),
which is the local namespace of the class statement, in other
words, it contains the methods. For each special method (like
__repr__) defined in the dictionary, the corresponding function
slot in the type object (like tp_repr) is set to a special function
whose name is 'slot_' followed by the slot name and whose signature
is whatever is required for that slot. These slot functions look
up the corresponding method in the type's dictionary and call it.
The slot functions have to take care of the various peculiarities
of the mapping between slots and special methods, such as mapping
one slot to multiple methods (tp_richcompare <--> __le__, __lt__
etc.) or mapping multiple slots to a single method (sq_item,
mp_subscript <--> __getitem__). */
/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper
functions. The offsets here are relative to the 'etype' structure, which
incorporates the additional structures used for numbers, sequences and
mappings. Note that multiple names may map to the same slot (e.g. __eq__,
__ne__ etc. all map to tp_richcompare) and one name may map to multiple
slots (e.g. __str__ affects tp_str as well as tp_repr). */
typedef struct {
char *name;
int offset;
void *function;
wrapperfunc wrapper;
} slotdef;
#undef TPSLOT
#undef ETSLOT
#undef SQSLOT
#undef MPSLOT
#undef NBSLOT
#undef BINSLOT
#undef RBINSLOT
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
{NAME, offsetof(PyTypeObject, SLOT), FUNCTION, WRAPPER}
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
{NAME, offsetof(etype, SLOT), FUNCTION, WRAPPER}
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER)
#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER)
#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER)
#define BINSLOT(NAME, SLOT, FUNCTION) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l)
#define RBINSLOT(NAME, SLOT, FUNCTION) \
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r)
static slotdef slotdefs[] = {
SQSLOT("__len__", sq_length, slot_sq_length, wrap_inquiry),
SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc),
SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc),
SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc),
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item),
SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_intintargfunc),
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem),
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem),
SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
wrap_intintobjargproc),
SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice),
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc),
SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat,
wrap_binaryfunc),
SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat,
wrap_intargfunc),
MPSLOT("__len__", mp_length, slot_mp_length, wrap_inquiry),
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_sq_item),
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
wrap_objobjargproc),
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
wrap_delitem),
BINSLOT("__add__", nb_add, slot_nb_add),
RBINSLOT("__radd__", nb_add, slot_nb_add),
BINSLOT("__sub__", nb_subtract, slot_nb_subtract),
RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract),
BINSLOT("__mul__", nb_multiply, slot_nb_multiply),
RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply),
BINSLOT("__div__", nb_divide, slot_nb_divide),
RBINSLOT("__rdiv__", nb_divide, slot_nb_divide),
BINSLOT("__mod__", nb_remainder, slot_nb_remainder),
RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder),
BINSLOT("__divmod__", nb_divmod, slot_nb_divmod),
RBINSLOT("__rdivmod__", nb_divmod, slot_nb_divmod),
NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc),
NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r),
NBSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc),
NBSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc),
NBSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc),
NBSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_unaryfunc),
NBSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc),
BINSLOT("__lshift__", nb_lshift, slot_nb_lshift),
RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift),
BINSLOT("__rshift__", nb_rshift, slot_nb_rshift),
RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift),
BINSLOT("__and__", nb_and, slot_nb_and),
RBINSLOT("__rand__", nb_and, slot_nb_and),
BINSLOT("__xor__", nb_xor, slot_nb_xor),
RBINSLOT("__rxor__", nb_xor, slot_nb_xor),
BINSLOT("__or__", nb_or, slot_nb_or),
RBINSLOT("__ror__", nb_or, slot_nb_or),
NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc),
NBSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc),
NBSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc),
NBSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc),
NBSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc),
NBSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc),
NBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
wrap_binaryfunc),
NBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
wrap_binaryfunc),
NBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
wrap_binaryfunc),
NBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
wrap_binaryfunc),
NBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
wrap_binaryfunc),
NBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
wrap_ternaryfunc),
NBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
wrap_binaryfunc),
NBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
wrap_binaryfunc),
NBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
wrap_binaryfunc),
NBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
wrap_binaryfunc),
NBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
wrap_binaryfunc),
BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide),
RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide),
BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide),
RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide),
NBSLOT("__ifloordiv__", nb_inplace_floor_divide,
slot_nb_inplace_floor_divide, wrap_binaryfunc),
NBSLOT("__itruediv__", nb_inplace_true_divide,
slot_nb_inplace_true_divide, wrap_binaryfunc),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc),
TPSLOT("__str__", tp_print, NULL, NULL),
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc),
TPSLOT("__repr__", tp_print, NULL, NULL),
TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc),
TPSLOT("__call__", tp_call, slot_tp_call, wrap_call),
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattro,
wrap_binaryfunc),
TPSLOT("__getattribute__", tp_getattr, NULL, NULL),
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL),
TPSLOT("__getattr__", tp_getattr, NULL, NULL),
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr),
TPSLOT("__setattr__", tp_setattr, NULL, NULL),
TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr),
TPSLOT("__delattr__", tp_setattr, NULL, NULL),
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt),
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le),
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq),
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne),
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt),
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge),
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc),
TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next),
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get),
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set),
TPSLOT("__init__", tp_init, slot_tp_init, wrap_init),
TPSLOT("__new__", tp_new, slot_tp_new, NULL),
{NULL}
};
static int
update_slot(PyTypeObject *type, PyObject *name, PyObject *value)
{
char *s;
int n;
slotdef *p;
void **ptr;
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
if (value == NULL)
return 0; /* Can't unset a slot */
s = PyString_AsString(name);
n = PyString_Size(name);
if (s == NULL || n < 0) {
/* Shouldn't happen, but can't be bothered */
PyErr_Clear();
return 0;
}
if (!(s[0] == '_' && s[1] == '_' && s[n-1] == '_' && s[n-2] == '_'))
return 0;
for (p = slotdefs; p->name; p++) {
if (!strcmp(p->name, s)) {
ptr = (void **) ((char *)type + p->offset);
*ptr = p->function;
}
}
return 0;
}
static void **
slotptr(PyTypeObject *type, int offset)
{
char *ptr;
assert(offset >= 0);
assert(offset < offsetof(etype, as_buffer));
if (offset >= offsetof(etype, as_mapping)) {
ptr = (void *)type->tp_as_mapping;
offset -= offsetof(etype, as_mapping);
}
else if (offset >= offsetof(etype, as_sequence)) {
ptr = (void *)type->tp_as_sequence;
offset -= offsetof(etype, as_sequence);
}
else if (offset >= offsetof(etype, as_number)) {
ptr = (void *)type->tp_as_number;
offset -= offsetof(etype, as_number);
}
else {
ptr = (void *)type;
}
if (ptr != NULL)
ptr += offset;
return (void **)ptr;
}
static void
override_slots(PyTypeObject *type, PyObject *dict)
fixup_slot_dispatchers(PyTypeObject *type)
{
PySequenceMethods *sq = type->tp_as_sequence;
PyMappingMethods *mp = type->tp_as_mapping;
PyNumberMethods *nb = type->tp_as_number;
slotdef *p;
PyObject *mro, *descr;
PyTypeObject *base;
PyWrapperDescrObject *d;
int i, n;
void **ptr;
#define SQSLOT(OPNAME, SLOTNAME, FUNCNAME) \
if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
sq->SLOTNAME = FUNCNAME; \
for (p = slotdefs; p->name; p++) {
ptr = slotptr(type, p->offset);
if (ptr)
*ptr = NULL;
}
#define MPSLOT(OPNAME, SLOTNAME, FUNCNAME) \
if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
mp->SLOTNAME = FUNCNAME; \
mro = type->tp_mro;
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
for (p = slotdefs; p->name; p++) {
for (i = 0; i < n; i++) {
base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);
assert(PyType_Check(base));
descr = PyDict_GetItemString(
base->tp_defined, p->name);
if (descr == NULL)
continue;
ptr = slotptr(type, p->offset);
if (ptr == NULL)
continue;
if (descr->ob_type == &PyWrapperDescr_Type) {
d = (PyWrapperDescrObject *)descr;
if (d->d_base->wrapper == p->wrapper) {
if (*ptr == NULL) {
*ptr = d->d_wrapped;
continue;
}
if (p->wrapper == wrap_binaryfunc_r)
continue;
}
}
*ptr = p->function;
break;
}
}
#define NBSLOT(OPNAME, SLOTNAME, FUNCNAME) \
if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
nb->SLOTNAME = FUNCNAME; \
}
#define TPSLOT(OPNAME, SLOTNAME, FUNCNAME) \
if (dict == NULL || PyDict_GetItemString(dict, OPNAME)) { \
type->SLOTNAME = FUNCNAME; \
}
SQSLOT("__len__", sq_length, slot_sq_length);
SQSLOT("__add__", sq_concat, slot_sq_concat);
SQSLOT("__mul__", sq_repeat, slot_sq_repeat);
SQSLOT("__getitem__", sq_item, slot_sq_item);
SQSLOT("__getslice__", sq_slice, slot_sq_slice);
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item);
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item);
SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice);
SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice);
SQSLOT("__contains__", sq_contains, slot_sq_contains);
SQSLOT("__iadd__", sq_inplace_concat, slot_sq_inplace_concat);
SQSLOT("__imul__", sq_inplace_repeat, slot_sq_inplace_repeat);
MPSLOT("__len__", mp_length, slot_mp_length);
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript);
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript);
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript);
NBSLOT("__add__", nb_add, slot_nb_add);
NBSLOT("__sub__", nb_subtract, slot_nb_subtract);
NBSLOT("__mul__", nb_multiply, slot_nb_multiply);
NBSLOT("__div__", nb_divide, slot_nb_divide);
NBSLOT("__mod__", nb_remainder, slot_nb_remainder);
NBSLOT("__divmod__", nb_divmod, slot_nb_divmod);
NBSLOT("__pow__", nb_power, slot_nb_power);
NBSLOT("__neg__", nb_negative, slot_nb_negative);
NBSLOT("__pos__", nb_positive, slot_nb_positive);
NBSLOT("__abs__", nb_absolute, slot_nb_absolute);
NBSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero);
NBSLOT("__invert__", nb_invert, slot_nb_invert);
NBSLOT("__lshift__", nb_lshift, slot_nb_lshift);
NBSLOT("__rshift__", nb_rshift, slot_nb_rshift);
NBSLOT("__and__", nb_and, slot_nb_and);
NBSLOT("__xor__", nb_xor, slot_nb_xor);
NBSLOT("__or__", nb_or, slot_nb_or);
NBSLOT("__coerce__", nb_coerce, slot_nb_coerce);
NBSLOT("__int__", nb_int, slot_nb_int);
NBSLOT("__long__", nb_long, slot_nb_long);
NBSLOT("__float__", nb_float, slot_nb_float);
NBSLOT("__oct__", nb_oct, slot_nb_oct);
NBSLOT("__hex__", nb_hex, slot_nb_hex);
NBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add);
NBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract);
NBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply);
NBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide);
NBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder);
NBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power);
NBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift);
NBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift);
NBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and);
NBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor);
NBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or);
NBSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide);
NBSLOT("__truediv__", nb_true_divide, slot_nb_true_divide);
NBSLOT("__ifloordiv__", nb_inplace_floor_divide,
slot_nb_inplace_floor_divide);
NBSLOT("__itruediv__", nb_inplace_true_divide,
slot_nb_inplace_true_divide);
if (dict == NULL ||
PyDict_GetItemString(dict, "__str__") ||
PyDict_GetItemString(dict, "__repr__"))
type->tp_print = NULL;
TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare);
TPSLOT("__repr__", tp_repr, slot_tp_repr);
TPSLOT("__hash__", tp_hash, slot_tp_hash);
TPSLOT("__call__", tp_call, slot_tp_call);
TPSLOT("__str__", tp_str, slot_tp_str);
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattro);
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook);
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro);
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare);
TPSLOT("__iter__", tp_iter, slot_tp_iter);
TPSLOT("next", tp_iternext, slot_tp_iternext);
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get);
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set);
TPSLOT("__init__", tp_init, slot_tp_init);
TPSLOT("__new__", tp_new, slot_tp_new);
}