[Zodb-checkins] CVS: Zope/lib/python/persistent/pickle - pickle.c:1.2

Jim Fulton cvs-admin at zope.org
Fri Nov 28 11:45:28 EST 2003


Update of /cvs-repository/Zope/lib/python/persistent/pickle
In directory cvs.zope.org:/tmp/cvs-serv3783/lib/python/persistent/pickle

Added Files:
	pickle.c 
Log Message:
Merged Jeremy and Tim's changes from the zodb33-devel-branch.


=== Zope/lib/python/persistent/pickle/pickle.c 1.1 => 1.2 ===
--- /dev/null	Fri Nov 28 11:45:28 2003
+++ Zope/lib/python/persistent/pickle/pickle.c	Fri Nov 28 11:44:55 2003
@@ -0,0 +1,376 @@
+/*
+
+ Copyright (c) 2003 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.
+
+*/
+/* 
+
+ Reusable pickle support code
+
+ This is "includeware", meant to be used through a C include
+
+ */
+
+/* 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, nr;
+
+  copy = PyDict_New();
+  if (copy == NULL)
+    return NULL;
+
+  if (state == NULL)
+    return copy;
+
+  while ((nr = PyDict_Next(state, &pos, &key, &value))) 
+    {
+      if (nr < 0)
+        goto err;
+
+      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 (key != NULL && value != NULL &&
+          (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;
+            }
+
+          value = PyObject_GetAttr(self, name);
+          if (value == NULL)
+            PyErr_Clear();
+          else 
+            {
+              int err = PyDict_SetItem(slots, name, value);
+              Py_DECREF(value);
+              if (err)
+                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 (key != NULL && value != NULL &&
+          (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___getnewargs__doc[] = 
+"Get arguments to be passed to __new__\n"
+;
+
+static PyObject *
+pickle___getnewargs__(PyObject *self)
+{
+  return PyTuple_New(0);
+}
+
+static char pickle___reduce__doc[] = 
+"Reduce an object to contituent parts for serialization\n"
+;
+
+static PyObject *
+pickle___reduce__(PyObject *self)
+{
+  PyObject *args=NULL, *bargs=0, *state=NULL;
+  int l, i;
+  
+  bargs = PyObject_CallMethodObjArgs(self, str__getnewargs__, NULL);
+  if (bargs == NULL)
+    return NULL;
+
+  l = PyTuple_Size(bargs);
+  if (l < 0)
+    goto end;
+
+  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;
+}
+
+#define PICKLE_GETSTATE_DEF \
+{"__getstate__", (PyCFunction)pickle___getstate__, METH_NOARGS,      \
+   pickle___getstate__doc},
+
+#define PICKLE_SETSTATE_DEF \
+{"__setstate__", (PyCFunction)pickle___setstate__, METH_O,           \
+   pickle___setstate__doc},                                          
+
+#define PICKLE_GETNEWARGS_DEF \
+{"__getnewargs__", (PyCFunction)pickle___getnewargs__, METH_NOARGS,  \
+   pickle___getnewargs__doc},                                        
+
+#define PICKLE_REDUCE_DEF \
+{"__reduce__", (PyCFunction)pickle___reduce__, METH_NOARGS,          \
+   pickle___reduce__doc},
+
+#define PICKLE_METHODS PICKLE_GETSTATE_DEF PICKLE_SETSTATE_DEF \
+                       PICKLE_GETNEWARGS_DEF PICKLE_REDUCE_DEF




More information about the Zodb-checkins mailing list