[Python-checkins] python/dist/src/Objects typeobject.c,2.188,2.189

mwh@users.sourceforge.net mwh@users.sourceforge.net
2002年11月26日 06:47:29 -0800


Update of /cvsroot/python/python/dist/src/Objects
In directory sc8-pr-cvs1:/tmp/cvs-serv18876/Objects
Modified Files:
	typeobject.c 
Log Message:
This is my patch:
[ 635933 ] make some type attrs writable
Plus a couple of extra tests beyond what's up there.
It hasn't been as carefully reviewed as it perhaps should, so all readers
are encouraged, nay exhorted, to give this a close reading.
There are still a couple of oddities related to assigning to __name__,
but I intend to solicit python-dev's opinions on these.
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.188
retrieving revision 2.189
diff -C2 -d -r2.188 -r2.189
*** typeobject.c	25 Nov 2002 21:36:54 -0000	2.188
--- typeobject.c	26 Nov 2002 14:47:26 -0000	2.189
***************
*** 33,37 ****
 	{"__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}
--- 33,36 ----
***************
*** 51,54 ****
--- 50,93 ----
 }
 
+ static int
+ type_set_name(PyTypeObject *type, PyObject *value, void *context)
+ {
+ 	etype* et;
+ 
+ 	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ 		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 (strlen(PyString_AS_STRING(value)) 
+ 	 != (size_t)PyString_GET_SIZE(value)) {
+ 		PyErr_Format(PyExc_ValueError,
+ 			 "__name__ must not contain null bytes");
+ 		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)
***************
*** 64,68 ****
 		return PyString_FromString("__builtin__");
 	mod = PyDict_GetItemString(type->tp_dict, "__module__");
! 	if (mod != NULL && PyString_Check(mod)) {
 		Py_INCREF(mod);
 		return mod;
--- 103,107 ----
 		return PyString_FromString("__builtin__");
 	mod = PyDict_GetItemString(type->tp_dict, "__module__");
! 	if (mod != NULL) {
 		Py_INCREF(mod);
 		return mod;
***************
*** 75,80 ****
 type_set_module(PyTypeObject *type, PyObject *value, void *context)
 {
! 	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
! 	 strrchr(type->tp_name, '.')) {
 		PyErr_Format(PyExc_TypeError,
 			 "can't set %s.__module__", type->tp_name);
--- 114,118 ----
 type_set_module(PyTypeObject *type, PyObject *value, void *context)
 {
! 	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
 		PyErr_Format(PyExc_TypeError,
 			 "can't set %s.__module__", type->tp_name);
***************
*** 86,93 ****
--- 124,286 ----
 		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 PyTypeObject *best_base(PyObject *);
+ static int mro_internal(PyTypeObject *);
+ static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *);
+ static int add_subclass(PyTypeObject*, PyTypeObject*);
+ static void remove_subclass(PyTypeObject *, PyTypeObject *);
+ static void update_all_slots(PyTypeObject *);
+ 
+ static int
+ mro_subclasses(PyTypeObject *type)
+ {
+ 	PyTypeObject *subclass;
+ 	PyObject *ref, *subclasses, *old_mro;
+ 	int i, n, r;
+ 
+ 	subclasses = type->tp_subclasses;
+ 	if (subclasses == NULL)
+ 		return 0;
+ 	assert(PyList_Check(subclasses));
+ 	n = PyList_GET_SIZE(subclasses);
+ 	for (i = 0; i < n; i++) {
+ 		ref = PyList_GET_ITEM(subclasses, i);
+ 		assert(PyWeakref_CheckRef(ref));
+ 		subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref);
+ 		assert(subclass != NULL);
+ 		if ((PyObject *)subclass == Py_None)
+ 			continue;
+ 		assert(PyType_Check(subclass));
+ 		old_mro = subclass->tp_mro;
+ 		if (mro_internal(subclass) < 0) {
+ 			subclass->tp_mro = old_mro;
+ 			r = -1;
+ 		}
+ 		else {
+ 			Py_DECREF(old_mro);
+ 		}
+ 		if (mro_subclasses(subclass) < 0)
+ 			r = -1;
+ 	}
+ 	return r;
+ }
+ 
+ static int
+ type_set_bases(PyTypeObject *type, PyObject *value, void *context)
+ {
+ 	int i, r = 0;
+ 	PyObject* ob;
+ 	PyTypeObject *new_base, *old_base;
+ 	PyObject *old_bases, *old_mro;
+ 
+ 	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ 		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;
+ 		}
+ 		if (PyType_IsSubtype(type, (PyTypeObject*)ob)) {
+ 			PyErr_SetString(PyExc_TypeError,
+ 		"a __bases__ item causes an inheritance cycle");
+ 			return -1;
+ 		}
+ 	}
+ 
+ 	new_base = best_base(value);
+ 
+ 	if (!new_base) {
+ 		return -1;
+ 	}
+ 
+ 	if (!compatible_for_assignment(type->tp_base, new_base, "__bases__"))
+ 		return -1;
+ 
+ 	Py_INCREF(new_base);
+ 	Py_INCREF(value);
+ 
+ 	old_bases = type->tp_bases;
+ 	old_base = type->tp_base;
+ 	old_mro = type->tp_mro;
+ 
+ 	type->tp_bases = value;
+ 	type->tp_base = new_base;
+ 
+ 	if (mro_internal(type) < 0) {
+ 		type->tp_bases = old_bases;
+ 		type->tp_base = old_base;
+ 		type->tp_mro = old_mro;
+ 
+ 		Py_DECREF(value);
+ 		Py_DECREF(new_base);
+ 
+ 		return -1;
+ 	}
+ 
+ 	if (mro_subclasses(type) < 0)
+ 		r = -1;
+ 
+ 	/* 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--) {
+ 		ob = PyTuple_GET_ITEM(old_bases, i);
+ 		if (PyType_Check(ob)) {
+ 			remove_subclass(
+ 				(PyTypeObject*)ob, type);
+ 		}
+ 	}
+ 
+ 	for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) {
+ 		ob = PyTuple_GET_ITEM(value, i);
+ 		if (PyType_Check(ob)) {
+ 			if (add_subclass((PyTypeObject*)ob, type) < 0)
+ 				r = -1;
+ 		}
+ 	}
+ 
+ 	update_all_slots(type);
+ 
+ 	Py_DECREF(old_bases);
+ 	Py_DECREF(old_base);
+ 	Py_DECREF(old_mro);
+ 
+ 	return r;
+ }
+ 
+ static PyObject *
 type_dict(PyTypeObject *type, void *context)
 {
***************
*** 121,125 ****
 
 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},
--- 314,319 ----
 
 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},
***************
*** 2027,2034 ****
 
 static int
 object_set_class(PyObject *self, PyObject *value, void *closure)
 {
 	PyTypeObject *old = self->ob_type;
! 	PyTypeObject *new, *newbase, *oldbase;
 
 	if (value == NULL) {
--- 2221,2265 ----
 
 static int
+ compatible_for_assignment(PyTypeObject* old, PyTypeObject* new, char* attr)
+ {
+ 	PyTypeObject *newbase, *oldbase;
+ 
+ 	if (new->tp_dealloc != old->tp_dealloc ||
+ 	 new->tp_free != old->tp_free)
+ 	{
+ 		PyErr_Format(PyExc_TypeError,
+ 			 "%s assignment: "
+ 			 "'%s' deallocator differs from '%s'",
+ 			 attr,
+ 			 new->tp_name,
+ 			 old->tp_name);
+ 		return 0;
+ 	}
+ 	newbase = new;
+ 	oldbase = old;
+ 	while (equiv_structs(newbase, newbase->tp_base))
+ 		newbase = newbase->tp_base;
+ 	while (equiv_structs(oldbase, oldbase->tp_base))
+ 		oldbase = oldbase->tp_base;
+ 	if (newbase != oldbase &&
+ 	 (newbase->tp_base != oldbase->tp_base ||
+ 	 !same_slots_added(newbase, oldbase))) {
+ 		PyErr_Format(PyExc_TypeError,
+ 			 "%s assignment: "
+ 			 "'%s' object layout differs from '%s'",
+ 			 attr,
+ 			 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) {
***************
*** 2051,2084 ****
 		return -1;
 	}
! 	if (new->tp_dealloc != old->tp_dealloc ||
! 	 new->tp_free != old->tp_free)
! 	{
! 		PyErr_Format(PyExc_TypeError,
! 			 "__class__ assignment: "
! 			 "'%s' deallocator differs from '%s'",
! 			 new->tp_name,
! 			 old->tp_name);
! 		return -1;
 	}
! 	newbase = new;
! 	oldbase = old;
! 	while (equiv_structs(newbase, newbase->tp_base))
! 		newbase = newbase->tp_base;
! 	while (equiv_structs(oldbase, oldbase->tp_base))
! 		oldbase = oldbase->tp_base;
! 	if (newbase != oldbase &&
! 	 (newbase->tp_base != oldbase->tp_base ||
! 	 !same_slots_added(newbase, oldbase))) {
! 		PyErr_Format(PyExc_TypeError,
! 			 "__class__ assignment: "
! 			 "'%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;
 }
 
--- 2282,2294 ----
 		return -1;
 	}
! 	if (compatible_for_assignment(new, old, "__class__")) {
! 		Py_INCREF(new);
! 		self->ob_type = new;
! 		Py_DECREF(old);
! 		return 0;
 	}
! 	else {
 		return -1;
 	}
 }
 
***************
*** 2479,2483 ****
 
 static int add_operators(PyTypeObject *);
- static int add_subclass(PyTypeObject *base, PyTypeObject *type);
 
 int
--- 2689,2692 ----
***************
*** 2642,2645 ****
--- 2851,2876 ----
 }
 
+ static void
+ remove_subclass(PyTypeObject *base, PyTypeObject *type)
+ {
+ 	int i;
+ 	PyObject *list, *ref;
+ 
+ 	list = base->tp_subclasses;
+ 	if (list == NULL) {
+ 		return;
+ 	}
+ 	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) {
+ 			/* this can't fail, right? */
+ 			PySequence_DelItem(list, i);
+ 			return;
+ 		}
+ 	}
+ }
 
 /* Generic wrappers for overloadable 'operators' such as __getitem__ */
***************
*** 4555,4558 ****
--- 4786,4801 ----
 	for (p = slotdefs; p->name; )
 		p = update_one_slot(type, p);
+ }
+ 
+ static void
+ update_all_slots(PyTypeObject* type)
+ {
+ 	slotdef *p;
+ 
+ 	init_slotdefs();
+ 	for (p = slotdefs; p->name; p++) {
+ 		/* update_slot returns int but can't actually fail */
+ 		update_slot(type, p->name_strobj);
+ 	}
 }
 

AltStyle によって変換されたページ (->オリジナル) /