[Zope-Checkins] CVS: ZODB3/Persistence - TimeStamp.c:1.3.2.1 cPickleCache.c:1.85.8.1 cPersistence.h:1.25.122.1 cPersistence.c:1.72.8.1 __init__.py:1.4.88.1

Jeremy Hylton jeremy@zope.com
Tue, 1 Jul 2003 15:28:12 -0400


Update of /cvs-repository/ZODB3/Persistence
In directory cvs.zope.org:/tmp/cvs-serv28481/Persistence

Modified Files:
      Tag: zodb33-devel-branch
	cPickleCache.c cPersistence.h cPersistence.c __init__.py 
Added Files:
      Tag: zodb33-devel-branch
	TimeStamp.c 
Log Message:
Initial versions of code that does not depend on ExtensionClass.

There are a bunch of refcount problems, but occasionally some tests
pass.


=== Added File ZODB3/Persistence/TimeStamp.c ===
/*****************************************************************************

  Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
  
  This software is subject to the provisions of the Zope Public License,
  Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  FOR A PARTICULAR PURPOSE
  
 ****************************************************************************/

#include "Python.h"
#include <time.h>

PyObject *TimeStamp_FromDate(int, int, int, int, int, double);
PyObject *TimeStamp_FromString(const char *);

static char TimeStampModule_doc[] = 
"A 64-bit TimeStamp used as a ZODB serial number.\n";

typedef struct {
    PyObject_HEAD
    unsigned char data[8];
} TimeStamp;

/* The first dimension of the arrays below is non-leapyear / leapyear */

static char month_len[2][12]={
  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

static short joff[2][12] = {
  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
  {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};

static double gmoff=0;

/* XXX should this be stored in sconv? */
#define SCONV ((double)60) / ((double)(1<<16)) / ((double)(1<<16))

static int
leap(int year)
{
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

static int
days_in_month(int year, int month)
{
    return month_len[leap(year)][month];
}

static double
TimeStamp_yad(int y)
{
    double d, s;

    y -= 1900;
  
    d = (y - 1) * 365;
    if (y > 0) {
        s = 1.0;
	y -= 1;
    } else {
	s = -1.0;
	y = -y;
    }
    return d + s * (y / 4 - y / 100 + (y + 300) / 400);
}

static double
TimeStamp_abst(int y, int mo, int d, int m, int s)
{
    return (TimeStamp_yad(y) + joff[leap(y)][mo] + d) * 86400 + m * 60 + s;
}

static int
TimeStamp_init_gmoff(void)
{
    struct tm *t;
    time_t z=0;
  
    t = gmtime(&z);
    if (t == NULL) {
	PyErr_SetString(PyExc_SystemError, "gmtime failed");
	return -1;
    }

    gmoff = TimeStamp_abst(t->tm_year+1900, t->tm_mon, t->tm_mday - 1, 
			   t->tm_hour * 60 + t->tm_min, t->tm_sec);

    return 0;
}

static void
TimeStamp_dealloc(TimeStamp *ts)
{
    PyObject_Del(ts);
}

static int
TimeStamp_compare(TimeStamp *v, TimeStamp *w)
{
    int cmp = memcmp(v->data, w->data, 8);
    if (cmp < 0) return -1;
    if (cmp > 0) return 1;
    return 0;
}

static long
TimeStamp_hash(TimeStamp *self)
{
    register unsigned char *p = (unsigned char *)self->data;
    register int len = 8;
    register long x = *p << 7;
    /* XXX unroll loop? */
    while (--len >= 0)
	x = (1000003*x) ^ *p++;
    x ^= 8;
    if (x == -1)
	x = -2;
    return x;
}

typedef struct {
    int y, m, d, mi;
} TimeStampParts;
  
static void 
TimeStamp_unpack(TimeStamp *self, TimeStampParts *p)
{
    unsigned long v;

    v = (self->data[0] * 16777216 + self->data[1] * 65536 
	 + self->data[2] * 256 + self->data[3]);
    p->y = v / 535680 + 1900;
    p->m = (v % 535680) / 44640 + 1;
    p->d = (v % 44640) / 1440 + 1;
    p->mi = v % 1440;
}

static double
TimeStamp_sec(TimeStamp *self)
{
    unsigned int v;

    v = (self->data[4] * 16777216 + self->data[5] * 65536
	 + self->data[6] * 256 + self->data[7]);
    return SCONV * v;
}

static PyObject *
TimeStamp_year(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyInt_FromLong(p.y);
}

static PyObject *
TimeStamp_month(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyInt_FromLong(p.m);
}

static PyObject *
TimeStamp_day(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyInt_FromLong(p.d);
}

static PyObject *
TimeStamp_hour(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyInt_FromLong(p.mi / 60);
}

static PyObject *
TimeStamp_minute(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyInt_FromLong(p.mi % 60);
}

static PyObject *
TimeStamp_second(TimeStamp *self)
{
    return PyFloat_FromDouble(TimeStamp_sec(self));
}

static PyObject *
TimeStamp_timeTime(TimeStamp *self)
{
    TimeStampParts p;
    TimeStamp_unpack(self, &p);
    return PyFloat_FromDouble(TimeStamp_abst(p.y, p.m - 1, p.d - 1, p.mi, 0)
			      + TimeStamp_sec(self) - gmoff);
}

static PyObject *
TimeStamp_raw(TimeStamp *self)
{
    return PyString_FromStringAndSize(self->data, 8);
}

static PyObject *
TimeStamp_laterThan(TimeStamp *self, PyObject *obj)
{
    TimeStamp *o = NULL;
    TimeStampParts p;
    unsigned char new[8];
    int i;

    if (obj->ob_type != self->ob_type) {
	PyErr_SetString(PyExc_TypeError, "expected TimeStamp object");
	return NULL;
    }
    o = (TimeStamp *)obj;
    if (memcmp(self->data, o->data, 8) > 0) {
	Py_INCREF(self);
	return (PyObject *)self;
    }

    memcpy(new, o->data, 8);
    for (i = 7; i > 3; i--) {
	if (new[i] == 255)
	    new[i] = 0;
	else {
	    new[i]++;
	    return TimeStamp_FromString(new);
	}
    }

    /* All but the first two bytes are the same.  Need to increment
       the year, month, and day explicitly. */
    TimeStamp_unpack(o, &p);
    if (p.mi >= 1439) {
	p.mi = 0;
	if (p.d == month_len[leap(p.y)][p.m - 1]) {
	    p.d = 1;
	    if (p.m == 12) {
		p.m = 1;
		p.y++;
	    } else
		p.m++;
	} else
	    p.d++;
    } else
	p.mi++;

    return TimeStamp_FromDate(p.y, p.m, p.d, p.mi / 60, p.mi % 60, 0);
}

static struct PyMethodDef TimeStamp_methods[] = {
    {"year", 	(PyCFunction)TimeStamp_year, 	METH_NOARGS},
    {"minute", 	(PyCFunction)TimeStamp_minute, 	METH_NOARGS},
    {"month", 	(PyCFunction)TimeStamp_month, 	METH_NOARGS},
    {"day", 	(PyCFunction)TimeStamp_day,	METH_NOARGS},
    {"hour", 	(PyCFunction)TimeStamp_hour, 	METH_NOARGS},
    {"second", 	(PyCFunction)TimeStamp_second, 	METH_NOARGS},
    {"timeTime",(PyCFunction)TimeStamp_timeTime, 	METH_NOARGS},
    {"laterThan", (PyCFunction)TimeStamp_laterThan, 	METH_O},
    {"raw",	(PyCFunction)TimeStamp_raw,	METH_NOARGS},
    {NULL,	NULL},
};

static PyTypeObject TimeStamp_type = {
    PyObject_HEAD_INIT(NULL)
    0,
    "Persistence.TimeStamp",
    sizeof(TimeStamp),
    0,
    (destructor)TimeStamp_dealloc,	/* tp_dealloc */
    0,					/* tp_print */
    0,					/* tp_getattr */
    0,					/* tp_setattr */
    (cmpfunc)TimeStamp_compare,		/* tp_compare */
    (reprfunc)TimeStamp_raw,		/* tp_repr */
    0,					/* tp_as_number */
    0,					/* tp_as_sequence */
    0,					/* tp_as_mapping */
    (hashfunc)TimeStamp_hash,		/* tp_hash */
    0,					/* tp_call */
    0,					/* tp_str */
    0,					/* tp_getattro */
    0,					/* tp_setattro */
    0,					/* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    0,					/* tp_doc */
    0,					/* tp_traverse */
    0,					/* tp_clear */
    0,					/* tp_richcompare */
    0,					/* tp_weaklistoffset */
    0,					/* tp_iter */
    0,					/* tp_iternext */
    TimeStamp_methods,			/* tp_methods */
    0,					/* tp_members */
    0,					/* tp_getset */
    0,					/* tp_base */
    0,					/* tp_dict */
    0,					/* tp_descr_get */
    0,					/* tp_descr_set */
};

PyObject *
TimeStamp_FromString(const char *buf)
{
    /* buf must be exactly 8 characters */
    TimeStamp *ts = (TimeStamp *)PyObject_New(TimeStamp, &TimeStamp_type);
    memcpy(ts->data, buf, 8);
    return (PyObject *)ts;
}

#define CHECK_RANGE(VAR, LO, HI) if ((VAR) < (LO) || (VAR) > (HI)) { \
     return PyErr_Format(PyExc_ValueError, \
			 # VAR " must be between %d and %d: %d", \
			 (LO), (HI), (VAR)); \
    }

PyObject *
TimeStamp_FromDate(int year, int month, int day, int hour, int min, 
		   double sec)
{
    TimeStamp *ts = NULL;
    int d;
    unsigned int v;

    if (year < 1900) 
	return PyErr_Format(PyExc_ValueError,
			    "year must be greater than 1900: %d", year);
    CHECK_RANGE(month, 1, 12);
    d = days_in_month(year, month - 1);
    if (day < 1 || day > d)
	return PyErr_Format(PyExc_ValueError,
			    "day must be between 1 and %d: %d", d, day);
    CHECK_RANGE(hour, 0, 23);
    CHECK_RANGE(min, 0, 59);
    /* Seconds are allowed to be anything, so chill
       If we did want to be pickly, 60 would be a better choice.
    if (sec < 0 || sec > 59)
	return PyErr_Format(PyExc_ValueError,
			    "second must be between 0 and 59: %f", sec);
    */
    ts = (TimeStamp *)PyObject_New(TimeStamp, &TimeStamp_type);
    v = (((year - 1900) * 12 + month - 1) * 31 + day - 1);
    v = (v * 24 + hour) * 60 + min;
    ts->data[0] = v / 16777216;
    ts->data[1] = (v % 16777216) / 65536;
    ts->data[2] = (v % 65536) / 256;
    ts->data[3] = v % 256;
    sec /= SCONV;
    v = (unsigned int)sec;
    ts->data[4] = v / 16777216;
    ts->data[5] = (v % 16777216) / 65536;
    ts->data[6] = (v % 65536) / 256;
    ts->data[7] = v % 256;

    return (PyObject *)ts;
}

PyObject *
TimeStamp_TimeStamp(PyObject *obj, PyObject *args)
{
    char *buf = NULL;
    int len = 0, y, mo, d, h = 0, m = 0;
    double sec = 0;

    if (PyArg_ParseTuple(args, "s#:TimeStamp", &buf, &len)) {
	if (len != 8) {
	    PyErr_SetString(PyExc_ValueError, "8-character string expected");
	    return NULL;
	}
	return TimeStamp_FromString(buf);
    }
    PyErr_Clear();

    if (!PyArg_ParseTuple(args, "iii|iid", &y, &mo, &d, &h, &m, &sec))
	return NULL;
    return TimeStamp_FromDate(y, mo, d, h, m, sec);
}

static PyMethodDef TimeStampModule_functions[] = {
    {"TimeStamp",	TimeStamp_TimeStamp,	METH_VARARGS},
    {NULL,		NULL},
};


void
initTimeStamp(void)
{
    PyObject *m;

    if (TimeStamp_init_gmoff() < 0)
	return;

    m = Py_InitModule4("TimeStamp", TimeStampModule_functions,
		       TimeStampModule_doc, NULL, PYTHON_API_VERSION);
    if (m == NULL)
	return;

    TimeStamp_type.ob_type = &PyType_Type;
    TimeStamp_type.tp_getattro = PyObject_GenericGetAttr;
}
 



=== ZODB3/Persistence/cPickleCache.c 1.85 => 1.85.8.1 ===
--- ZODB3/Persistence/cPickleCache.c:1.85	Fri May 30 15:20:55 2003
+++ ZODB3/Persistence/cPickleCache.c	Tue Jul  1 15:28:11 2003
@@ -303,7 +303,7 @@
 
     if (!v)
 	return;
-    if (PyExtensionClass_Check(v)) {
+    if (PyType_Check(v)) {
 	if (v->ob_refcnt <= 1) {
 	    self->klass_count--;
 	    if (PyDict_DelItem(self->data, key) < 0)
@@ -397,7 +397,7 @@
 	return NULL;
 
     while (PyDict_Next(self->data, &p, &k, &v)) {
-        if(PyExtensionClass_Check(v)) {
+        if(PyType_Check(v)) {
 	    v = Py_BuildValue("OO", k, v);
 	    if (v == NULL) {
 		Py_DECREF(l);
@@ -709,16 +709,16 @@
     PyObject *oid, *object_again, *jar;
     cPersistentObject *p;
 
-    if (PyExtensionClass_Check(v)) {
+    if (PyType_Check(v)) {
         /* Its a persistent class, such as a ZClass. Thats ok. */
     }
-    else if( PyExtensionInstance_Check(v) &&
-             (((PyExtensionClass*)(v->ob_type))->class_flags & PERSISTENT_TYPE_FLAG) &&
-             (v->ob_type->tp_basicsize >= sizeof(cPersistentObject)) ) {
-        /* Its and instance of a persistent class, (ie Python classeses that
-        derive from Persistence.Persistent, BTrees, etc). Thats ok. */
-    }
-    else {
+    else if (v->ob_type->tp_basicsize < sizeof(cPersistentObject)) {
+        /* If it's not an instance of a persistent class, (ie Python
+	   classes that derive from Persistence.Persistent, BTrees,
+	   etc), report an error.
+
+	   XXX Need a better test.
+	*/
 	PyErr_SetString(PyExc_TypeError, 
 			"Cache values must be persistent objects.");
 	return -1;
@@ -774,7 +774,7 @@
 	}
     }
 
-    if (PyExtensionClass_Check(v)) {
+    if (PyType_Check(v)) {
 	if (PyDict_SetItem(self->data, key, v) < 0) 
 	    return -1;
 	self->klass_count++;
@@ -829,7 +829,7 @@
     if (v == NULL)
 	return -1;
 
-    if (PyExtensionClass_Check(v)) {
+    if (PyType_Check(v)) {
 	self->klass_count--;
     } else {
 	p = (cPersistentObject *)v;
@@ -887,7 +887,7 @@
 static PyTypeObject Cctype = {
     PyObject_HEAD_INIT(NULL)
     0,				/*ob_size*/
-    "cPickleCache",		/*tp_name*/
+    "Persistence.cPickleCache",	/*tp_name*/
     sizeof(ccobject),		/*tp_basicsize*/
     0,				/*tp_itemsize*/
     /* methods */
@@ -955,27 +955,23 @@
 void
 initcPickleCache(void)
 {
-    PyObject *m, *d;
+    PyObject *m;
 
     Cctype.ob_type = &PyType_Type;
 
-    if (!ExtensionClassImported) 
-	return;
+    m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
+		       (PyObject*)NULL, PYTHON_API_VERSION);
 
-    capi = (cPersistenceCAPIstruct *)PyCObject_Import("cPersistence", "CAPI");
+    capi = (cPersistenceCAPIstruct *)PyCObject_Import(
+	"Persistence.cPersistence", "CAPI");
     if (!capi)
 	return;
     capi->percachedel = (percachedelfunc)cc_oid_unreferenced;
 
-    m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
-		       (PyObject*)NULL, PYTHON_API_VERSION);
-
     py_reload = PyString_InternFromString("reload");
     py__p_jar = PyString_InternFromString("_p_jar");
     py__p_changed = PyString_InternFromString("_p_changed");
     py__p_oid = PyString_InternFromString("_p_oid");
 
-    d = PyModule_GetDict(m);
-
-    PyDict_SetItemString(d, "cache_variant", PyString_FromString("stiff/c"));
+    PyModule_AddStringConstant(m, "cache_variant", "stiff/c");
 }


=== ZODB3/Persistence/cPersistence.h 1.25 => 1.25.122.1 ===
--- ZODB3/Persistence/cPersistence.h:1.25	Thu Apr  4 20:12:48 2002
+++ ZODB3/Persistence/cPersistence.h	Tue Jul  1 15:28:11 2003
@@ -15,7 +15,7 @@
 #ifndef CPERSISTENCE_H
 #define CPERSISTENCE_H
 
-#include "ExtensionClass.h"
+#include "Python.h"
 #include <time.h>
 
 typedef struct CPersistentRing_struct
@@ -57,7 +57,7 @@
 typedef int (*percachedelfunc)(PerCache *, PyObject *);
 
 typedef struct {
-    PyMethodChain *methods;
+    PyTypeObject *pertype;
     getattrofunc getattro;
     setattrofunc setattro;
     int (*changed)(cPersistentObject*);
@@ -76,13 +76,7 @@
 
 #define cPersistanceModuleName "cPersistence"
 
-#define PERSISTENT_TYPE_FLAG EXTENSIONCLASS_USER_FLAG8
-
-/* ExtensionClass class flags for persistent base classes should
-   include PERSISTENCE_FLAGS. 
-*/
-#define PERSISTENCE_FLAGS EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG \
-  | EXTENSIONCLASS_PYTHONICATTR_FLAG
+#define PER_TypeCheck(O) PyObject_TypeCheck((O), cPersistenceCAPI->pertype)
 
 #define PER_USE_OR_RETURN(O,R) {if((O)->state==cPersistent_GHOST_STATE && cPersistenceCAPI->setstate((PyObject*)(O)) < 0) return (R); else if ((O)->state==cPersistent_UPTODATE_STATE) (O)->state=cPersistent_STICKY_STATE;}
 


=== ZODB3/Persistence/cPersistence.c 1.72 => 1.72.8.1 ===
--- ZODB3/Persistence/cPersistence.c:1.72	Fri May 30 15:20:55 2003
+++ ZODB3/Persistence/cPersistence.c	Tue Jul  1 15:28:11 2003
@@ -148,7 +148,7 @@
 
 /****************************************************************************/
 
-staticforward PyExtensionClass Pertype;
+static PyTypeObject Pertype;
 
 static void
 accessed(cPersistentObject *self)
@@ -277,7 +277,7 @@
 static PyObject *
 Per__p_deactivate(cPersistentObject *self, PyObject *args)
 {
-  PyObject *dict,*dict2=NULL;
+  PyObject *dict, *dict2=NULL;
 
 #ifdef DEBUG_LOG
   if (idebug_log < 0) call_debug("reinit",self);
@@ -286,16 +286,18 @@
   if (args && !checknoargs(args))
     return NULL;
 
-  if (self->state==cPersistent_UPTODATE_STATE && self->jar &&
-      HasInstDict(self) && (dict=INSTANCE_DICT(self)))
-    {
-      dict2 = PyDict_Copy(dict);
-      PyDict_Clear(dict);
-      /* Note that we need to set to ghost state unless we are 
-	 called directly. Methods that override this need to
-         do the same! */
-      ghostify(self);
-    }
+  if (self->state==cPersistent_UPTODATE_STATE && self->jar) {
+      PyObject **dictptr = _PyObject_GetDictPtr((PyObject *)self);
+      if (dictptr) {
+	  dict = *dictptr;
+	  dict2 = PyDict_Copy(dict);
+	  PyDict_Clear(dict);
+	  /* Note that we need to set to ghost state unless we are 
+	     called directly. Methods that override this need to
+	     do the same! */
+	  ghostify(self);
+      }
+  }
 
   /* need to delay releasing the last reference on instance attributes
      until after we have finished accounting for losing our state */
@@ -322,7 +324,7 @@
 static PyObject *
 Per__getstate__(cPersistentObject *self, PyObject *args)
 {
-    PyObject *__dict__, *d=0;
+    PyObject **dictptr, *__dict__, *d=0;
 
     if (!checknoargs(args))
         return NULL;
@@ -335,10 +337,13 @@
     if (!unghostify(self))
         return NULL;
 
-    if (HasInstDict(self) && (__dict__=INSTANCE_DICT(self))) {
+    dictptr = _PyObject_GetDictPtr((PyObject *)self);
+    if (dictptr) {
         PyObject *k, *v;
         int pos;
         char *ck;
+
+	__dict__ = *dictptr;
 	  
         for(pos=0; PyDict_Next(__dict__, &pos, &k, &v); ) {
             if (PyString_Check(k) && (ck=PyString_AS_STRING(k)) &&
@@ -374,16 +379,16 @@
   PyObject *__dict__, *v, *keys=0, *key=0, *e=0;
   int l, i;
 
-  if (HasInstDict(self))
-    {
-
+  if (_PyObject_GetDictPtr((PyObject *)self)) {
        UNLESS(PyArg_ParseTuple(args, "O", &v)) return NULL;
 #ifdef DEBUG_LOG
        if (idebug_log < 0) call_debug("set",self);
 #endif
        if (v!=Py_None)
 	 {
-	   __dict__=INSTANCE_DICT(self);
+	     PyObject **dictptr = _PyObject_GetDictPtr((PyObject *)self);
+	     assert(dictptr);
+	     __dict__ = *dictptr;
 	   
 	   if (PyDict_Check(v))
 	     {
@@ -442,7 +447,7 @@
 #endif
   deallocated(self);
   Py_DECREF(self->ob_type);
-  PyObject_DEL(self);
+  self->ob_type->tp_free(self);
 }
 
 static PyObject *
@@ -453,11 +458,36 @@
   return v;
 }
 
+/* convert_name() returns a new reference to a string name
+   or sets an exception and returns NULL.
+*/
+
 static PyObject *
-Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
-	 PyObject *(*getattrf)(PyObject *, PyObject*))
+convert_name(PyObject *name)
 {
-  char *n=name;
+#ifdef Py_USING_UNICODE
+    /* The Unicode to string conversion is done here because the
+       existing tp_setattro slots expect a string object as name
+       and we wouldn't want to break those. */
+    if (PyUnicode_Check(name)) {
+	name = PyUnicode_AsEncodedString(name, NULL, NULL);
+    }
+    else
+#endif
+    if (!PyString_Check(name)) {
+	PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
+	return NULL;
+    } else
+	Py_INCREF(name);
+    return name;
+}
+
+static PyObject *
+Per_getattr(cPersistentObject *self, PyObject *oname)
+{
+  char *n, *name;
+  name = PyString_AS_STRING(oname);
+  n = name;
 
   if (n && *n++=='_')
     if (*n++=='p' && *n++=='_')
@@ -518,7 +548,7 @@
 	    break;
 	  }
 
-	return getattrf((PyObject *)self, oname);
+	return self->ob_type->tp_base->tp_getattro((PyObject *)self, oname);
       }
   if (! (name && *name++=='_' && *name++=='_' &&
 	(strcmp(name,"dict__")==0 || strcmp(name,"class__")==0
@@ -530,40 +560,27 @@
       accessed(self);
     }
 
-  return getattrf((PyObject *)self, oname);
+  return PyObject_GenericGetAttr((PyObject *)self, oname);
 }
 
 static PyObject*
 Per_getattro(cPersistentObject *self, PyObject *name)
 {
-  char *s=NULL;
   PyObject *r;
 
-  if (PyString_Check(name))
-    UNLESS(s=PyString_AS_STRING(name)) return NULL;
-
-  r = Per_getattr(self, name, s, PyExtensionClassCAPI->getattro);
-  if (! r && self->state != cPersistent_GHOST_STATE &&
-      (((PyExtensionClass*)(self->ob_type))->class_flags 
-       & EXTENSIONCLASS_USERGETATTR_FLAG)
-      )
-    {
-      PyErr_Clear();
+  
+  name = convert_name(name);
+  if (!name)
+      return NULL;
 
-      r=PyObject_GetAttr(OBJECT(self), py___getattr__);
-      if (r) 
-	{
-	  ASSIGN(r, PyObject_CallFunction(r, "O", name));
-	}
-      else PyErr_SetObject(PyExc_AttributeError, name);
-    }
+  r = Per_getattr(self, name);
  
+  Py_DECREF(name);
   return r;  
 }
 
 static int
-_setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
-	     int (*setattrf)(PyObject *, PyObject*, PyObject*))
+_setattro(cPersistentObject *self, PyObject *oname, PyObject *v)
 {
   char *name = "";
 
@@ -687,15 +704,12 @@
 
       if ((! (*name=='_' && name[1]=='v' && name[2]=='_'))
 	 && (self->state != cPersistent_CHANGED_STATE && self->jar)
-	 && setattrf
+	  && self->ob_type->tp_base->tp_setattro
 	 )
 	if (changed(self) < 0) return -1;
     }
 
-  if (setattrf)
-    return setattrf((PyObject*)self,oname,v);
-  
-  return 1;			/* Ready for user setattr */
+  return PyObject_GenericSetAttr((PyObject *)self, oname, v);
 }
 
 static int
@@ -704,10 +718,9 @@
   int r;
   PyObject *m;
 
-  if (v && (((PyExtensionClass*)self->ob_type)->class_flags 
-	    & EXTENSIONCLASS_USERSETATTR_FLAG))
+  if (v)
     {
-      r = _setattro(self, oname, v, NULL);
+      r = _setattro(self, oname, v);
       if (r < 1) return r;
 
       m=PyObject_GetAttr(OBJECT(self), py___setattr__);
@@ -717,11 +730,9 @@
 	}
       else PyErr_SetObject(PyExc_AttributeError, oname);
     }
-  else if (!v && (((PyExtensionClass*)self->ob_type)->class_flags 
-		  & EXTENSIONCLASS_USERDELATTR_FLAG)
-	   )
+  else if (!v)
     {
-      r=_setattro(self,oname, v, NULL);
+      r=_setattro(self,oname, v);
       if (r < 1) return r;
 
       m=PyObject_GetAttr(OBJECT(self), py___delattr__);
@@ -732,7 +743,7 @@
       else PyErr_SetObject(PyExc_AttributeError, oname);
     }
   else
-    return _setattro(self, oname, v, PyExtensionClassCAPI->setattro);
+      return _setattro(self, oname, v);
 
   if (m) 
     {
@@ -743,61 +754,50 @@
   return -1;
 }
 
-static PyExtensionClass Pertype = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Persistent",			/*tp_name*/
-	sizeof(cPersistentObject),	/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	(destructor)Per_dealloc,	/*tp_dealloc*/
-	(printfunc)0,			/*tp_print*/
-	(getattrfunc)0,			/*tp_getattr*/
-	(setattrfunc)0,	       		/*tp_setattr*/
-	(cmpfunc)0,			/*tp_compare*/
-	(reprfunc)0,			/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	(hashfunc)0,			/*tp_hash*/
-	(ternaryfunc)0,			/*tp_call*/
-	(reprfunc)0,			/*tp_str*/
-	(getattrofunc)Per_getattro,	/*tp_getattr with object key*/
-	(setattrofunc)Per_setattro,	/*tp_setattr with object key*/
-	/* Space for future expansion */
-	0L,0L,
-        "Base class for objects that are stored in their own database records",
-	METHOD_CHAIN(Per_methods),
-	PERSISTENCE_FLAGS,
-};
-
-static PyExtensionClass Overridable = {
-	PyObject_HEAD_INIT(NULL)
-	0,				/*ob_size*/
-	"Overridable",			/*tp_name*/
-	sizeof(cPersistentObject),	/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	(destructor)Per_dealloc,	/*tp_dealloc*/
-	(printfunc)0,			/*tp_print*/
-	(getattrfunc)0,			/*tp_getattr*/
-	(setattrfunc)0,	       		/*tp_setattr*/
-	(cmpfunc)0,			/*tp_compare*/
-	(reprfunc)0,			/*tp_repr*/
-	0,				/*tp_as_number*/
-	0,				/*tp_as_sequence*/
-	0,				/*tp_as_mapping*/
-	(hashfunc)0,			/*tp_hash*/
-	(ternaryfunc)0,			/*tp_call*/
-	(reprfunc)0,			/*tp_str*/
-	(getattrofunc)Per_getattro,	/*tp_getattr with object key*/
-	(setattrofunc)Per_setattro,	/*tp_setattr with object key*/
-	/* Space for future expansion */
-	0L,0L,
-        "Hacked base class used in Zope's App.Uninstalled.BrokenClass\n\n"
-        "Not sure if this is still needed",
-	METHOD_CHAIN(Per_methods),
-	EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG
+/* This module is compiled as a shared library.  Some compilers don't
+   allow addresses of Python objects defined in other libraries to be
+   used in static initializers here.  The DEFERRED_ADDRESS macro is
+   used to tag the slots where such addresses appear; the module init
+   function must fill in the tagged slots at runtime.  The argument is
+   for documentation -- the macro ignores it.
+*/
+#define DEFERRED_ADDRESS(ADDR) 0
+
+/* A reminder that these need to be implemented. */
+#define Per_traverse 0
+#define Per_clear 0
+
+static PyTypeObject Pertype = {
+    PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyPersist_MetaType))
+    0,					/* ob_size */
+    "Persistence.Persistent",		/* tp_name */
+    sizeof(cPersistentObject),		/* tp_basicsize */
+    0,					/* tp_itemsize */
+    (destructor)Per_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)Per_getattro,		/* tp_getattro */
+    (setattrofunc)Per_setattro,		/* tp_setattro */
+    0,					/* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+    					/* tp_flags */
+    0,					/* tp_doc */
+    (traverseproc)Per_traverse,		/* tp_traverse */
+    (inquiry)Per_clear,			/* tp_clear */
+    0,					/* tp_richcompare */
+    0,					/* tp_weaklistoffset */
+    0,					/* tp_iter */
+    0,					/* tp_iternext */
+    Per_methods,			/* tp_methods */
 };
 
 /* End of code for Persistent objects */
@@ -836,53 +836,53 @@
 
 static cPersistenceCAPIstruct
 truecPersistenceCAPI = {
-  &(Pertype.methods),
-  (getattrofunc)Per_getattro,	/*tp_getattr with object key*/
-  (setattrofunc)Per_setattro,	/*tp_setattr with object key*/
-  changed,
-  accessed,
-  ghostify,
-  deallocated,
-  (intfunctionwithpythonarg)Per_setstate,
-  (pergetattr)Per_getattr,
-  (persetattr)_setattro,
-  NULL /* The percachedel slot is initialized in cPickleCache.c when
-          the module is loaded.  It uses a function in a different
-          shared library. */
+    &Pertype,    
+    (getattrofunc)Per_getattro,	/*tp_getattr with object key*/
+    (setattrofunc)Per_setattro,	/*tp_setattr with object key*/
+    changed,
+    accessed,
+    ghostify,
+    deallocated,
+    (intfunctionwithpythonarg)Per_setstate,
+    (pergetattr)Per_getattr,
+    (persetattr)_setattro,
+    NULL /* The percachedel slot is initialized in cPickleCache.c when
+	    the module is loaded.  It uses a function in a different
+	    shared library. */
 };
 
 void
 initcPersistence(void)
 {
-  PyObject *m, *d, *s;
+    PyObject *m, *s;
 
-  s = PyString_FromString("ZODB.TimeStamp");
-  if (s == NULL)
-      return;
-  m = PyImport_Import(s);
-  if (m == NULL) {
-      Py_DECREF(s);
+    if (init_strings() < 0) 
       return;
-  }
-  TimeStamp = PyObject_GetAttrString(m, "TimeStamp");
-  assert(TimeStamp);
-  Py_DECREF(m);
-  Py_DECREF(s);
-
-  if (init_strings() < 0) 
-      return;
-
-  m = Py_InitModule4("cPersistence", cP_methods, cPersistence_doc_string,
+    
+    m = Py_InitModule4("cPersistence", cP_methods, cPersistence_doc_string,
 		     (PyObject*)NULL, PYTHON_API_VERSION);
+    
 
-  
-  d = PyModule_GetDict(m);
+    Pertype.ob_type = &PyType_Type;
+    Pertype.tp_new = PyType_GenericNew;
+    if (PyType_Ready(&Pertype) < 0)
+	return;
+    if (PyModule_AddObject(m, "Persistent", (PyObject *)&Pertype) < 0)
+	return;
 
-  PyExtensionClass_Export(d, "Persistent",  Pertype);
-  PyExtensionClass_Export(d, "Overridable", Overridable);
+    cPersistenceCAPI = &truecPersistenceCAPI;
+    s = PyCObject_FromVoidPtr(cPersistenceCAPI, NULL);
+    if (!s)
+	return;
+    if (PyModule_AddObject(m, "CAPI", s) < 0)
+	return;
 
-  cPersistenceCAPI = &truecPersistenceCAPI;
-  s = PyCObject_FromVoidPtr(cPersistenceCAPI, NULL);
-  PyDict_SetItemString(d, "CAPI", s);
-  Py_XDECREF(s);
+    /* Initialize the global TimeStamp variable. */
+    m = PyImport_ImportModule("Persistence.TimeStamp");
+    if (!m)
+	return;
+    TimeStamp = PyObject_GetAttrString(m, "TimeStamp");
+    if (!TimeStamp)
+	return;
+    Py_DECREF(m);
 }


=== ZODB3/Persistence/__init__.py 1.4 => 1.4.88.1 ===
--- ZODB3/Persistence/__init__.py:1.4	Wed Aug 14 17:43:18 2002
+++ ZODB3/Persistence/__init__.py	Tue Jul  1 15:28:11 2003
@@ -11,10 +11,6 @@
 # FOR A PARTICULAR PURPOSE
 #
 ##############################################################################
-"""Provide access to Persistent and PersistentMapping
+"""Provide access to Persistent and PersistentMapping."""
 
-This avoids dependency on the database package name.
-
-While obviously there is nothing in this module, the correct names are
-inserted by the __init__.py in ZODB, jumpstarting the process.
-"""
+from cPersistence import Persistent