[Zope3-checkins] CVS: ZODB4/Persistence - cPersistenceAPI.h:1.5 cPersistence.h:1.5 cPersistence.c:1.20 __init__.py:1.8 Module.py:1.28 Class.py:1.4

Jeremy Hylton jeremy@zope.com
Wed, 9 Oct 2002 18:41:33 -0400


Update of /cvs-repository/ZODB4/Persistence
In directory cvs.zope.org:/tmp/cvs-serv29649/Persistence

Modified Files:
	cPersistenceAPI.h cPersistence.h cPersistence.c __init__.py 
	Module.py Class.py 
Log Message:
Eliminate BasePersistent!

Python 2.2 has peculiar rules about whether a type's instances should
have an __dict__, which have been fixed in 2.3.  The new rules make
the BasePersistent unnecessary, because Persistent does not need to
explicitly create an __dict__.

There is a vast simplification to the code by eliminating
BasePersistent and the corresponding C type.  All C code uses a single
type (PyPersist_TYPE) and struct (PyPersistObject *).  Yay!

But we've still got to support Python 2.2 (bummer) and it's two big a
change to make some version of 2.2 behave like 2.3.  So we still need
some sort of hack to make this all work with 2.2.  The answer is a
persistent meta class that creates the __dict__ for us.

The change has fairly broad changes to the Persistence package,
because the Python code already used PersistentMetaClass for
persistent clas support.  Rename that meta class to
PersistentClassMetaClass, which is descriptive but too verbose.  (Then
again all the names are too verbose.)



=== ZODB4/Persistence/cPersistenceAPI.h 1.4 => 1.5 ===
--- ZODB4/Persistence/cPersistenceAPI.h:1.4	Thu Oct  3 00:16:59 2002
+++ ZODB4/Persistence/cPersistenceAPI.h	Wed Oct  9 18:41:32 2002
@@ -21,13 +21,12 @@
 
 static PyPersist_C_API_struct *PyPersist_C_API;
 
-#define PyPersist_BASE_TYPE PyPersist_C_API->base_type
-#define PyPersist_INSTANCE_TYPE PyPersist_C_API->instance_type
+#define PyPersist_TYPE PyPersist_C_API->base_type
 
 #define PyPersist_INCREF(O) \
     if (((O)->po_state == UPTODATE) \
 	|| ((O)->po_state == GHOST \
-	    && PyPersist_C_API->load((PyPersistBaseObject *)(O)))) \
+	    && PyPersist_C_API->load((PyPersistObject *)(O)))) \
 	(O)->po_state = STICKY;
 
 #define PyPersist_DECREF(O) \
@@ -41,24 +40,24 @@
     ((O)->po_state == STICKY || (O)->po_state == CHANGED)
 
 #define PyPersist_CHANGED(O) \
-    PyPersist_C_API->reg_mgr((PyPersistBaseObject *)(O))
+    PyPersist_C_API->reg_mgr((PyPersistObject *)(O))
 
 #define PyPersist_SetATime(O) \
-    PyPersist_C_API->set_atime((PyPersistBaseObject *)(O))
+    PyPersist_C_API->set_atime((PyPersistObject *)(O))
 
 /* Macros for compatibility with ZODB 3 C extensions. */
 
 #define PER_USE_OR_RETURN(O, R) \
 { \
     if (((O)->po_state == GHOST) \
-	&& (PyPersist_C_API->load((PyPersistBaseObject *)(O)) < 0)) { \
+	&& (PyPersist_C_API->load((PyPersistObject *)(O)) < 0)) { \
         (O)->po_state = STICKY; \
 	return (R); \
     } else if ((O)->po_state == UPTODATE) \
 	(O)->po_state = STICKY; \
 }
 
-#define PER_CHANGED(O) PyPersist_C_API->reg_mgr((PyPersistBaseObject *)(O))
+#define PER_CHANGED(O) PyPersist_C_API->reg_mgr((PyPersistObject *)(O))
 
 #define PER_ALLOW_DEACTIVATION(O) \
 { \
@@ -73,9 +72,9 @@
 }
 
 #define PER_USE(O) \
-    ((((PyPersistBaseObject *)(O))->po_state != GHOST) \
-     || (PyPersist_C_API->load((PyPersistBaseObject *)(O)) >= 0) \
-     ? ((((PyPersistBaseObject *)(O))->po_state == UPTODATE) \
-	? (((PyPersistBaseObject *)(O))->po_state = STICKY) : 1) : 0)
+    ((((PyPersistObject *)(O))->po_state != GHOST) \
+     || (PyPersist_C_API->load((PyPersistObject *)(O)) >= 0) \
+     ? ((((PyPersistObject *)(O))->po_state == UPTODATE) \
+	? (((PyPersistObject *)(O))->po_state = STICKY) : 1) : 0)
 
-#define PER_ACCESSED(O) PyPersist_C_API->set_atime((PyPersistBaseObject *)O)
+#define PER_ACCESSED(O) PyPersist_C_API->set_atime((PyPersistObject *)O)


=== ZODB4/Persistence/cPersistence.h 1.4 => 1.5 ===
--- ZODB4/Persistence/cPersistence.h:1.4	Thu Oct  3 00:16:59 2002
+++ ZODB4/Persistence/cPersistence.h	Wed Oct  9 18:41:32 2002
@@ -40,21 +40,13 @@
     int po_atime; \
     enum PyPersist_State po_state;
 
-#define PyPersist_INSTANCE_HEAD \
-    PyPersist_HEAD \
-    PyObject *po_dict; 
-
 typedef struct {
     PyPersist_HEAD
-} PyPersistBaseObject;
-
-typedef struct {
-    PyPersist_INSTANCE_HEAD
 } PyPersistObject;
 
-extern PyObject *_PyPersist_Load(PyPersistBaseObject *);
-extern PyObject *_PyPersist_RegisterDataManager(PyPersistBaseObject *);
-extern void _PyPersist_SetATime(PyPersistBaseObject *);
+extern PyObject *_PyPersist_Load(PyPersistObject *);
+extern PyObject *_PyPersist_RegisterDataManager(PyPersistObject *);
+extern void _PyPersist_SetATime(PyPersistObject *);
 
 /* A struct to encapsulation the PyPersist C API for use by other
    dynamically load extensions.
@@ -62,9 +54,8 @@
 
 typedef struct {
     PyTypeObject *base_type;
-    PyTypeObject *instance_type;
-    PyObject *(*load)(PyPersistBaseObject *);
-    PyObject *(*reg_mgr)(PyPersistBaseObject *);
-    void (*set_atime)(PyPersistBaseObject *);
+    PyObject *(*load)(PyPersistObject *);
+    PyObject *(*reg_mgr)(PyPersistObject *);
+    void (*set_atime)(PyPersistObject *);
 } PyPersist_C_API_struct;
 


=== ZODB4/Persistence/cPersistence.c 1.19 => 1.20 ===
--- ZODB4/Persistence/cPersistence.c:1.19	Mon Oct  7 19:27:08 2002
+++ ZODB4/Persistence/cPersistence.c	Wed Oct  9 18:41:32 2002
@@ -20,35 +20,8 @@
 "\n"
 "$Id$\n";
 
-/* cPersistence defines two Python types and a C API for them.
-
-   This table summarizes the stuff connected to each type.
-
-   PyTypeObject	   PyPersistBase_Type    	PyPersist_Type
-   supports        persistent objects in C 	persistent objects in Python
-   PyObject *      PyPersistBaseObject *        PyPersistObject *
-   C struct        PyPersist_HEAD		PyPersist_INSTANCE_HEAD
-   C API macro     PyPersist_BASE_TYPE          PyPersist_INSTANCE_TYPE       
-   Python object   Persistence.BasePersistent   Persistence.Persistent
-
-   The two types share many of the same tp_xxx implementations.  The
-   key difference between the base type and the instance type is that
-   the latter has room for an __dict__.  The Persistence.Persistent
-   object is used as a base class for peristent object classes written
-   in Python.
-
-   The functions that can operate on either type take a
-   PyPersistBaseObject * argument.  If the function needs to access
-   the po_dict slot, it must first check obj->ob_type->tp_dictoffset.
-   For a PyPersistBase_Type object, the dictoffset is 0.
-
-   The getstate and setstate implementations only work with
-   PyPersist_Type objects, because they depend on having an __dict__.
-
-   The base type exists to support C types that are also persistent.
-   The only examples of such types are in Persistence.BTrees.
-
-*/
+/* Python version of the simple_new function; */
+static PyObject *py_simple_new = NULL;
 
 /* A helper function that registers a persistent object with its data
    manager.
@@ -56,14 +29,8 @@
 
 static PyObject *s_register = NULL;
 
-/* Python version of the simple_new function; */
-static PyObject *py_simple_new = NULL;
-
-
-
-
 PyObject *
-_PyPersist_RegisterDataManager(PyPersistBaseObject *self) 
+_PyPersist_RegisterDataManager(PyPersistObject *self) 
 {
     PyObject *meth, *arg, *result;
 
@@ -95,7 +62,7 @@
 */
 
 PyObject *
-_PyPersist_Load(PyPersistBaseObject *self) 
+_PyPersist_Load(PyPersistObject *self) 
 {
     static PyObject *s_setstate = NULL;
     PyObject *meth, *arg, *result;
@@ -131,7 +98,7 @@
  */
 
 void
-_PyPersist_SetATime(PyPersistBaseObject *self)
+_PyPersist_SetATime(PyPersistObject *self)
 {
     time_t t = time(NULL);
     self->po_atime = t % 86400;
@@ -223,7 +190,7 @@
 persist_activate(PyPersistObject *self)
 {
     if (self->po_state == GHOST && self->po_dm)
-	return _PyPersist_Load((PyPersistBaseObject *)self);
+	return _PyPersist_Load((PyPersistObject *)self);
     Py_INCREF(Py_None);
     return Py_None;
 }
@@ -313,7 +280,7 @@
 	if (newstate == CHANGED_TRUE || newstate == CHANGED_FALSE) {
 	    /* Turn a ghost into a real object. */
 	    self->po_state = CHANGED;
-	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL)
+	    if (_PyPersist_Load((PyPersistObject *)self) == NULL)
 		return -1;
 	    if (newstate == CHANGED_TRUE)
 		self->po_state = CHANGED;
@@ -324,7 +291,7 @@
 	/* Mark an up-to-date object as changed. */
 	if (self->po_state == UPTODATE) {
 	    self->po_state = CHANGED;
-	    if (!_PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
+	    if (!_PyPersist_RegisterDataManager((PyPersistObject *)self))
 		return -1;
 	}
     } else if (newstate == CHANGED_FALSE) {
@@ -352,19 +319,6 @@
     return 0;
 }
 
-static PyObject *
-persist_get_dict(PyPersistObject *self)
-{
-    if (self->po_dict == NULL) {
-	self->po_dict = PyDict_New();
-	if (self->po_dict == NULL)
-	    return NULL;
-    }
-    Py_INCREF(self->po_dict);
-    return self->po_dict;
-}
-
-
 /* convert_name() returns a new reference to a string name
    or sets an exception and returns NULL.
 */
@@ -434,14 +388,14 @@
 	       already registered. 
 	    */
 	    self->po_state = CHANGED;
-	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL) {
+	    if (_PyPersist_Load((PyPersistObject *)self) == NULL) {
 		call_p_deactivate(self);
 		self->po_state = GHOST;
 		return NULL;
 	    } else
 		self->po_state = UPTODATE;
 	}
-	_PyPersist_SetATime((PyPersistBaseObject *)self);
+	_PyPersist_SetATime((PyPersistObject *)self);
     }
 
     /* will invoke an __getattr__ if it exists. */
@@ -461,7 +415,7 @@
 */
 
 static int
-persist_setattr_prep(PyPersistBaseObject *self, PyObject *name, 
+persist_setattr_prep(PyPersistObject *self, PyObject *name, 
 			PyObject *value)
 {
     char *s_name;
@@ -491,7 +445,7 @@
 				"attempt to modify unrevivable ghost");
 		return -1;
 	    }
-	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL)
+	    if (_PyPersist_Load((PyPersistObject *)self) == NULL)
 		return -1;
 	}
 	/* If the object is marked as UPTODATE then it must be
@@ -503,12 +457,12 @@
 	   XXX What if it's in the sticky state?
 	*/
 	if (self->po_state == UPTODATE && self->po_dm &&
-	    !_PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
+	    !_PyPersist_RegisterDataManager((PyPersistObject *)self))
 	    return -1;
 
 	if (self->po_dm && self->po_oid) {
 	    self->po_state = CHANGED;
-	    _PyPersist_SetATime((PyPersistBaseObject *)self);
+	    _PyPersist_SetATime((PyPersistObject *)self);
 	}
 	return 1;
     }
@@ -516,7 +470,7 @@
 }
 
 static int
-persist_setattro(PyPersistBaseObject *self, PyObject *name, PyObject *value)
+persist_setattro(PyPersistObject *self, PyObject *name, PyObject *value)
 {
     int r;
 
@@ -532,7 +486,7 @@
 }
 
 static PyObject *
-persist_p_set_or_delattr(PyPersistBaseObject *self, PyObject *name, 
+persist_p_set_or_delattr(PyPersistObject *self, PyObject *name, 
 			 PyObject *value)
 {
     PyObject *res;
@@ -567,7 +521,7 @@
 */
 
 static PyObject *
-persist_p_setattr(PyPersistBaseObject *self, PyObject *args)
+persist_p_setattr(PyPersistObject *self, PyObject *args)
 {
     PyObject *name, *value;
 
@@ -584,7 +538,7 @@
 */
 
 static PyObject *
-persist_p_delattr(PyPersistBaseObject *self, PyObject *name)
+persist_p_delattr(PyPersistObject *self, PyObject *name)
 {
     return persist_p_set_or_delattr(self, name, NULL);
 }
@@ -595,9 +549,6 @@
     Py_XDECREF(self->po_dm);
     Py_XDECREF(self->po_oid);
     Py_XDECREF(self->po_serial);
-    if (self->ob_type->tp_dictoffset) {
-	Py_XDECREF(self->po_dict);
-    }
     PyObject_GC_Del(self);
 }
 
@@ -615,9 +566,6 @@
     VISIT(self->po_dm);
     VISIT(self->po_oid);
     VISIT(self->po_serial);
-    if (self->ob_type->tp_dictoffset) {
-	VISIT(self->po_dict);
-    }
 #undef VISIT
     return 0;
 }
@@ -631,10 +579,6 @@
     self->po_dm = NULL;
     self->po_oid = NULL;
     self->po_serial = NULL;
-    if (self->ob_type->tp_dictoffset) {
-	Py_XDECREF(self->po_dict);
-	self->po_dict = NULL;
-    }
     return 0;
 }
 
@@ -684,14 +628,90 @@
   return NULL;
 }
 
-static PyMethodDef base_persist_methods[] = {
-    {"_p_activate", (PyCFunction)persist_activate, METH_NOARGS, },
-    {"_p_deactivate", (PyCFunction)persist_deactivate, METH_NOARGS, },
-    {"_p_setattr", (PyCFunction)persist_p_setattr, METH_VARARGS, },
-    {"_p_delattr", (PyCFunction)persist_p_delattr, METH_O, },
-    {NULL}
+/* Make persistent objects work with Python 2.2. 
+
+   The rules for deciding whether to give an object an __dict__ or an
+   __weakref__ are different in 2.2 than in later versions of Python.
+   In particular, an object will not get an __dict__ if it has a
+   custom setattr.
+*/
+
+static PyObject *
+persist_dict(PyObject *obj, void *context)
+{
+    PyObject **dictptr;
+
+    dictptr = _PyObject_GetDictPtr(obj);
+    assert(dictptr);
+    
+    if (!*dictptr) {
+	PyObject *dict = PyDict_New();
+	if (!dict)
+	    return NULL;
+	*dictptr = dict;
+    }
+    Py_INCREF(*dictptr);
+    return *dictptr;
+}
+
+static PyGetSetDef persist_meta_getsets[] = {
+	{"__dict__",  (getter)persist_dict,  NULL, NULL},
+	{NULL}
 };
 
+/* PyPersist_New is the tp_new of PersistentMetaClass, which exists
+   only for compatibility with Python 2.2. 
+
+   This new function must determine whether to create an __dict__.
+   XXX In the future, it might also handle __weakref__.
+
+   Python 2.2 and 2.3 have fairly different rules for whether an
+   instance should get a dict.  The 2.3 rules will often create an
+   __dict__; we don't want to emulate that functionality because it
+   would make persistent classes different from non-persistent
+   new-style classes.
+*/
+
+static PyObject *
+PyPersist_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyTypeObject *new;
+
+    new = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds);
+    if (!new)
+	return NULL;
+    
+    /* the slots test is not correct, because all base types must
+       define slots to get slots.
+     */
+    if (!(PyObject_HasAttrString((PyObject *)new, "__slots__")
+	  || new->tp_dictoffset)) {
+	PyObject *descr;
+
+	/* Update the type to know about __dict__. */
+	if (type->tp_itemsize)
+	    new->tp_dictoffset = -(long)sizeof(PyObject *);
+	else
+	    new->tp_dictoffset = type->tp_basicsize;
+	/* alignment issues */
+	new->tp_basicsize += sizeof(PyObject *);
+
+	/* Put a descriptor for __dict__ in the type's __dict__.
+	   It's too late to get type to do this for us. */
+	descr = PyDescr_NewGetSet(new, persist_meta_getsets);
+	if (!descr) {
+	    Py_DECREF(new);
+	    return NULL;
+	}
+	if (PyDict_SetItemString(new->tp_dict, "__dict__", descr) < 0) {
+	    Py_DECREF(new);
+	    return NULL;
+	}
+    }
+    
+    return (PyObject *)new;
+}
+
 static PyMethodDef persist_methods[] = {
     {"__reduce__", (PyCFunction)persist_reduce, METH_NOARGS, },
     {"__getstate__", (PyCFunction)persist_getstate, METH_NOARGS, },
@@ -703,14 +723,8 @@
     {NULL}
 };
 
-static PyGetSetDef base_persist_getsets[] = {
-    {"_p_changed", (getter)persist_get_state, (setter)persist_set_state},
-    {NULL}
-};
-
 static PyGetSetDef persist_getsets[] = {
     {"_p_changed", (getter)persist_get_state, (setter)persist_set_state},
-    {"__dict__", (getter)persist_get_dict},
     {NULL}
 };
 
@@ -721,7 +735,6 @@
     {"_p_oid", T_OBJECT, offsetof(PyPersistObject, po_oid)},
     {"_p_serial", T_OBJECT, offsetof(PyPersistObject, po_serial)},
     {"_p_atime", T_INT, offsetof(PyPersistObject, po_atime)},
-    /* XXX should this be exposed? */
     {"_p_state", T_INT, offsetof(PyPersistObject, po_state), RO},
     {NULL}
 };
@@ -735,56 +748,14 @@
 */
 #define DEFERRED_ADDRESS(ADDR) 0
 
-/* XXX Not sure how much functionality the base persistent type should
-   provide.  It is currently used only by the BTrees.
-*/
-   
-
-static PyTypeObject PyPersistBase_Type = {
+static PyTypeObject PyPersist_MetaType = {
     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
     0,					/* ob_size */
-    "Persistence.BasePersistent",	/* tp_name */
-    sizeof(PyPersistBaseObject),	/* tp_basicsize */
-    0,					/* tp_itemsize */
-    (destructor)persist_dealloc,	/* tp_dealloc */
-    0,					/* tp_print */
-    0,					/* tp_getattr */
-    0,					/* tp_setattr */
-    0,					/* tp_compare */
-    0,					/* tp_repr */
-    0,					/* tp_as_number */
-    0,					/* tp_as_sequence */
-    0,					/* tp_as_mapping */
-    0,					/* tp_hash */
-    0,					/* tp_call */
-    0,					/* tp_str */
-    (getattrofunc)persist_getattro,	/* tp_getattro */
-    (setattrofunc)persist_setattro,	/* tp_setattro */
-    0,					/* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-    Py_TPFLAGS_BASETYPE, 		/* tp_flags */
-    0,					/* tp_doc */
-    (traverseproc)persist_traverse,	/* tp_traverse */
-    (inquiry)persist_clear,		/* tp_clear */
-    0,					/* tp_richcompare */
-    0,					/* tp_weaklistoffset */
-    0,					/* tp_iter */
-    0,					/* tp_iternext */
-    base_persist_methods,		/* tp_methods */
-    persist_members,			/* tp_members */
-    base_persist_getsets,		/* tp_getset */
-    0,					/* tp_base */
-    0,					/* tp_dict */
-    0,					/* tp_descr_get */
-    0,					/* tp_descr_set */
-    0,					/* tp_dictoffset */
-    0,					/* tp_init */
-    0,					/* tp_alloc */
-    0, /*PyType_GenericNew,*/		/* tp_new */
+    "Persistence.PersistentMetaClass",	/* tp_name */
 };
 
 static PyTypeObject PyPersist_Type = {
-    PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+    PyObject_HEAD_INIT(&PyPersist_MetaType)
     0,					/* ob_size */
     "Persistence.Persistent",		/* tp_name */
     sizeof(PyPersistObject),		/* tp_basicsize */
@@ -820,27 +791,26 @@
     0,					/* tp_dict */
     0,					/* tp_descr_get */
     0,					/* tp_descr_set */
-    offsetof(PyPersistObject, po_dict),	/* tp_dictoffset */
+    0, 					/* tp_dictoffset */
     0,					/* tp_init */
     0,					/* tp_alloc */
-    0, /*PyType_GenericNew,*/		/* tp_new */
+    0,					/* tp_new */
 };
 
 static PyObject *
 simple_new(PyObject *self, PyObject *type_object)
 {
-  return PyType_GenericNew((PyTypeObject*)type_object, NULL, NULL);
+    return PyType_GenericNew((PyTypeObject*)type_object, NULL, NULL);
 }
 
 static PyMethodDef PyPersist_methods[] = {
-   {"simple_new", simple_new, METH_O,
-    "Create an object by simply calling a class' __new__ method without "
-    "arguments."},
-   {NULL, NULL}
+    {"simple_new", simple_new, METH_O,
+     "Create an object by simply calling a class' __new__ method without "
+     "arguments."},
+    {NULL, NULL}
 };
 
 static PyPersist_C_API_struct c_api = {
-    &PyPersistBase_Type,
     &PyPersist_Type,
     _PyPersist_Load,
     _PyPersist_RegisterDataManager,
@@ -891,16 +861,22 @@
 {
     PyObject *m, *d, *v;
 
-    PyPersistBase_Type.ob_type = &PyType_Type;
-    PyPersistBase_Type.tp_new = PyType_GenericNew;
-    PyPersist_Type.ob_type = &PyType_Type;
-    PyPersist_Type.tp_new = PyType_GenericNew;
-    if (PyType_Ready(&PyPersistBase_Type) < 0)
+    /* It's easier to initialize a few fields by assignment than to
+       fill out the entire type structure in an initializer. 
+    */
+    PyPersist_MetaType.ob_type = &PyType_Type;
+    PyPersist_MetaType.tp_new = PyPersist_New;
+    PyPersist_MetaType.tp_base = &PyType_Type;
+    PyPersist_MetaType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+	Py_TPFLAGS_BASETYPE;
+    PyPersist_MetaType.tp_traverse = PyType_Type.tp_traverse;
+    PyPersist_MetaType.tp_clear = PyType_Type.tp_clear;
+    if (PyType_Ready(&PyPersist_MetaType) < 0)
 	return;
+
+    PyPersist_Type.tp_new = PyType_GenericNew;
     if (PyType_Ready(&PyPersist_Type) < 0)
 	return;
-    if (persist_set_interface(&PyPersistBase_Type) < 0)
-	return;
     if (persist_set_interface(&PyPersist_Type) < 0)
 	return;
 
@@ -915,10 +891,9 @@
     Py_INCREF(&PyPersist_Type);
     if (PyDict_SetItemString(d, "Persistent", (PyObject *)&PyPersist_Type) < 0)
 	return;
-
-    Py_INCREF(&PyPersistBase_Type);
-    if (PyDict_SetItemString(d, "BasePersistent", 
-			     (PyObject *)&PyPersistBase_Type) < 0)
+    Py_INCREF(&PyPersist_MetaType);
+    if (PyDict_SetItemString(d, "PersistentMetaClass", 
+			     (PyObject *)&PyPersist_MetaType) < 0)
 	return;
 
     v = PyCObject_FromVoidPtr(&c_api, NULL);


=== ZODB4/Persistence/__init__.py 1.7 => 1.8 ===
--- ZODB4/Persistence/__init__.py:1.7	Mon Oct  7 10:46:22 2002
+++ ZODB4/Persistence/__init__.py	Wed Oct  9 18:41:32 2002
@@ -11,15 +11,15 @@
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""Provide access to Persistent and BasePersistent C extension types."""
+"""Provide access to Persistent C extension types."""
 
-from cPersistence import Persistent, BasePersistent
+from cPersistence import Persistent, PersistentMetaClass
 
 # Wire up simple constructor
 import cPersistence
-simple_new = cPersistence.simple_new
-del cPersistence.simple_new
-del cPersistence
+##simple_new = cPersistence.simple_new
+##del cPersistence.simple_new
+##del cPersistence
 import copy_reg
-copy_reg.constructor(simple_new)
-del copy_reg
+copy_reg.constructor(cPersistence.simple_new)
+##del copy_reg


=== ZODB4/Persistence/Module.py 1.27 => 1.28 ===
--- ZODB4/Persistence/Module.py:1.27	Tue Oct  8 16:58:43 2002
+++ ZODB4/Persistence/Module.py	Wed Oct  9 18:41:32 2002
@@ -22,7 +22,7 @@
 
 from Persistence import Persistent
 from Persistence.cPersistence import GHOST
-from Persistence.Class import PersistentMetaClass
+from Persistence.Class import PersistentClassMetaClass
 from Persistence.Function import PersistentFunction
 from Persistence.IPersistentModuleManager import IPersistentModuleManager
 from Persistence.IPersistentModuleRegistry \
@@ -135,7 +135,7 @@
         for k, v in new.items():
             if isinstance(v, function):
                 v = new[k] = PersistentFunction(v, module)
-            elif isinstance(v.__class__, PersistentMetaClass):
+            elif isinstance(v.__class__, PersistentClassMetaClass):
                 v.__class__.fixup(module)
             # XXX need to check for classes that are not persistent!
 


=== ZODB4/Persistence/Class.py 1.3 => 1.4 ===
--- ZODB4/Persistence/Class.py:1.3	Thu Oct  3 00:16:59 2002
+++ ZODB4/Persistence/Class.py	Wed Oct  9 18:41:32 2002
@@ -13,7 +13,7 @@
 ##############################################################################
 """Persistent Classes."""
 
-from Persistence import Persistent
+from Persistence import Persistent, PersistentMetaClass
 from Persistence.cPersistence import UPTODATE, CHANGED, STICKY, GHOST
 from Persistence.IPersistent import IPersistent
 from Persistence.Function import PersistentFunction
@@ -22,6 +22,10 @@
 from types import FunctionType as function
 import time
 
+# XXX There is a lot of magic here to give classes and instances
+# separate sets of attributes.  This code should be documented, as it
+# it quite delicate, and it should be move to a separate module.
+
 class ExtClassDescr(object):
     """Maintains seperate class and instance descriptors for an attribute.
 
@@ -144,7 +148,7 @@
             return o
     return default
 
-class PersistentMetaClass(type):
+class PersistentClassMetaClass(PersistentMetaClass):
 
     # an attempt to make persistent classes look just like other
     # persistent objects by providing class attributes and methods
@@ -158,7 +162,7 @@
     _pc_init = 0
 
     def __new__(meta, name, bases, dict):
-        cls = super(PersistentMetaClass, meta).__new__(meta, name, bases, dict)
+        cls = super(PersistentClassMetaClass, meta).__new__(meta, name, bases, dict)
         # helper functions
         def extend_attr(attr, v):
             prev = findattr(cls, attr, None)
@@ -191,7 +195,7 @@
             if cls._p_state is None:
                 cls._p_activate()
                 cls._p_atime = int(time.time() % 86400)
-        return super(PersistentMetaClass, cls).__getattribute__(name)
+        return super(PersistentClassMetaClass, cls).__getattribute__(name)
 
     def __setattr__(cls, attr, val):
         if not attr.startswith("_pc_") and cls._pc_init:
@@ -201,7 +205,7 @@
                 if set is not None:
                     set(None, val)
                     return
-        super(PersistentMetaClass, cls).__setattr__(attr, val)
+        super(PersistentClassMetaClass, cls).__setattr__(attr, val)
 
     def __delattr__(cls, attr):
         if attr.startswith('_p_'):
@@ -210,7 +214,7 @@
                 pass
             else:
                 return
-        super(PersistentMetaClass, cls).__delattr__(attr)
+        super(PersistentClassMetaClass, cls).__delattr__(attr)
     
     def __getstate__(cls):
         dict = {}
@@ -242,14 +246,14 @@
 
 class PersistentBaseClass(Persistent):
 
-    __metaclass__ = PersistentMetaClass
+    __metaclass__ = PersistentClassMetaClass
 
 def _test():
     global PC, P
 
     class PC(Persistent):
 
-        __metaclass__ = PersistentMetaClass
+        __metaclass__ = PersistentClassMetaClass
 
         def __init__(self):
             self.x = 1