- Big changes to fix SF bug #442833 (a nasty multiple inheritance
problem). inherit_slots() is split in two parts: inherit_special() which inherits the flags and a few very special members from the dominant base; inherit_slots() which inherits only regular slots, and is now called for each base in the MRO in turn. These are now both void functions since they don't have error returns. - Added object.__setitem__() back -- for the same reason as object.__new__(): a subclass of object should be able to call object.__new__(). - add_wrappers() was moved around to be closer to where it is used (it was defined together with add_methods() etc., but has nothing to do with these).
This commit is contained in:
parent
f24b2f3285
commit
13d52f0b32
@ -4,8 +4,6 @@
|
|||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
|
||||||
staticforward int add_members(PyTypeObject *, struct memberlist *);
|
|
||||||
|
|
||||||
static struct memberlist type_members[] = {
|
static struct memberlist type_members[] = {
|
||||||
{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
|
{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
|
||||||
{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
|
{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
|
||||||
@ -647,7 +645,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||||||
slotoffset += sizeof(PyObject *);
|
slotoffset += sizeof(PyObject *);
|
||||||
}
|
}
|
||||||
type->tp_basicsize = slotoffset;
|
type->tp_basicsize = slotoffset;
|
||||||
add_members(type, et->members);
|
type->tp_members = et->members;
|
||||||
|
|
||||||
/* Special case some slots */
|
/* Special case some slots */
|
||||||
if (type->tp_dictoffset != 0 || nslots > 0) {
|
if (type->tp_dictoffset != 0 || nslots > 0) {
|
||||||
@ -882,7 +880,7 @@ PyTypeObject PyBaseObject_Type = {
|
|||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
PyObject_GenericSetAttr, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
0, /* tp_as_buffer */
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||||
"The most base type", /* tp_doc */
|
"The most base type", /* tp_doc */
|
||||||
@ -928,25 +926,6 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
|
|
||||||
{
|
|
||||||
PyObject *dict = type->tp_defined;
|
|
||||||
|
|
||||||
for (; wraps->name != NULL; wraps++) {
|
|
||||||
PyObject *descr;
|
|
||||||
if (PyDict_GetItemString(dict, wraps->name))
|
|
||||||
continue;
|
|
||||||
descr = PyDescr_NewWrapper(type, wraps, wrapped);
|
|
||||||
if (descr == NULL)
|
|
||||||
return -1;
|
|
||||||
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
|
|
||||||
return -1;
|
|
||||||
Py_DECREF(descr);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_members(PyTypeObject *type, struct memberlist *memb)
|
add_members(PyTypeObject *type, struct memberlist *memb)
|
||||||
{
|
{
|
||||||
@ -986,27 +965,90 @@ add_getset(PyTypeObject *type, struct getsetlist *gsp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
staticforward int add_operators(PyTypeObject *);
|
static void
|
||||||
|
inherit_special(PyTypeObject *type, PyTypeObject *base)
|
||||||
static int
|
|
||||||
inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
|
||||||
{
|
{
|
||||||
int oldsize, newsize;
|
int oldsize, newsize;
|
||||||
|
|
||||||
|
/* Special flag magic */
|
||||||
|
if (!type->tp_as_buffer && base->tp_as_buffer) {
|
||||||
|
type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
|
||||||
|
type->tp_flags |=
|
||||||
|
base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
|
||||||
|
}
|
||||||
|
if (!type->tp_as_sequence && base->tp_as_sequence) {
|
||||||
|
type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
|
||||||
|
type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
|
||||||
|
}
|
||||||
|
if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
|
||||||
|
(base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
|
||||||
|
if ((!type->tp_as_number && base->tp_as_number) ||
|
||||||
|
(!type->tp_as_sequence && base->tp_as_sequence)) {
|
||||||
|
type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
|
||||||
|
if (!type->tp_as_number && !type->tp_as_sequence) {
|
||||||
|
type->tp_flags |= base->tp_flags &
|
||||||
|
Py_TPFLAGS_HAVE_INPLACEOPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Wow */
|
||||||
|
}
|
||||||
|
if (!type->tp_as_number && base->tp_as_number) {
|
||||||
|
type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
|
||||||
|
type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copying basicsize is connected to the GC flags */
|
||||||
|
oldsize = PyType_BASICSIZE(base);
|
||||||
|
newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
|
||||||
|
if (!(type->tp_flags & Py_TPFLAGS_GC) &&
|
||||||
|
(base->tp_flags & Py_TPFLAGS_GC) &&
|
||||||
|
(type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
|
||||||
|
(!type->tp_traverse && !type->tp_clear)) {
|
||||||
|
type->tp_flags |= Py_TPFLAGS_GC;
|
||||||
|
if (type->tp_traverse == NULL)
|
||||||
|
type->tp_traverse = base->tp_traverse;
|
||||||
|
if (type->tp_clear == NULL)
|
||||||
|
type->tp_clear = base->tp_clear;
|
||||||
|
}
|
||||||
|
if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
|
||||||
|
if (base != &PyBaseObject_Type ||
|
||||||
|
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
||||||
|
if (type->tp_new == NULL)
|
||||||
|
type->tp_new = base->tp_new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyType_SET_BASICSIZE(type, newsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
||||||
|
{
|
||||||
|
PyTypeObject *basebase;
|
||||||
|
|
||||||
|
#undef SLOTDEFINED
|
||||||
#undef COPYSLOT
|
#undef COPYSLOT
|
||||||
#undef COPYNUM
|
#undef COPYNUM
|
||||||
#undef COPYSEQ
|
#undef COPYSEQ
|
||||||
#undef COPYMAP
|
#undef COPYMAP
|
||||||
|
|
||||||
|
#define SLOTDEFINED(SLOT) \
|
||||||
|
(base->SLOT != 0 && \
|
||||||
|
(basebase == NULL || base->SLOT != basebase->SLOT))
|
||||||
|
|
||||||
#define COPYSLOT(SLOT) \
|
#define COPYSLOT(SLOT) \
|
||||||
if (!type->SLOT) type->SLOT = base->SLOT
|
if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT
|
||||||
|
|
||||||
#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
|
#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
|
||||||
#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
|
#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
|
||||||
#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
|
#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
|
||||||
|
|
||||||
if (type->tp_as_number == NULL)
|
/* This won't inherit indirect slots (from tp_as_number etc.)
|
||||||
type->tp_as_number = base->tp_as_number;
|
if type doesn't provide the space. */
|
||||||
else if (base->tp_as_number) {
|
|
||||||
|
if (type->tp_as_number != NULL && base->tp_as_number != NULL) {
|
||||||
|
basebase = base->tp_base;
|
||||||
|
if (basebase->tp_as_number == NULL)
|
||||||
|
basebase = NULL;
|
||||||
COPYNUM(nb_add);
|
COPYNUM(nb_add);
|
||||||
COPYNUM(nb_subtract);
|
COPYNUM(nb_subtract);
|
||||||
COPYNUM(nb_multiply);
|
COPYNUM(nb_multiply);
|
||||||
@ -1049,9 +1091,10 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->tp_as_sequence == NULL)
|
if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
|
||||||
type->tp_as_sequence = base->tp_as_sequence;
|
basebase = base->tp_base;
|
||||||
else if (base->tp_as_sequence) {
|
if (basebase->tp_as_sequence == NULL)
|
||||||
|
basebase = NULL;
|
||||||
COPYSEQ(sq_length);
|
COPYSEQ(sq_length);
|
||||||
COPYSEQ(sq_concat);
|
COPYSEQ(sq_concat);
|
||||||
COPYSEQ(sq_repeat);
|
COPYSEQ(sq_repeat);
|
||||||
@ -1064,53 +1107,16 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
|||||||
COPYSEQ(sq_inplace_repeat);
|
COPYSEQ(sq_inplace_repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->tp_as_mapping == NULL)
|
if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) {
|
||||||
type->tp_as_mapping = base->tp_as_mapping;
|
basebase = base->tp_base;
|
||||||
else if (base->tp_as_mapping) {
|
if (basebase->tp_as_mapping == NULL)
|
||||||
|
basebase = NULL;
|
||||||
COPYMAP(mp_length);
|
COPYMAP(mp_length);
|
||||||
COPYMAP(mp_subscript);
|
COPYMAP(mp_subscript);
|
||||||
COPYMAP(mp_ass_subscript);
|
COPYMAP(mp_ass_subscript);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Special flag magic */
|
basebase = base->tp_base;
|
||||||
if (!type->tp_as_buffer && base->tp_as_buffer) {
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
|
|
||||||
type->tp_flags |=
|
|
||||||
base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
|
|
||||||
}
|
|
||||||
if (!type->tp_as_sequence && base->tp_as_sequence) {
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
|
|
||||||
type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
|
|
||||||
}
|
|
||||||
if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
|
|
||||||
(base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
|
|
||||||
if ((!type->tp_as_number && base->tp_as_number) ||
|
|
||||||
(!type->tp_as_sequence && base->tp_as_sequence)) {
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
|
|
||||||
if (!type->tp_as_number && !type->tp_as_sequence) {
|
|
||||||
type->tp_flags |= base->tp_flags &
|
|
||||||
Py_TPFLAGS_HAVE_INPLACEOPS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Wow */
|
|
||||||
}
|
|
||||||
if (!type->tp_as_number && base->tp_as_number) {
|
|
||||||
type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
|
|
||||||
type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copying basicsize is connected to the GC flags */
|
|
||||||
oldsize = PyType_BASICSIZE(base);
|
|
||||||
newsize = type->tp_basicsize ? PyType_BASICSIZE(type) : oldsize;
|
|
||||||
if (!(type->tp_flags & Py_TPFLAGS_GC) &&
|
|
||||||
(base->tp_flags & Py_TPFLAGS_GC) &&
|
|
||||||
(type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
|
|
||||||
(!type->tp_traverse && !type->tp_clear)) {
|
|
||||||
type->tp_flags |= Py_TPFLAGS_GC;
|
|
||||||
COPYSLOT(tp_traverse);
|
|
||||||
COPYSLOT(tp_clear);
|
|
||||||
}
|
|
||||||
PyType_SET_BASICSIZE(type, newsize);
|
|
||||||
|
|
||||||
COPYSLOT(tp_itemsize);
|
COPYSLOT(tp_itemsize);
|
||||||
COPYSLOT(tp_dealloc);
|
COPYSLOT(tp_dealloc);
|
||||||
@ -1152,16 +1158,12 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
|||||||
COPYSLOT(tp_dictoffset);
|
COPYSLOT(tp_dictoffset);
|
||||||
COPYSLOT(tp_init);
|
COPYSLOT(tp_init);
|
||||||
COPYSLOT(tp_alloc);
|
COPYSLOT(tp_alloc);
|
||||||
if (base != &PyBaseObject_Type ||
|
|
||||||
(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
|
||||||
COPYSLOT(tp_new);
|
|
||||||
}
|
|
||||||
COPYSLOT(tp_free);
|
COPYSLOT(tp_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
staticforward int add_operators(PyTypeObject *);
|
||||||
|
|
||||||
int
|
int
|
||||||
PyType_Ready(PyTypeObject *type)
|
PyType_Ready(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
@ -1237,34 +1239,44 @@ PyType_Ready(PyTypeObject *type)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inherit special flags from dominant base */
|
||||||
|
if (type->tp_base != NULL)
|
||||||
|
inherit_special(type, type->tp_base);
|
||||||
|
|
||||||
/* Initialize tp_dict properly */
|
/* Initialize tp_dict properly */
|
||||||
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
|
if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
|
||||||
/* For a static type, tp_dict is the consolidation
|
/* For a static type, tp_dict is the consolidation
|
||||||
of the tp_defined of its bases in MRO. Earlier
|
of the tp_defined of its bases in MRO. */
|
||||||
bases override later bases; since d.update() works
|
|
||||||
the other way, we walk the MRO sequence backwards. */
|
|
||||||
Py_DECREF(type->tp_dict);
|
Py_DECREF(type->tp_dict);
|
||||||
type->tp_dict = PyDict_New();
|
type->tp_dict = PyDict_Copy(type->tp_defined);
|
||||||
if (type->tp_dict == NULL)
|
if (type->tp_dict == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
bases = type->tp_mro;
|
bases = type->tp_mro;
|
||||||
assert(bases != NULL);
|
assert(bases != NULL);
|
||||||
assert(PyTuple_Check(bases));
|
assert(PyTuple_Check(bases));
|
||||||
n = PyTuple_GET_SIZE(bases);
|
n = PyTuple_GET_SIZE(bases);
|
||||||
for (i = n; --i >= 0; ) {
|
for (i = 1; i < n; i++) {
|
||||||
base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
|
base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
|
||||||
assert(PyType_Check(base));
|
assert(PyType_Check(base));
|
||||||
x = base->tp_defined;
|
x = base->tp_defined;
|
||||||
if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
|
if (x != NULL && PyDict_Merge(type->tp_dict, x, 0) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
inherit_slots(type, base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inherit slots from direct base */
|
/* Some more special stuff */
|
||||||
if (type->tp_base != NULL)
|
base = type->tp_base;
|
||||||
if (inherit_slots(type, type->tp_base) < 0)
|
if (base != NULL) {
|
||||||
goto error;
|
if (type->tp_as_number == NULL)
|
||||||
|
type->tp_as_number = base->tp_as_number;
|
||||||
|
if (type->tp_as_sequence == NULL)
|
||||||
|
type->tp_as_sequence = base->tp_as_sequence;
|
||||||
|
if (type->tp_as_mapping == NULL)
|
||||||
|
type->tp_as_mapping = base->tp_as_mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All done -- set the ready flag */
|
||||||
assert(type->tp_dict != NULL);
|
assert(type->tp_dict != NULL);
|
||||||
type->tp_flags =
|
type->tp_flags =
|
||||||
(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
|
(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
|
||||||
@ -1911,6 +1923,25 @@ add_tp_new_wrapper(PyTypeObject *type)
|
|||||||
return PyDict_SetItemString(type->tp_defined, "__new__", func);
|
return PyDict_SetItemString(type->tp_defined, "__new__", func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
add_wrappers(PyTypeObject *type, struct wrapperbase *wraps, void *wrapped)
|
||||||
|
{
|
||||||
|
PyObject *dict = type->tp_defined;
|
||||||
|
|
||||||
|
for (; wraps->name != NULL; wraps++) {
|
||||||
|
PyObject *descr;
|
||||||
|
if (PyDict_GetItemString(dict, wraps->name))
|
||||||
|
continue;
|
||||||
|
descr = PyDescr_NewWrapper(type, wraps, wrapped);
|
||||||
|
if (descr == NULL)
|
||||||
|
return -1;
|
||||||
|
if (PyDict_SetItemString(dict, wraps->name, descr) < 0)
|
||||||
|
return -1;
|
||||||
|
Py_DECREF(descr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function is called by PyType_Ready() to populate the type's
|
/* This function is called by PyType_Ready() to populate the type's
|
||||||
dictionary with method descriptors for function slots. For each
|
dictionary with method descriptors for function slots. For each
|
||||||
function slot (like tp_repr) that's defined in the type, one or
|
function slot (like tp_repr) that's defined in the type, one or
|
||||||
|
Loading…
x
Reference in New Issue
Block a user