[Zope-Checkins] CVS: Zope3/lib/python/Zope/ContextWrapper - proxy.c:1.1.4.2 wrapper.c:1.12.2.15

Fred L. Drake, Jr. fdrake@acm.org
Thu, 6 Jun 2002 11:40:49 -0400


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

Modified Files:
      Tag: Zope-3x-branch
	proxy.c wrapper.c 
Log Message:
Implement __new__ methods for the proxy base class and the context wrapper
that allow the expected invariants to be maintained.

These types have the requirement that the slot for the proxied object must
be non-NULL until the dealloc handler is called.  This was not always the
case if GC was invoked between the call to __new__ and __init__, which could
be provoked by setting the GC threshold to a very small number (like 1).


=== Zope3/lib/python/Zope/ContextWrapper/proxy.c 1.1.4.1 => 1.1.4.2 ===
  */
 
+static PyObject *
+wrap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result = NULL;
+    PyObject *object;
+
+    if (PyArg_UnpackTuple(args, "__new__", 1, 1, &object)) {
+        result = PyType_GenericNew(type, args, kwds);
+        if (result != NULL) {
+            ProxyObject *wrapper = (ProxyObject *) result;
+            Py_INCREF(object);
+            wrapper->proxy_object = object;
+        }
+    }
+    return result;
+}
+
 static int
 wrap_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
@@ -24,13 +41,17 @@
 
     if (PyArg_UnpackTuple(args, "__init__", 1, 1, &object)) {
         ProxyObject *wrapper = (ProxyObject *)self;
-        if (PyType_Type.tp_init(self, empty_tuple, NULL) < 0)
-            goto finally;
-        Py_INCREF(object);
-        wrapper->proxy_object = object;
+        /* If the object in this proxy is not the one we
+         * received in args, replace it with the new one.
+         */
+        if (wrapper->proxy_object != object) {
+            PyObject *temp = wrapper->proxy_object;
+            Py_INCREF(object);
+            wrapper->proxy_object = object;
+            Py_DECREF(temp);
+        }
         result = 0;
     }
- finally:
     return result;
 }
 
@@ -603,7 +624,7 @@
     0,					/* tp_dictoffset */
     wrap_init,				/* tp_init */
     PyType_GenericAlloc,		/* tp_alloc */
-    PyType_GenericNew,			/* tp_new */
+    wrap_new,				/* tp_new */
     _PyObject_GC_Del,			/* tp_free */
 };
 


=== Zope3/lib/python/Zope/ContextWrapper/wrapper.c 1.12.2.14 => 1.12.2.15 ===
 empty_tuple = NULL;
 
+/* Helper for wrap_new/wrap_init; return the base class args tuple
+ * from the incoming args tuple.  Returns a new reference.
+ */
+static PyObject *
+create_proxy_args(PyObject *args, PyObject *object)
+{
+    if (PyTuple_GET_SIZE(args) == 1)
+        Py_INCREF(args);
+    else {
+        args = PyTuple_New(1);
+        if (args != NULL) {
+            Py_INCREF(object);
+            PyTuple_SET_ITEM(args, 0, object);
+        }
+    }
+    return args;
+}
 
 /*
  *   Slot methods.
  */
 
+static PyObject *
+wrap_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    PyObject *result = NULL;
+    PyObject *context;
+    PyObject *object;
+
+    if (PyArg_UnpackTuple(args, "__new__", 1, 2, &object, &context)) {
+        PyObject *proxyargs = create_proxy_args(args, object);
+        if (proxyargs == NULL)
+            goto finally;
+        result = ProxyType->tp_new(type, proxyargs, NULL);
+        Py_DECREF(proxyargs);
+    }
+ finally:
+    return result;
+}
+
 static int
 wrap_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
@@ -34,25 +69,32 @@
     PyObject *object;
 
     if (PyArg_UnpackTuple(args, "__init__", 1, 2, &object, &context)) {
-        WrapperObject *wrapper = (WrapperObject *)self;
-	proxyargs = PyTuple_New(1);
+        PyObject *temp;
+	WrapperObject *wrapper = (WrapperObject *)self;
+        proxyargs = create_proxy_args(args, object);
         if (proxyargs == NULL)
-	    goto finally;
-	Py_INCREF(object);
-	PyTuple_SET_ITEM(proxyargs, 0, object);
+            goto finally;
         if (ProxyType->tp_init(self, proxyargs, NULL) < 0)
             goto finally;
-        Py_XINCREF(context);
-        wrapper->wrap_context = context;
+        if (wrapper->wrap_context != context) {
+            temp = wrapper->wrap_context;
+            Py_XINCREF(context);
+            wrapper->wrap_context = context;
+            Py_XDECREF(temp);
+        }
         if (kwds != NULL && PyDict_Size(kwds) > 0) {
-            wrapper->wrap_dict = PyDict_Copy(kwds);
             if (wrapper->wrap_dict == NULL) {
+                wrapper->wrap_dict = PyDict_Copy(kwds);
+                if (wrapper->wrap_dict == NULL) {
+                    Py_DECREF(wrapper);
+                    goto finally;
+                }
+            }
+            else if (PyDict_Merge(wrapper->wrap_dict, kwds, 1) < 0) {
                 Py_DECREF(wrapper);
-                return result;
+                goto finally;
             }
         }
-        else
-            wrapper->wrap_dict = NULL;
         result = 0;
     }
  finally:
@@ -180,7 +222,7 @@
     0,					/* tp_dictoffset */
     wrap_init,				/* tp_init */
     PyType_GenericAlloc,		/* tp_alloc */
-    PyType_GenericNew,			/* tp_new */
+    wrap_new,				/* tp_new */
     _PyObject_GC_Del,			/* tp_free */
 };