[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.16.8.49,2.16.8.50
Guido van Rossum
gvanrossum@users.sourceforge.net
Fri, 29 Jun 2001 08:03:00 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv27650
Modified Files:
Tag: descr-branch
typeobject.c
Log Message:
First cut at dynamic types. Too much code moved around to describe
the changes in detail. Specification of what changed:
If you set ``__dynamic__ = 1'' is a class statement that creates a new
type, the new type is dynamic. A new type is also dynamic if at least
one of its base types is dynamic and no __dynamic__ flag is set in the
class statement. By setting ``__dynamic__ = 0'' in the class
statement you can force a static type even if some bases are dynamic.
For a dynamic type t:
- t.__dict__ is t.__defined__ # they are the same object
- type(t.__dict__) is dictionary # not a proxy
- t.<name> = <value> is equivalent to t.__dict__['<name>'] = <value>
- attribute lookup for dynamic types and their instances searches the
__defined__ dict of the type and its base types, in MRO sequence
(even if the base class is static)
Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.49
retrieving revision 2.16.8.50
diff -C2 -r2.16.8.49 -r2.16.8.50
*** typeobject.c 2001/06/29 14:58:30 2.16.8.49
--- typeobject.c 2001/06/29 15:02:58 2.16.8.50
***************
*** 36,39 ****
--- 36,43 ----
return Py_None;
}
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_dict);
+ return type->tp_dict;
+ }
return PyDictProxy_New(type->tp_dict);
}
***************
*** 46,49 ****
--- 50,57 ----
return Py_None;
}
+ if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ Py_INCREF(type->tp_defined);
+ return type->tp_defined;
+ }
return PyDictProxy_New(type->tp_defined);
}
***************
*** 371,379 ****
PyObject *name, *bases, *dict;
static char *kwlist[] = {"name", "bases", "dict", 0};
! PyObject *slots;
! PyTypeObject *type, *base;
etype *et;
struct memberlist *mp;
! int i, nbases, nslots, slotoffset;
if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
--- 379,387 ----
PyObject *name, *bases, *dict;
static char *kwlist[] = {"name", "bases", "dict", 0};
! PyObject *slots, *tmp;
! PyTypeObject *type, *base, *tmptype;
etype *et;
struct memberlist *mp;
! int i, nbases, nslots, slotoffset, dynamic;
if (PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
***************
*** 386,414 ****
/* Check arguments */
! if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO:type", kwlist,
! &name, &bases, &dict))
return NULL;
! if (PyTuple_Check(bases)) {
! int i, n;
! n = PyTuple_GET_SIZE(bases);
! for (i = 0; i < n; i++) {
! PyObject *base_i = PyTuple_GET_ITEM(bases, i);
! PyTypeObject *type_i = base_i->ob_type;
! if (issubtype(metatype, type_i))
! continue;
! if (issubtype(type_i, metatype)) {
! metatype = type_i;
! continue;
! }
! PyErr_SetString(PyExc_TypeError,
! "metaclass conflict among bases");
! return NULL;
}
! if (metatype->tp_new != type_new)
! return metatype->tp_new(metatype, args, kwds);
}
! /* Adjust empty bases */
! nbases = PyTuple_GET_SIZE(bases);
if (nbases == 0) {
bases = Py_BuildValue("(O)", &PyBaseObject_Type);
--- 394,425 ----
/* Check arguments */
! if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist,
! &name,
! &PyTuple_Type, &bases,
! &PyDict_Type, &dict))
return NULL;
!
! /* Determine the proper metatype to deal with this,
! and check for metatype conflicts while we're at it.
! Note that if some other metatype wins to contract,
! it's possible that its instances are not types. */
! nbases = PyTuple_GET_SIZE(bases);
! for (i = 0; i < nbases; i++) {
! tmp = PyTuple_GET_ITEM(bases, i);
! tmptype = tmp->ob_type;
! if (issubtype(metatype, tmptype))
! continue;
! if (issubtype(tmptype, metatype)) {
! metatype = tmptype;
! continue;
}
! PyErr_SetString(PyExc_TypeError,
! "metatype conflict among bases");
! return NULL;
}
+ if (metatype->tp_new != type_new) /* Pass it to the winner */
+ return metatype->tp_new(metatype, args, kwds);
! /* Adjust for empty tuple bases */
if (nbases == 0) {
bases = Py_BuildValue("(O)", &PyBaseObject_Type);
***************
*** 419,424 ****
else
Py_INCREF(bases);
! /* Calculate best base */
base = best_base(bases);
if (base == NULL)
--- 430,437 ----
else
Py_INCREF(bases);
+
+ /* XXX From here until type is allocated, "return NULL" leaks bases! */
! /* Calculate best base, and check that all bases are type objects */
base = best_base(bases);
if (base == NULL)
***************
*** 431,434 ****
--- 444,475 ----
}
+ /* Should this be a dynamic class (i.e. modifiable __dict__)? */
+ tmp = PyDict_GetItemString(dict, "__dynamic__");
+ if (tmp != NULL) {
+ /* The class author has a preference */
+ dynamic = PyObject_IsTrue(tmp);
+ Py_DECREF(tmp);
+ if (dynamic < 0)
+ return NULL;
+ }
+ else {
+ /* Make a new class dynamic if any of its bases is dynamic.
+ This is not always the same as inheriting the __dynamic__
+ class attribute! */
+ dynamic = 0;
+ for (i = 0; i < nbases; i++) {
+ tmptype = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+ if (tmptype->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
+ dynamic = 1;
+ break;
+ }
+ }
+
+ /* Set the __dynamic__ attribute */
+ if (PyDict_SetItemString(dict, "__dynamic__",
+ dynamic ? Py_True : Py_False) < 0)
+ return NULL;
+ }
+
/* Check for a __slots__ sequence variable in dict, and count it */
slots = PyDict_GetItemString(dict, "__slots__");
***************
*** 457,460 ****
--- 498,504 ----
nslots = 1;
+ /* XXX From here until type is safely allocated,
+ "return NULL" may leak slots! */
+
/* Allocate the type object */
type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots);
***************
*** 471,474 ****
--- 515,520 ----
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
Py_TPFLAGS_BASETYPE;
+ if (dynamic)
+ type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
type->tp_as_number = &et->as_number;
type->tp_as_sequence = &et->as_sequence;
***************
*** 515,519 ****
/* Special case some slots */
! if (type->tp_dictoffset != 0) {
if (base->tp_getattr == NULL && base->tp_getattro == NULL)
type->tp_getattro = PyObject_GenericGetAttr;
--- 561,565 ----
/* Special case some slots */
! if (type->tp_dictoffset != 0 || nslots > 0) {
if (base->tp_getattr == NULL && base->tp_getattro == NULL)
type->tp_getattro = PyObject_GenericGetAttr;
***************
*** 537,548 ****
}
static PyObject *
type_getattro(PyTypeObject *type, PyObject *name)
{
if (type->tp_dict == NULL) {
if (PyType_InitDict(type) < 0)
return NULL;
}
! return PyObject_GenericGetAttr((PyObject *)type, name);
}
--- 583,641 ----
}
+ /* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+ PyObject *
+ _PyType_Lookup(PyTypeObject *type, PyObject *name)
+ {
+ int i, n;
+ PyObject *mro = type->tp_mro, *res;
+
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ type = (PyTypeObject *) PyTuple_GET_ITEM(mro, i);
+ assert(PyType_Check(type));
+ assert(type->tp_dict && PyDict_Check(type->tp_dict));
+ res = PyDict_GetItem(type->tp_dict, name);
+ if (res != NULL)
+ return res;
+ }
+ return NULL;
+ }
+
static PyObject *
type_getattro(PyTypeObject *type, PyObject *name)
{
+ PyObject *descr, *res;
+ descrgetfunc f;
+
if (type->tp_dict == NULL) {
if (PyType_InitDict(type) < 0)
return NULL;
+ }
+ descr = PyObject_GenericGetAttr((PyObject *)type, name);
+ if (descr == NULL) {
+ descr = _PyType_Lookup(type, name);
+ if (descr == NULL)
+ return NULL;
+ PyErr_Clear();
+ Py_INCREF(descr);
+ }
+ f = descr->ob_type->tp_descr_get;
+ if (f != NULL) {
+ res = f(descr, NULL);
+ Py_DECREF(descr);
+ return res;
}
! return descr;
! }
!
! 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");
! return -1;
}
***************
*** 589,593 ****
0, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
! 0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
--- 682,686 ----
0, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
! (setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
***************
*** 994,1008 ****
}
- /* Initialize tp_dict from tp_defined */
- type->tp_dict = PyDict_Copy(dict);
- if (type->tp_dict == NULL)
- return -1;
-
- /* Inherit base class slots */
- if (base) {
- if (inherit_slots(type, base) < 0)
- return -1;
- }
-
/* Calculate method resolution order */
x = method_resolution_order(type);
--- 1087,1090 ----
***************
*** 1015,1032 ****
Py_DECREF(x);
! /* Inherit methods, updating from last base backwards */
! bases = type->tp_mro;
! assert(bases != NULL);
! assert(PyTuple_Check(bases));
! n = PyTuple_GET_SIZE(bases);
! for (i = n; --i >= 0; ) {
! base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
! assert(PyType_Check(base));
! x = base->tp_defined;
! if (x != NULL) {
! x = PyObject_CallMethod(type->tp_dict, "update","O",x);
! if (x == NULL)
return -1;
- Py_DECREF(x); /* throw away None */
}
}
--- 1097,1125 ----
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)
! return -1;
! bases = type->tp_mro;
! assert(bases != NULL);
! assert(PyTuple_Check(bases));
! n = PyTuple_GET_SIZE(bases);
! for (i = n; --i >= 0; ) {
! base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
! assert(PyType_Check(base));
! x = base->tp_defined;
! if (x != NULL && PyDict_Update(type->tp_dict, x) < 0)
return -1;
}
}