[Zope3-checkins] CVS: Zope3/src/zope/proxy - _zope_proxy_proxy.c:1.4

Jim Fulton jim at zope.com
Sun Sep 21 13:34:56 EDT 2003


Update of /cvs-repository/Zope3/src/zope/proxy
In directory cvs.zope.org:/tmp/cvs-serv16044/src/zope/proxy

Modified Files:
	_zope_proxy_proxy.c 
Log Message:
Added support for descriptors in proxy subclasses.


=== Zope3/src/zope/proxy/_zope_proxy_proxy.c 1.3 => 1.4 ===
--- Zope3/src/zope/proxy/_zope_proxy_proxy.c:1.3	Wed May 28 18:15:27 2003
+++ Zope3/src/zope/proxy/_zope_proxy_proxy.c	Sun Sep 21 13:34:26 2003
@@ -119,21 +119,163 @@
     self->ob_type->tp_free(self);
 }
 
+/* A variant of _PyType_Lookup that doesn't look in ProxyType.
+ *
+ * If argument search_wrappertype is nonzero, we can look in WrapperType.
+ */
+PyObject *
+WrapperType_Lookup(PyTypeObject *type, PyObject *name)
+{
+    int i, n;
+    PyObject *mro, *res, *base, *dict;
+
+    /* Look in tp_dict of types in MRO */
+    mro = type->tp_mro;
+
+    /* If mro is NULL, the type is either not yet initialized
+       by PyType_Ready(), or already cleared by type_clear().
+       Either way the safest thing to do is to return NULL. */
+    if (mro == NULL)
+        return NULL;
+
+    assert(PyTuple_Check(mro));
+
+    n = PyTuple_GET_SIZE(mro) 
+      - 1; /* We don't want to look at the last item, which is object. */
+
+    for (i = 0; i < n; i++) {
+        base = PyTuple_GET_ITEM(mro, i);
+
+        if (((PyTypeObject *)base) != &ProxyType) {
+            if (PyClass_Check(base))
+                dict = ((PyClassObject *)base)->cl_dict;
+            else {
+                assert(PyType_Check(base));
+                dict = ((PyTypeObject *)base)->tp_dict;
+            }
+            assert(dict && PyDict_Check(dict));
+            res = PyDict_GetItem(dict, name);
+            if (res != NULL)
+                return res;
+        }
+    }
+    return NULL;
+}
+
+
 static PyObject *
 wrap_getattro(PyObject *self, PyObject *name)
 {
-  return PyObject_GetAttr(Proxy_GET_OBJECT(self), name);
+    PyObject *wrapped;
+    PyObject *descriptor;
+    PyObject *res = NULL;
+    char *name_as_string;
+    int maybe_special_name;
+
+#ifdef Py_USING_UNICODE
+    /* The Unicode to string conversion is done here because the
+       existing tp_getattro slots expect a string object as name
+       and we wouldn't want to break those. */
+    if (PyUnicode_Check(name)) {
+        name = PyUnicode_AsEncodedString(name, NULL, NULL);
+        if (name == NULL)
+            return NULL;
+    }
+    else
+#endif
+    if (!PyString_Check(name)){
+        PyErr_SetString(PyExc_TypeError, "attribute name must be string");
+        return NULL;
+    }
+    else
+        Py_INCREF(name);
+
+    name_as_string = PyString_AS_STRING(name);
+    wrapped = Proxy_GET_OBJECT(self);
+    if (wrapped == NULL) {
+        PyErr_Format(PyExc_RuntimeError,
+            "object is NULL; requested to get attribute '%s'",
+            name_as_string);
+        goto finally;
+    }
+
+    maybe_special_name = name_as_string[0] == '_' && name_as_string[1] == '_';
+
+    if (!(maybe_special_name && strcmp(name_as_string, "__class__") == 0)) {
+
+        descriptor = WrapperType_Lookup(self->ob_type, name);
+
+        if (descriptor != NULL) {
+            if (PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS)
+                && descriptor->ob_type->tp_descr_get != NULL) {
+                res = descriptor->ob_type->tp_descr_get(
+                        descriptor,
+                        self,
+                        (PyObject *)self->ob_type);
+            } else {
+                Py_INCREF(descriptor);
+                res = descriptor;
+            }
+            goto finally;
+        }
+    }
+    res = PyObject_GetAttr(wrapped, name);
+
+finally:
+    Py_DECREF(name);
+    return res;
 }
 
 static int
 wrap_setattro(PyObject *self, PyObject *name, PyObject *value)
 {
-    if (Proxy_GET_OBJECT(self) != NULL)
-        return PyObject_SetAttr(Proxy_GET_OBJECT(self), name, value);
-    PyErr_Format(PyExc_RuntimeError,
-                 "object is NULL; requested to set attribute '%s'",
-                 PyString_AS_STRING(name));
-    return -1;
+    PyObject *wrapped;
+    PyObject *descriptor;
+    int res = -1;
+
+#ifdef Py_USING_UNICODE
+    /* The Unicode to string conversion is done here because the
+       existing tp_setattro slots expect a string object as name
+       and we wouldn't want to break those. */
+    if (PyUnicode_Check(name)) {
+        name = PyUnicode_AsEncodedString(name, NULL, NULL);
+        if (name == NULL)
+            return -1;
+    }
+    else
+#endif
+    if (!PyString_Check(name)){
+        PyErr_SetString(PyExc_TypeError, "attribute name must be string");
+        return -1;
+    }
+    else
+        Py_INCREF(name);
+
+    descriptor = WrapperType_Lookup(self->ob_type, name);
+    if (descriptor != NULL) {
+        if (PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS) &&
+            descriptor->ob_type->tp_descr_set != NULL) {
+            res = descriptor->ob_type->tp_descr_set(descriptor, self, value);
+        } else {
+            PyErr_Format(PyExc_TypeError,
+                "Tried to set attribute '%s' on wrapper, but it is not"
+                " a data descriptor", PyString_AS_STRING(name));
+        }
+        goto finally;
+    }
+
+    wrapped = Proxy_GET_OBJECT(self);
+    if (wrapped == NULL) {
+        PyErr_Format(PyExc_RuntimeError,
+            "object is NULL; requested to set attribute '%s'",
+            PyString_AS_STRING(name));
+        goto finally;
+    }
+    res = PyObject_SetAttr(wrapped, name, value);
+
+finally:
+    Py_DECREF(name);
+    return res;
 }
 
 static int




More information about the Zope3-Checkins mailing list