[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.16.8.61,2.16.8.62

Guido van Rossum gvanrossum@users.sourceforge.net
Thu, 05 Jul 2001 14:39:54 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv25858

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
Make method resolution a method defined on the metatype, mro(), which
can be overridden.

PyType_InitDict(): change the initialization order a little bit again,
so that mro() can be called on a type that isn't quite entirely

type_members[]: make this a static array, which it should have been
all the time.

conservative_merge(): add full error checking.

method_resolution(): refactored into mro_external(), mro_internal(),
and mro_implementation(); add full error checking.

PyType_Type: add type_methods[], the array or methods.  Currently
there's one type method, "mro".


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.61
retrieving revision 2.16.8.62
diff -C2 -r2.16.8.61 -r2.16.8.62
*** typeobject.c	2001/07/05 21:26:00	2.16.8.61
--- typeobject.c	2001/07/05 21:39:52	2.16.8.62
***************
*** 7,11 ****
  staticforward int add_members(PyTypeObject *, struct memberlist *);
  
! struct memberlist type_members[] = {
  	{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
  	{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
--- 7,11 ----
  staticforward int add_members(PyTypeObject *, struct memberlist *);
  
! static struct memberlist type_members[] = {
  	{"__name__", T_STRING, offsetof(PyTypeObject, tp_name), READONLY},
  	{"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY},
***************
*** 225,232 ****
  	int left_size;
  	int right_size;
! 	int i, j, r;
  	PyObject *temp, *rr;
  
! 	/* XXX add error checking */
  
    again:
--- 225,233 ----
  	int left_size;
  	int right_size;
! 	int i, j, r, ok;
  	PyObject *temp, *rr;
  
! 	assert(PyList_Check(left));
! 	assert(PyList_Check(right));
  
    again:
***************
*** 239,250 ****
  				/* found a merge point */
  				temp = PyList_New(0);
  				for (r = 0; r < j; r++) {
  					rr = PyList_GET_ITEM(right, r);
! 					if (!PySequence_Contains(left, rr))
! 						PyList_Append(temp, rr);
  				}
! 				PyList_SetSlice(left, i, i, temp);
  				Py_DECREF(temp);
! 				PyList_SetSlice(right, 0, j+1, NULL);
  				goto again;
  			}
--- 240,267 ----
  				/* found a merge point */
  				temp = PyList_New(0);
+ 				if (temp == NULL)
+ 					return -1;
  				for (r = 0; r < j; r++) {
  					rr = PyList_GET_ITEM(right, r);
! 					ok = PySequence_Contains(left, rr);
! 					if (ok < 0) {
! 						Py_DECREF(temp);
! 						return -1;
! 					}
! 					if (!ok) {
! 						ok = PyList_Append(temp, rr);
! 						if (ok < 0) {
! 							Py_DECREF(temp);
! 							return -1;
! 						}
! 					}
  				}
! 				ok = PyList_SetSlice(left, i, i, temp);
  				Py_DECREF(temp);
! 				if (ok < 0)
! 					return -1;
! 				ok = PyList_SetSlice(right, 0, j+1, NULL);
! 				if (ok < 0)
! 					return -1;
  				goto again;
  			}
***************
*** 261,284 ****
  
  static PyObject *
! method_resolution_order(PyTypeObject *type)
  {
! 	int i, n;
! 	PyObject *bases;
! 	PyObject *result;
! 
! 	/* XXX add error checking */
! 
! 	if (type->tp_mro != NULL)
! 		return PySequence_List(type->tp_mro);
  
  	bases = type->tp_bases;
- 	if (bases == NULL || !PyTuple_Check(bases))
- 		return NULL;
  	n = PyTuple_GET_SIZE(bases);
! 	result = Py_BuildValue("[O]", type);
  	for (i = 0; i < n; i++) {
! 		PyTypeObject *base = (PyTypeObject *)
! 			PyTuple_GET_ITEM(bases, i);
! 		PyObject *parentMRO = method_resolution_order(base);
  		if (parentMRO == NULL) {
  			Py_DECREF(result);
--- 278,295 ----
  
  static PyObject *
! mro_implementation(PyTypeObject *type)
  {
! 	int i, n, ok;
! 	PyObject *bases, *result;
  
  	bases = type->tp_bases;
  	n = PyTuple_GET_SIZE(bases);
! 	result = Py_BuildValue("[O]", (PyObject *)type);
! 	if (result == NULL)
! 		return NULL;
  	for (i = 0; i < n; i++) {
! 		PyTypeObject *base =
! 			(PyTypeObject *) PyTuple_GET_ITEM(bases, i);
! 		PyObject *parentMRO = PySequence_List(base->tp_mro);
  		if (parentMRO == NULL) {
  			Py_DECREF(result);
***************
*** 289,300 ****
  			return NULL;
  		}
! 		conservative_merge(result, parentMRO);
  		Py_DECREF(parentMRO);
  	}
- 	if (result != NULL && type->tp_mro == NULL)
- 		type->tp_mro = PySequence_Tuple(result);
  	return result;
  }
  
  /* Calculate the best base amongst multiple base classes.
     This is the first one that's on the path to the "solid base". */
--- 300,347 ----
  			return NULL;
  		}
! 		ok = conservative_merge(result, parentMRO);
  		Py_DECREF(parentMRO);
+ 		if (ok < 0) {
+ 			Py_DECREF(result);
+ 			return NULL;
+ 		}
  	}
  	return result;
  }
  
+ static PyObject *
+ mro_external(PyObject *self, PyObject *args)
+ {
+ 	PyTypeObject *type = (PyTypeObject *)self;
+ 
+ 	if (!PyArg_ParseTuple(args, ""))
+ 		return NULL;
+ 	return mro_implementation(type);
+ }
+ 
+ static int
+ mro_internal(PyTypeObject *type)
+ {
+ 	PyObject *mro, *result, *tuple;
+ 
+ 	if (type->ob_type == &PyType_Type) {
+ 		result = mro_implementation(type);
+ 	}
+ 	else {
+ 		mro = PyObject_GetAttrString((PyObject *)type, "mro");
+ 		if (mro == NULL)
+ 			return -1;
+ 		result = PyObject_CallObject(mro, NULL);
+ 		Py_DECREF(mro);
+ 	}
+ 	if (result == NULL)
+ 		return -1;
+ 	tuple = PySequence_Tuple(result);
+ 	Py_DECREF(result);
+ 	type->tp_mro = tuple;
+ 	return 0;
+ }
+ 
+ 
  /* Calculate the best base amongst multiple base classes.
     This is the first one that's on the path to the "solid base". */
***************
*** 707,710 ****
--- 754,763 ----
  }
  
+ static PyMethodDef type_methods[] = {
+ 	{"mro", mro_external, METH_VARARGS,
+ 	 "mro() -> list\nreturn a type's method resolution order"},
+ 	{0}
+ };
+ 
  static char type_doc[] =
  "type(object) -> the object's type\n"
***************
*** 740,744 ****
  	0,					/* tp_iter */
  	0,					/* tp_iternext */
! 	0,					/* tp_methods */
  	type_members,				/* tp_members */
  	type_getsets,				/* tp_getset */
--- 793,797 ----
  	0,					/* tp_iter */
  	0,					/* tp_iternext */
! 	type_methods,				/* tp_methods */
  	type_members,				/* tp_members */
  	type_getsets,				/* tp_getset */
***************
*** 1152,1177 ****
  	}
  
  	/* Calculate method resolution order */
! 	x = method_resolution_order(type);
! 	if (x == NULL) {
! 		if (!PyErr_Occurred())
! 			PyErr_SetString(PyExc_TypeError,
! 					"method resolution order failed");
  		return -1;
  	}
- 	Py_DECREF(x);
  
! 	/* Initialize tp_dict */
! 	if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
! 		/* For a dynamic type. tp_dict *is* tp_defined */
! 		Py_INCREF(type->tp_defined);
! 		type->tp_dict = type->tp_defined;
! 	}
! 	else {
  		/* For a static type, tp_dict is the consolidation
  		   of the tp_defined of its bases in MRO.  Earlier
  		   bases override later bases; since d.update() works
  		   the other way, we walk the MRO sequence backwards. */
! 
  		type->tp_dict = PyDict_New();
  		if (type->tp_dict == NULL)
--- 1205,1226 ----
  	}
  
+ 	/* Temporarily make tp_dict the same object as tp_defined.
+ 	   (This is needed to call mro(), and can stay this way for
+ 	   dynamic types). */
+ 	Py_INCREF(type->tp_defined);
+ 	type->tp_dict = type->tp_defined;
+ 
  	/* Calculate method resolution order */
! 	if (mro_internal(type) < 0) {
  		return -1;
  	}
  
! 	/* Initialize tp_dict properly */
! 	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.  Earlier
  		   bases override later bases; since d.update() works
  		   the other way, we walk the MRO sequence backwards. */
! 		Py_DECREF(type->tp_dict);
  		type->tp_dict = PyDict_New();
  		if (type->tp_dict == NULL)