[Zope-Checkins] CVS: ZODB/src/persistent - cPersistence.c:1.75.2.7

Fred L. Drake, Jr. fred at zope.com
Wed Feb 18 18:11:33 EST 2004


Update of /cvs-repository/ZODB/src/persistent
In directory cvs.zope.org:/tmp/cvs-serv14396

Modified Files:
      Tag: zope3-zodb3-devel-branch
	cPersistence.c 
Log Message:
- fold in the not-actually-shared pickle support code
- remove __getnewargs__(), since we want to allow ghost creation to
  avoid the extra database lookup when possible


=== ZODB/src/persistent/cPersistence.c 1.75.2.6 => 1.75.2.7 ===
--- ZODB/src/persistent/cPersistence.c:1.75.2.6	Fri Feb 13 23:02:38 2004
+++ ZODB/src/persistent/cPersistence.c	Wed Feb 18 18:11:32 2004
@@ -233,8 +233,333 @@
 
 
 
-#include "pickle/pickle.c"
+/* It's a dang shame we can't inherit __get/setstate__ from object :( */
 
+static PyObject *str__slotnames__, *copy_reg_slotnames, *__newobj__;
+static PyObject *str__getnewargs__, *str__getstate__;
+
+static int
+pickle_setup(void)
+{
+  PyObject *copy_reg;
+  int r = -1;
+
+#define DEFINE_STRING(S) \
+  if(! (str ## S = PyString_FromString(# S))) return -1
+  DEFINE_STRING(__slotnames__);
+  DEFINE_STRING(__getnewargs__);
+  DEFINE_STRING(__getstate__);
+#undef DEFINE_STRING
+
+  copy_reg = PyImport_ImportModule("copy_reg");
+  if (copy_reg == NULL)
+    return -1;
+
+  copy_reg_slotnames = PyObject_GetAttrString(copy_reg, "_slotnames");
+  if (copy_reg_slotnames == NULL)
+    goto end;
+
+  __newobj__ = PyObject_GetAttrString(copy_reg, "__newobj__");
+  if (__newobj__ == NULL)
+    goto end;
+
+  r = 0;
+ end:
+  Py_DECREF(copy_reg);
+  return r;
+}
+
+static PyObject *
+pickle_slotnames(PyTypeObject *cls)
+{
+  PyObject *slotnames;
+
+  slotnames = PyDict_GetItem(cls->tp_dict, str__slotnames__);
+  if (slotnames != NULL) 
+    {
+      Py_INCREF(slotnames);
+      return slotnames;
+    }
+
+  slotnames = PyObject_CallFunctionObjArgs(copy_reg_slotnames, (PyObject*)cls, 
+                                           NULL);
+  if (slotnames != NULL &&
+      slotnames != Py_None &&
+      ! PyList_Check(slotnames))
+    {
+      PyErr_SetString(PyExc_TypeError,
+                      "copy_reg._slotnames didn't return a list or None");
+      Py_DECREF(slotnames);
+      slotnames = NULL;
+    }
+  
+  return slotnames;
+}
+
+static PyObject *
+pickle_copy_dict(PyObject *state)
+{
+  PyObject *copy, *key, *value;
+  char *ckey;
+  int pos = 0;
+
+  copy = PyDict_New();
+  if (copy == NULL)
+    return NULL;
+
+  if (state == NULL)
+    return copy;
+
+  while (PyDict_Next(state, &pos, &key, &value))
+    {
+      if (key && PyString_Check(key))
+        {
+          ckey = PyString_AS_STRING(key);
+          if (*ckey == '_' &&
+              (ckey[1] == 'v' || ckey[1] == 'p') &&
+              ckey[2] == '_')
+            /* skip volatile and persistent */
+            continue;
+        }
+
+      if (PyObject_SetItem(copy, key, value) < 0)
+        goto err;
+    }
+  
+  return copy;
+ err:
+  Py_DECREF(copy);
+  return NULL;
+}
+
+
+static char pickle___getstate__doc[] =
+"Get the object serialization state\n"
+"\n"
+"If the object has no assigned slots and has no instance dictionary, then \n"
+"None is returned.\n"
+"\n"
+"If the object has no assigned slots and has an instance dictionary, then \n"
+"the a copy of the instance dictionary is returned. The copy has any items \n"
+"with names starting with '_v_' or '_p_' ommitted.\n"
+"\n"
+"If the object has assigned slots, then a two-element tuple is returned.  \n"
+"The first element is either None or a copy of the instance dictionary, \n"
+"as described above. The second element is a dictionary with items \n"
+"for each of the assigned slots.\n"
+;
+
+static PyObject *
+pickle___getstate__(PyObject *self)
+{
+  PyObject *slotnames=NULL, *slots=NULL, *state=NULL;
+  PyObject **dictp;
+  int n=0;
+
+  slotnames = pickle_slotnames(self->ob_type);
+  if (slotnames == NULL)
+    return NULL;
+
+  dictp = _PyObject_GetDictPtr(self);
+  if (dictp)
+    state = pickle_copy_dict(*dictp);
+  else 
+    {
+      state = Py_None;
+      Py_INCREF(state);
+    }
+
+  if (slotnames != Py_None)
+    {
+      int i;
+
+      slots = PyDict_New();
+      if (slots == NULL)
+        goto end;
+
+      for (i = 0; i < PyList_GET_SIZE(slotnames); i++) 
+        {
+          PyObject *name, *value;
+          char *cname;
+
+          name = PyList_GET_ITEM(slotnames, i);
+          if (PyString_Check(name))
+            {
+              cname = PyString_AS_STRING(name);
+              if (*cname == '_' &&
+                  (cname[1] == 'v' || cname[1] == 'p') &&
+                  cname[2] == '_')
+                /* skip volatile and persistent */
+                continue;
+            }
+
+	  /* XXX will this go through our getattr hook? */
+          value = PyObject_GetAttr(self, name);
+          if (value == NULL)
+            PyErr_Clear();
+          else 
+            {
+              int err = PyDict_SetItem(slots, name, value);
+              Py_DECREF(value);
+              if (err < 0)
+                goto end;
+              n++;
+            }
+        }
+    }
+
+  if (n) 
+    state = Py_BuildValue("(NO)", state, slots);
+
+ end:
+  Py_XDECREF(slotnames);
+  Py_XDECREF(slots);
+  
+  return state;
+}
+
+static int
+pickle_setattrs_from_dict(PyObject *self, PyObject *dict)
+{
+  PyObject *key, *value;
+  int pos = 0;
+  
+  if (! PyDict_Check(dict))
+    {
+      PyErr_SetString(PyExc_TypeError, "Expected dictionary");
+      return -1;
+    }
+  
+  while (PyDict_Next(dict, &pos, &key, &value)) 
+    {
+      if (PyObject_SetAttr(self, key, value) < 0)
+        return -1;
+    }
+  return 0;
+}
+
+static char pickle___setstate__doc[] =
+"Set the object serialization state\n"
+"\n"
+"The state should be in one of 3 forms:\n"
+"\n"
+"- None\n"
+"\n"
+"  Ignored\n"
+"\n"
+"- A dictionary\n"
+"\n"
+"  In this case, the object's instance dictionary will be cleared and \n"
+"  updated with the new state.\n"
+"\n"
+"- A two-tuple with a string as the first element.  \n"
+"\n"
+"  In this case, the method named by the string in the first element will be\n"
+"  called with the second element.\n"
+"\n"
+"  This form supports migration of data formats.\n"
+"\n"
+"- A two-tuple with None or a Dictionary as the first element and\n"
+"  with a dictionary as the second element.\n"
+"\n"
+"  If the first element is not None, then the object's instance dictionary \n"
+"  will be cleared and updated with the value.\n"
+"\n"
+"  The items in the second element will be assigned as attributes.\n"
+;
+
+static PyObject *
+pickle___setstate__(PyObject *self, PyObject *state)
+{
+  PyObject *slots=NULL;
+
+  if (PyTuple_Check(state))
+    {
+      if (! PyArg_ParseTuple(state, "OO", &state, &slots))
+        return NULL;
+    }
+
+  if (state != Py_None)
+    {
+      PyObject **dict;
+
+      dict = _PyObject_GetDictPtr(self);
+      if (dict)
+        {
+          if (*dict == NULL)
+            {
+              *dict = PyDict_New();
+              if (*dict == NULL)
+                return NULL;
+            }
+        }
+
+      if (*dict != NULL)
+        {
+          PyDict_Clear(*dict);
+          if (PyDict_Update(*dict, state) < 0)
+            return NULL;
+        }
+      else if (pickle_setattrs_from_dict(self, state) < 0)
+        return NULL;
+    }
+
+  if (slots != NULL && pickle_setattrs_from_dict(self, slots) < 0)
+    return NULL;
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static char pickle___reduce__doc[] = 
+"Reduce an object to contituent parts for serialization\n"
+;
+
+static PyObject *
+pickle___reduce__(PyObject *self)
+{
+  PyObject *args=NULL, *bargs=NULL, *state=NULL, *getnewargs=NULL;
+  int l, i;
+
+  getnewargs = PyObject_GetAttr(self, str__getnewargs__);
+  if (getnewargs != NULL) {
+      bargs = PyObject_CallFunctionObjArgs(getnewargs, NULL);
+      Py_DECREF(getnewargs);
+      if (bargs == NULL)
+          return NULL;
+      l = PyTuple_Size(bargs);
+      if (l < 0)
+          goto end;
+  }
+  else {
+      PyErr_Clear();
+      l = 0;
+  }
+  
+  args = PyTuple_New(l+1);
+  if (args == NULL)
+    goto end;
+  
+  Py_INCREF(self->ob_type);
+  PyTuple_SET_ITEM(args, 0, (PyObject*)(self->ob_type));
+  for (i = 0; i < l; i++)
+    {
+      Py_INCREF(PyTuple_GET_ITEM(bargs, i));
+      PyTuple_SET_ITEM(args, i+1, PyTuple_GET_ITEM(bargs, i));
+    }
+  
+  state = PyObject_CallMethodObjArgs(self, str__getstate__, NULL);
+  if (state == NULL)
+    goto end;
+
+  state = Py_BuildValue("(OON)", __newobj__, args, state);
+
+ end:
+  Py_XDECREF(bargs);
+  Py_XDECREF(args);
+
+  return state;
+}
 
 
 
@@ -752,10 +1077,10 @@
   },
   {"__getstate__", (PyCFunction)Per__getstate__, METH_NOARGS,
    pickle___getstate__doc },
-
-  PICKLE_SETSTATE_DEF
-  PICKLE_GETNEWARGS_DEF
-  PICKLE_REDUCE_DEF
+  {"__setstate__", (PyCFunction)pickle___setstate__, METH_O,
+   pickle___setstate__doc},                                          
+  {"__reduce__", (PyCFunction)pickle___reduce__, METH_NOARGS,
+   pickle___reduce__doc},
 
   {NULL,		NULL}		/* sentinel */
 };




More information about the Zope-Checkins mailing list