Index: typeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v retrieving revision 2.187 diff -c -r2.187 typeobject.c *** typeobject.c 14 Nov 2002 23:22:33 -0000 2.187 --- typeobject.c 20 Nov 2002 16:03:24 -0000 *************** *** 5,10 **** --- 5,17 ---- #include + static PyTypeObject *best_base(PyObject *bases); + static int mro_internal(PyTypeObject *type); + static int compatible_for_assignment(PyTypeObject* old, PyTypeObject* new); + static int add_subclass(PyTypeObject *base, PyTypeObject *type); + static int remove_subclass(PyTypeObject *base, PyTypeObject *type); + static void inherit_slots(PyTypeObject *type, PyTypeObject *base); + /* The *real* layout of a type object when allocated on the heap */ /* XXX Should we publish this in a header file? */ typedef struct { *************** *** 32,38 **** {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY}, {"__dictoffset__", T_LONG, offsetof(PyTypeObject, tp_dictoffset), READONLY}, - {"__bases__", T_OBJECT, offsetof(PyTypeObject, tp_bases), READONLY}, {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY}, {0} }; --- 39,44 ---- *************** *** 50,55 **** --- 56,102 ---- return PyString_FromString(s); } + static int + type_set_name(PyTypeObject *type, PyObject *value, void *context) + { + etype* et; + + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) || + strrchr(type->tp_name, '.')) { + PyErr_Format(PyExc_TypeError, + "can't set %s.__name__", type->tp_name); + return -1; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.__name__", type->tp_name); + return -1; + } + if (!PyString_Check(value)) { + PyErr_Format(PyExc_TypeError, + "can only assign string to %s.__name__, not '%s'", + type->tp_name, value->ob_type->tp_name); + return -1; + } + if (strchr(PyString_AS_STRING(value), '.') != NULL) { + PyErr_Format(PyExc_ValueError, + "can't assign dotted string to %s.__name__", + type->tp_name); + return -1; + } + + et = (etype*)type; + + Py_INCREF(value); + + Py_DECREF(et->name); + et->name = value; + + type->tp_name = PyString_AS_STRING(value); + + return 0; + } + static PyObject * type_module(PyTypeObject *type, void *context) { *************** *** 63,69 **** if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) return PyString_FromString("__builtin__"); mod = PyDict_GetItemString(type->tp_dict, "__module__"); ! if (mod != NULL && PyString_Check(mod)) { Py_INCREF(mod); return mod; } --- 110,116 ---- if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) return PyString_FromString("__builtin__"); mod = PyDict_GetItemString(type->tp_dict, "__module__"); ! if (mod != NULL) { Py_INCREF(mod); return mod; } *************** *** 85,94 **** --- 132,252 ---- "can't delete %s.__module__", type->tp_name); return -1; } + return PyDict_SetItemString(type->tp_dict, "__module__", value); } static PyObject * + type_get_bases(PyTypeObject *type, void *context) + { + Py_INCREF(type->tp_bases); + return type->tp_bases; + } + + static int + type_set_bases(PyTypeObject *type, PyObject *value, void *context) + { + int i; + PyObject* ob; + PyTypeObject *new_base, *old_base; + PyObject* old_bases; + + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) || + strrchr(type->tp_name, '.')) { + PyErr_Format(PyExc_TypeError, + "can't set %s.__bases__", type->tp_name); + return -1; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.__bases__", type->tp_name); + return -1; + } + if (!PyTuple_Check(value)) { + PyErr_Format(PyExc_TypeError, + "can only assign tuple to %s.__bases__, not %s", + type->tp_name, value->ob_type->tp_name); + return -1; + } + for (i = 0; i < PyTuple_GET_SIZE(value); i++) { + ob = PyTuple_GET_ITEM(value, i); + if (!PyClass_Check(ob) && !PyType_Check(ob)) { + PyErr_Format( + PyExc_TypeError, + "%s.__bases__ must be tuple of old- or new-style classes, not '%s'", + type->tp_name, ob->ob_type->tp_name); + return -1; + } + } + + new_base = best_base(value); + + if (!new_base) { + return -1; + } + + if (compatible_for_assignment(type->tp_base, new_base)) { + Py_INCREF(new_base); + Py_INCREF(value); + + old_bases = type->tp_bases; + old_base = type->tp_base; + + type->tp_bases = value; + type->tp_base = new_base; + + + if (mro_internal(type) < 0) { + /* wtf do we do here !? */ + type->tp_bases = old_bases; + type->tp_base = old_base; + + Py_DECREF(value); + Py_DECREF(new_base); + + mro_internal(type); + + return -1; + } + else { + /* any base that was in __bases__ but now isn't, we + need to remove |type| from it's tp_subclasses. + conversely, any class now in __bases__ that wasn't + needs to have |type| added to it's subclasses. */ + + /* for now, sod that: just remove from all old_bases, + add to all new_bases */ + + for (i = PyTuple_GET_SIZE(old_bases) - 1; + i >= 0; i--) { + remove_subclass( + (PyTypeObject*)PyTuple_GET_ITEM( + old_bases, i), + type); + } + for (i = PyTuple_GET_SIZE(value) - 1; + i >= 0; i--) { + add_subclass( + (PyTypeObject*)PyTuple_GET_ITEM( + value, i), + type); + } + + /* we also need to worry about some hooks, like + __getattribute__ ... */ + + Py_DECREF(old_bases); + Py_DECREF(old_base); + } + + return 0; + } + else { + return -1; + } + } + + static PyObject * type_dict(PyTypeObject *type, void *context) { if (type->tp_dict == NULL) { *************** *** 120,126 **** } static PyGetSetDef type_getsets[] = { ! {"__name__", (getter)type_name, NULL, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, {"__doc__", (getter)type_get_doc, NULL, NULL}, --- 278,285 ---- } static PyGetSetDef type_getsets[] = { ! {"__name__", (getter)type_name, (setter)type_set_name, NULL}, ! {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, {"__doc__", (getter)type_get_doc, NULL, NULL}, *************** *** 1892,1921 **** } static int ! object_set_class(PyObject *self, PyObject *value, void *closure) { ! PyTypeObject *old = self->ob_type; ! PyTypeObject *new, *newbase, *oldbase; - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, - "can't delete __class__ attribute"); - return -1; - } - if (!PyType_Check(value)) { - PyErr_Format(PyExc_TypeError, - "__class__ must be set to new-style class, not '%s' object", - value->ob_type->tp_name); - return -1; - } - new = (PyTypeObject *)value; - if (!(new->tp_flags & Py_TPFLAGS_HEAPTYPE) || - !(old->tp_flags & Py_TPFLAGS_HEAPTYPE)) - { - PyErr_Format(PyExc_TypeError, - "__class__ assignment: only for heap types"); - return -1; - } if (new->tp_dealloc != old->tp_dealloc || new->tp_free != old->tp_free) { --- 2051,2060 ---- } static int ! compatible_for_assignment(PyTypeObject* old, PyTypeObject* new) { ! PyTypeObject *newbase, *oldbase; if (new->tp_dealloc != old->tp_dealloc || new->tp_free != old->tp_free) { *************** *** 1924,1930 **** "'%s' deallocator differs from '%s'", new->tp_name, old->tp_name); ! return -1; } newbase = new; oldbase = old; --- 2063,2069 ---- "'%s' deallocator differs from '%s'", new->tp_name, old->tp_name); ! return 0; } newbase = new; oldbase = old; *************** *** 1940,1951 **** "'%s' object layout differs from '%s'", new->tp_name, old->tp_name); return -1; } - Py_INCREF(new); - self->ob_type = new; - Py_DECREF(old); - return 0; } static PyGetSetDef object_getsets[] = { --- 2079,2124 ---- "'%s' object layout differs from '%s'", new->tp_name, old->tp_name); + return 0; + } + + return 1; + } + + static int + object_set_class(PyObject *self, PyObject *value, void *closure) + { + PyTypeObject *old = self->ob_type; + PyTypeObject *new; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete __class__ attribute"); + return -1; + } + if (!PyType_Check(value)) { + PyErr_Format(PyExc_TypeError, + "__class__ must be set to new-style class, not '%s' object", + value->ob_type->tp_name); + return -1; + } + new = (PyTypeObject *)value; + if (!(new->tp_flags & Py_TPFLAGS_HEAPTYPE) || + !(old->tp_flags & Py_TPFLAGS_HEAPTYPE)) + { + PyErr_Format(PyExc_TypeError, + "__class__ assignment: only for heap types"); + return -1; + } + if (compatible_for_assignment(new, old)) { + Py_INCREF(new); + self->ob_type = new; + Py_DECREF(old); + return 0; + } + else { return -1; } } static PyGetSetDef object_getsets[] = { *************** *** 2344,2350 **** } static int add_operators(PyTypeObject *); - static int add_subclass(PyTypeObject *base, PyTypeObject *type); int PyType_Ready(PyTypeObject *type) --- 2517,2522 ---- *************** *** 2505,2510 **** --- 2677,2705 ---- i = PyList_Append(list, new); Py_DECREF(new); return i; + } + + static int + remove_subclass(PyTypeObject *base, PyTypeObject *type) + { + int i; + PyObject *list, *ref; + + list = base->tp_subclasses; + if (list == NULL) { + base->tp_subclasses = list = PyList_New(0); + if (list == NULL) + return -1; + } + assert(PyList_Check(list)); + i = PyList_GET_SIZE(list); + while (--i >= 0) { + ref = PyList_GET_ITEM(list, i); + assert(PyWeakref_CheckRef(ref)); + if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) + return PySequence_DelItem(list, i); + } + return 0; }