[Zope-Checkins] CVS: Zope3/lib/python/Zope/ContextWrapper - wrapper.c:1.12.2.1

Fred Drake Jr fdrake@acm.org
Wed, 28 Nov 2001 15:12:06 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/ContextWrapper
In directory cvs.zope.org:/tmp/cvs-serv31004/ContextWrapper

Modified Files:
      Tag: Zope-3x-branch
	wrapper.c 
Log Message:
Add a __reduce__() method to Wrapper so that pickling is disabled by
default.  Picklable Wrapper subclasses need to replace __reduce__() to
support pickling.

Fudge attribute access for __class__ so that the type of the wrapped
object is returned.  This is a Jim requirement.


=== Zope3/lib/python/Zope/ContextWrapper/wrapper.c 1.12 => 1.12.2.1 ===
 
 
+/*
+ *   Slot methods.
+ */
+
 static int
 wrap_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
@@ -86,10 +90,17 @@
 wrap_getattro(PyObject *self, PyObject *name)
 {
     PyObject *result;
-    result = PyObject_GenericGetAttr(self, name);
-    if (result == NULL) {
-        PyErr_Clear();
-        result = PyObject_GetAttr(Wrapper_GetObject(self), name);
+    char *s = PyString_AS_STRING(name);
+    if (s[0] == '_' && strcmp(s, "__class__") == 0) {
+        result = (PyObject *)(Wrapper_GetObject(self)->ob_type);
+        Py_INCREF(result);
+    }
+    else {
+        result = PyObject_GenericGetAttr(self, name);
+        if (result == NULL) {
+            PyErr_Clear();
+            result = PyObject_GetAttr(Wrapper_GetObject(self), name);
+        }
     }
     return result;
 }
@@ -184,6 +195,39 @@
     return PyObject_SetItem(Wrapper_GetObject(self), key, value);
 }
 
+/*
+ *   Normal methods
+ */
+
+static char
+reduce__doc__[] =
+"__reduce__()\n"
+"Raise an exception; this prevents wrappers from being picklable by\n"
+"default, even if the underlying object is picklable.";
+
+static PyObject *
+wrap_reduce(PyObject *self)
+{
+    PyObject *pickle_error = NULL;
+    PyObject *pickle = PyImport_ImportModule("pickle");
+
+    if (pickle == NULL)
+        PyErr_Clear();
+    else {
+        pickle_error = PyObject_GetAttrString(pickle, "PicklingError");
+        if (pickle_error == NULL)
+            PyErr_Clear();
+    }
+    if (pickle_error == NULL) {
+        pickle_error = PyExc_RuntimeError;
+        Py_INCREF(pickle_error);
+    }
+    PyErr_SetString(pickle_error,
+                    "Wrapper instances cannot be pickled.");
+    Py_DECREF(pickle_error);
+    return NULL;
+}
+
 static PySequenceMethods
 wrap_as_sequence = {
     wrap_length,			/* sq_length */
@@ -203,6 +247,12 @@
     wrap_setitem,			/* mp_ass_subscript */
 };
 
+static PyMethodDef
+wrap_methods[] = {
+    {"__reduce__", (PyCFunction)wrap_reduce, METH_NOARGS, reduce__doc__},
+    {NULL, NULL},
+};
+
 /*
  * Note that the numeric methods are not supported.  This is primarily
  * because of the way coercion-less operations are performed with
@@ -243,7 +293,7 @@
     0,					/* tp_weaklistoffset */
     0,					/* tp_iter */
     0,					/* tp_iternext */
-    0,					/* tp_methods */
+    wrap_methods,			/* tp_methods */
     0,					/* tp_members */
     0,					/* tp_getset */
     0,					/* tp_base */