[Zope-Checkins] CVS: ZODB3/Persistence - cPersistence.c:1.72.8.15

Jeremy Hylton jeremy@zope.com
Mon, 7 Jul 2003 12:15:57 -0400


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

Modified Files:
      Tag: zodb33-devel-branch
	cPersistence.c 
Log Message:
Add __reduce__() and remove __changed__().

Change METH_VARARGS to METH_O and METH_NOARGS as appropriate, removing
checknoargs() in the process.

Add test that persistent objects are picklable using plain old pickle.


=== ZODB3/Persistence/cPersistence.c 1.72.8.14 => 1.72.8.15 ===
--- ZODB3/Persistence/cPersistence.c:1.72.8.14	Thu Jul  3 18:45:10 2003
+++ ZODB3/Persistence/cPersistence.c	Mon Jul  7 12:15:22 2003
@@ -27,41 +27,33 @@
 #define UNLESS(E) if(!(E))
 #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
 
+/* Strings initialized by init_strings() below. */
 static PyObject *py_keys, *py_setstate, *py___dict__, *py_timeTime;
 static PyObject *py__p_changed, *py__p_deactivate;
 static PyObject *py___getattr__, *py___setattr__, *py___delattr__;
+static PyObject *py___getstate__;
 
-static PyObject *TimeStamp;
+/* These two objects are initialized when the module is loaded */
+static PyObject *TimeStamp, *py_simple_new;
 
 static int
 init_strings(void)
 {
-#define INIT_STRING(S) if (! (py_ ## S = PyString_FromString(#S))) return -1;
-  INIT_STRING(keys);
-  INIT_STRING(setstate);
-  INIT_STRING(timeTime);
-  INIT_STRING(__dict__);
-  INIT_STRING(_p_changed);
-  INIT_STRING(_p_deactivate);
-  INIT_STRING(__getattr__);
-  INIT_STRING(__setattr__);
-  INIT_STRING(__delattr__);
+#define INIT_STRING(S) \
+    if (!(py_ ## S = PyString_InternFromString(#S))) \
+	return -1;
+    INIT_STRING(keys);
+    INIT_STRING(setstate);
+    INIT_STRING(timeTime);
+    INIT_STRING(__dict__);
+    INIT_STRING(_p_changed);
+    INIT_STRING(_p_deactivate);
+    INIT_STRING(__getattr__);
+    INIT_STRING(__setattr__);
+    INIT_STRING(__delattr__);
+    INIT_STRING(__getstate__);
 #undef INIT_STRING
-  return 0;
-}
-
-static int
-checknoargs(PyObject *args)
-{
-  if (!PyTuple_Check(args))
-    return 0;
-  if (PyTuple_GET_SIZE(args) != 0) {
-    PyErr_Format(PyExc_TypeError, 
-		 "function takes exactly 0 arguments (%d given)",
-		 PyTuple_GET_SIZE(args));
     return 0;
-  }
-  return 1;
 }
 
 static PyObject *
@@ -227,32 +219,8 @@
 }
 
 static PyObject *
-Per___changed__(cPersistentObject *self, PyObject *args)
+Per__p_deactivate(cPersistentObject *self)
 {
-    PyObject *v = NULL;
-
-    if (args && !PyArg_ParseTuple(args, "|O:__changed__", &v)) 
-	return NULL;
-    if (!v) 
-	return PyObject_GetAttr((PyObject *)self, py__p_changed);
-
-    if (PyObject_IsTrue(v)) {
-	if (changed(self) < 0) 
-	    return NULL;
-    }
-    else if (self->state >= 0) 
-	self->state = cPersistent_UPTODATE_STATE;
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-static PyObject *
-Per__p_deactivate(cPersistentObject *self, PyObject *args)
-{
-    if (args && !checknoargs(args))
-	return NULL;
-
     if (self->state == cPersistent_UPTODATE_STATE && self->jar) {
 	PyObject **dictptr = _PyObject_GetDictPtr((PyObject *)self);
 	if (dictptr && *dictptr) {
@@ -333,15 +301,14 @@
 }  
 
 static PyObject *
-Per__setstate__(cPersistentObject *self, PyObject *args)
+Per__setstate__(cPersistentObject *self, PyObject *v)
 {
     PyObject **dictptr;
-    PyObject *__dict__, *v, *keys=0, *key=0, *e=0;
+    PyObject *__dict__, *keys=0, *key=0, *e=0;
     int l, i;
 
     dictptr = _PyObject_GetDictPtr((PyObject *)self);
     if (dictptr) {
-	UNLESS(PyArg_ParseTuple(args, "O", &v)) return NULL;
 	if (v != Py_None) {
 	    if (!*dictptr) {
 		*dictptr = PyDict_New();
@@ -380,17 +347,55 @@
     Py_XDECREF(e);
     Py_XDECREF(keys);
     return NULL;
-}  
+}
+
+static PyObject *
+Per__reduce__(cPersistentObject *self)
+{
+    PyObject *state, *args=NULL, *result, *__getstate__;
+  
+    __getstate__ = PyObject_GetAttr((PyObject*)self, py___getstate__);
+    if (!__getstate__)
+	return NULL;
+
+    state = PyObject_CallObject(__getstate__, NULL);
+    Py_DECREF(__getstate__);
+    if (!state)
+	return NULL;
+  
+    args = PyTuple_New(1);
+    if (!args)
+	goto err;
+  
+    Py_INCREF(self->ob_type);
+    PyTuple_SET_ITEM(args, 0, (PyObject *)self->ob_type);
+  
+    result = PyTuple_New(3);
+    if (!result)
+	goto err;
+  
+    Py_INCREF(py_simple_new);
+    PyTuple_SET_ITEM(result, 0, py_simple_new);
+    PyTuple_SET_ITEM(result, 1, args);
+    PyTuple_SET_ITEM(result, 2, state);
+  
+    return result;      
+  
+ err:
+    Py_DECREF(state);
+    Py_XDECREF(args);
+    return NULL;
+}
 
 
 static struct PyMethodDef Per_methods[] = {
-  {"__changed__",	(PyCFunction)Per___changed__,	METH_VARARGS,
-   "DEPRECATED: use self._p_changed=1"},
-  {"_p_deactivate",	(PyCFunction)Per__p_deactivate,	METH_VARARGS,
-   "_p_deactivate(oid) -- Deactivate the object"},
-  {"__getstate__",	(PyCFunction)Per__getstate__,	METH_NOARGS,
+  {"_p_deactivate", (PyCFunction)Per__p_deactivate, METH_NOARGS,
+   "_p_deactivate() -- Deactivate the object"},
+  {"__reduce__", (PyCFunction)Per__reduce__, METH_NOARGS,
+   "__reduce__ -- Support for traditional pickling of persistent objects"},
+  {"__getstate__", (PyCFunction)Per__getstate__, METH_NOARGS,
    "__getstate__() -- Return the state of the object" },
-  {"__setstate__",	(PyCFunction)Per__setstate__,	METH_VARARGS,
+  {"__setstate__", (PyCFunction)Per__setstate__, METH_O,
    "__setstate__(v) -- Restore the saved state of the object from v" },
   
   {NULL,		NULL}		/* sentinel */
@@ -406,7 +411,10 @@
 static int
 Per_clear(cPersistentObject *self)
 {
-    deallocated(self);
+    /* XXX Will subtype_clear() handle the instance dict? */
+    Py_XDECREF(self->jar);
+    Py_XDECREF(self->oid);
+    Py_XDECREF(self->cache);
     self->jar = NULL;
     self->oid = NULL;
     self->cache = NULL;
@@ -810,6 +818,20 @@
     return 0;
 }
 
+static PyObject *
+simple_new(PyObject *self, PyObject *type_object)
+{
+    return PyType_GenericNew((PyTypeObject *)type_object, NULL, NULL);
+}
+
+static PyMethodDef cPersistence_methods[] = {
+    {"simple_new", simple_new, METH_O,
+     "Create an object by simply calling a class's __new__ method without "
+     "arguments."},
+    {NULL, NULL}
+};
+
+
 static cPersistenceCAPIstruct
 truecPersistenceCAPI = {
     &Pertype,    
@@ -833,9 +855,8 @@
     if (init_strings() < 0) 
       return;
     
-    m = Py_InitModule4("cPersistence", NULL, cPersistence_doc_string,
-		     (PyObject*)NULL, PYTHON_API_VERSION);
-    
+    m = Py_InitModule3("cPersistence", cPersistence_methods, 
+		       cPersistence_doc_string);
 
     Pertype.ob_type = &PyType_Type;
     Pertype.tp_new = PyType_GenericNew;
@@ -851,7 +872,10 @@
     if (PyModule_AddObject(m, "CAPI", s) < 0)
 	return;
 
-    /* Initialize the global TimeStamp variable. */
+    py_simple_new = PyObject_GetAttrString(m, "simple_new");
+    if (!py_simple_new)
+        return;
+
     m = PyImport_ImportModule("Persistence.TimeStamp");
     if (!m)
 	return;