[Zope-Checkins] CVS: ZODB3/Persistence - cPersistence.c:1.72.8.11 cPersistence.h:1.25.122.2

Jeremy Hylton jeremy@zope.com
Thu, 3 Jul 2003 17:07:49 -0400


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

Modified Files:
      Tag: zodb33-devel-branch
	cPersistence.c cPersistence.h 
Log Message:
Simply Per_setattro() for now and add comment about future work.
Remove two slots from the CAPI that don't make much sense any more.


=== ZODB3/Persistence/cPersistence.c 1.72.8.10 => 1.72.8.11 ===
--- ZODB3/Persistence/cPersistence.c:1.72.8.10	Thu Jul  3 15:21:08 2003
+++ ZODB3/Persistence/cPersistence.c	Thu Jul  3 17:07:44 2003
@@ -73,27 +73,6 @@
   return self;
 }
 
-static PyObject *
-callmethod1(PyObject *self, PyObject *name, PyObject *arg)
-{
-    PyObject *args = NULL, *result = NULL, *meth = NULL;
-
-    meth = PyObject_GetAttr(self, name);
-    if (!meth)
-	goto err;
-    args = PyTuple_New(1);
-    if (!args)
-	goto err;
-    PyTuple_SET_ITEM(args, 0, arg);
-    result = PyObject_CallObject(meth, args);
-    PyTuple_SET_ITEM(name, 0, NULL);
- err:
-    Py_XDECREF(meth);
-    Py_XDECREF(args);
-    return result;
-}
-
-
 static void ghostify(cPersistentObject*);
 
 /* Load the state of the object, unghostifying it.  Upon success, return 1.
@@ -121,7 +100,7 @@
 	*/
         self->state = cPersistent_CHANGED_STATE;
         /* Call the object's __setstate__() */
-        r = callmethod1(self->jar, py_setstate, (PyObject*)self);
+	r = PyObject_CallMethod(self->jar, "setstate", "O", (PyObject *)self);
         if (r == NULL) {
             ghostify(self);
             return 0;
@@ -502,95 +481,52 @@
     return r;
 }
 
-static int
-_setattro(cPersistentObject *self, PyObject *oname, PyObject *v)
-{
-    char *name;
-
-    if (oname == NULL)
-	return -1;
-    if (!PyString_Check(oname)) 
-	return -1;
-    name = PyString_AS_STRING(oname);
-    if (name == NULL)
-	return -1;
+/* We need to decide on a reasonable way for a programmer to write
+   an __setattr__() or __delattr__() hook.  
 
-    if (*name == '_' && name[1] == 'p' && name[2] == '_') {
-    }
-    else
-    {
-        if (!unghostify(self))
-            return -1;
-	
-	accessed(self);
-	
-	if ((! (*name=='_' && name[1]=='v' && name[2]=='_'))
-	    && (self->state != cPersistent_CHANGED_STATE && self->jar)
-	    && self->ob_type->tp_base->tp_setattro
-	    )
-	    if (changed(self) < 0) return -1;
-    }
-    
-    return PyObject_GenericSetAttr((PyObject *)self, oname, v);
-}
+   The ZODB3 has been that if you write a hook, it will be called if
+   the attribute is not an _p_ attribute and after doing any necessary
+   unghostifying.  AMK's guide says modification will not be tracked
+   automatically, so the hook must explicitly set _p_changed; I'm not
+   sure if I believe that.
+
+   This approach won't work with new-style classes, because type will
+   install a slot wrapper that calls the derived class's __setattr__().
+   That means Persistent's tp_setattro doesn't get a chance to be called.
+   Changing this behavior would require a metaclass.
+
+   One option for ZODB 3.3 is to require setattr hooks to know about
+   _p_ and to call a prep function before modifying the object's state.
+   That's the solution I like best at the moment.
+*/
 
 static int
-Per_setattro(cPersistentObject *self, PyObject *oname, PyObject *v)
+Per_setattro(cPersistentObject *self, PyObject *name, PyObject *v)
 {
-  int r;
-  PyObject *m;
+    int r;
+    char *s;
 
-  if (v)
-    {
-      r = _setattro(self, oname, v);
-      if (r < 1) return r;
+    name = convert_name(name);
+    if (!name)
+	return -1;
+    s = PyString_AS_STRING(name);
 
-      m=PyObject_GetAttr((PyObject *)self, py___setattr__);
-      if (m) 
-	{
-	  ASSIGN(m, PyObject_CallFunction(m, "OO", oname, v));
+    if (strncmp(s, "_p_", 3) != 0) {
+	if (!unghostify(self))
+	    return -1;
+	accessed(self);
+	if (strncmp(s, "_v_", 3) != 0 
+	    && self->state != cPersistent_CHANGED_STATE) {
+	    if (changed(self) < 0)
+		return -1;
 	}
-      else PyErr_SetObject(PyExc_AttributeError, oname);
     }
-  else if (!v)
-    {
-      r=_setattro(self,oname, v);
-      if (r < 1) return r;
+    r = PyObject_GenericSetAttr((PyObject *)self, name, v);
 
-      m=PyObject_GetAttr((PyObject *)self, py___delattr__);
-      if (m) 
-      {
-	ASSIGN(m, PyObject_CallFunction(m, "O", oname));
-      }
-      else PyErr_SetObject(PyExc_AttributeError, oname);
-    }
-  else
-      return _setattro(self, oname, v);
-
-  if (m) 
-    {
-      Py_DECREF(m);
-      return 0;
-    }
-  
-  return -1;
+    Py_DECREF(name);
+    return r;
 }
 
-/*
-
-static PyMethodDef Per_methods[] = {
-    {"__reduce__", (PyCFunction)persist_reduce, METH_NOARGS, },
-    {"__getstate__", (PyCFunction)persist_getstate, METH_NOARGS, },
-    {"__setstate__", persist_setstate, METH_O, },
-    {"_p_activate", (PyCFunction)persist_activate, METH_NOARGS, },
-    {"_p_deactivate", (PyCFunction)persist_deactivate, METH_KEYWORDS, },
-    {"_p_setattr", (PyCFunction)persist_p_setattr, METH_VARARGS, },
-    {"_p_delattr", (PyCFunction)persist_p_delattr, METH_O, },
-    {NULL}
-};
-
-*/
-
 static PyObject *
 Per_get_changed(cPersistentObject *self)
 {
@@ -834,8 +770,6 @@
     ghostify,
     deallocated,
     (intfunctionwithpythonarg)Per_setstate,
-    (pergetattr)Per_getattro,
-    (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. */


=== ZODB3/Persistence/cPersistence.h 1.25.122.1 => 1.25.122.2 ===
--- ZODB3/Persistence/cPersistence.h:1.25.122.1	Tue Jul  1 15:28:11 2003
+++ ZODB3/Persistence/cPersistence.h	Thu Jul  3 17:07:44 2003
@@ -65,8 +65,6 @@
     void (*ghostify)(cPersistentObject*);
     void (*deallocated)(cPersistentObject*);
     int (*setstate)(PyObject*);
-    pergetattr pergetattro;
-    persetattr persetattro;
     percachedelfunc percachedel;
 } cPersistenceCAPIstruct;