[Zope3-checkins] CVS: Zope3/src/zope/context - wrapper.c:1.19
Steve Alexander
steve@cat-box.net
Thu, 29 May 2003 05:07:06 -0400
Update of /cvs-repository/Zope3/src/zope/context
In directory cvs.zope.org:/tmp/cvs-serv30464/src/zope/context
Modified Files:
wrapper.c
Log Message:
Wrappers now allow subclasses to supply new methods and other descriptors,
and to override existing slots and methods.
=== Zope3/src/zope/context/wrapper.c 1.18 => 1.19 ===
--- Zope3/src/zope/context/wrapper.c:1.18 Wed May 28 09:16:09 2003
+++ Zope3/src/zope/context/wrapper.c Thu May 29 05:06:35 2003
@@ -1,3 +1,4 @@
+#include <stdio.h>
#include <Python.h>
#include "structmember.h"
#include "modsupport.h"
@@ -15,7 +16,6 @@
#define Wrapper_GetDict(wrapper) \
(((WrapperObject *)wrapper)->wrap_dict)
-
static PyTypeObject WrapperType;
static PyTypeObject ContextAwareType;
@@ -525,7 +525,7 @@
PyObject *proxyargs = create_proxy_args(args, object);
if (proxyargs == NULL)
goto finally;
- result = ProxyType->tp_new(type, proxyargs, NULL);
+ result = ProxyType.tp_new(type, proxyargs, NULL);
Py_DECREF(proxyargs);
}
finally:
@@ -546,7 +546,7 @@
proxyargs = create_proxy_args(args, object);
if (proxyargs == NULL)
goto finally;
- if (ProxyType->tp_init(self, proxyargs, NULL) < 0)
+ if (ProxyType.tp_init(self, proxyargs, NULL) < 0)
goto finally;
if (wrapper->wrap_context != context) {
/* XXX This might be a little weird: if a subclass initializes
@@ -637,6 +637,52 @@
* However, Guido says that it is ok to use _PyType_Lookup, and that the
* function isn't going to go away.
*/
+
+
+/* A variant of _PyType_Lookup that doesn't look in WrapperType or ProxyType.
+ *
+ * The argument is_reduce is 1 iff name is "__reduce__".
+ * If is_reduce is 1, we may look in WrapperType.
+ */
+PyObject *
+WrapperType_Lookup(PyTypeObject *type, PyObject *name, int is_reduce)
+{
+ 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);
+
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(mro, i);
+
+ if (((PyTypeObject *)base) != &ProxyType &&
+ (((PyTypeObject *)base) != &WrapperType || is_reduce)) {
+ 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)
{
@@ -644,6 +690,7 @@
PyObject *descriptor;
PyObject *wrapped_type;
PyObject *res = NULL;
+ char *name_as_string;
#ifdef Py_USING_UNICODE
/* The Unicode to string conversion is done here because the
@@ -663,32 +710,49 @@
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'",
- PyString_AS_STRING(name));
+ name_as_string);
goto finally;
}
- descriptor = _PyType_Lookup(wrapped->ob_type, name);
- if (descriptor != NULL &&
- PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS) &&
- descriptor->ob_type->tp_descr_get != NULL &&
- (PyObject_TypeCheck(descriptor, &ContextDescriptorType) ||
- /* If object is context-aware, still don't rebind __class__.
- */
- (PyObject_TypeCheck(wrapped, &ContextAwareType)
- && ! (PyString_Check(name)
- && strcmp(PyString_AS_STRING(name), "__class__") == 0))
- )) {
- wrapped_type = (PyObject *)wrapped->ob_type;
- if (wrapped_type == NULL)
+ if (strcmp(name_as_string, "__class__") != 0) {
+
+ descriptor = WrapperType_Lookup(
+ self->ob_type, name,
+ strcmp(name_as_string, "__reduce__") == 0);
+ 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 = descriptor->ob_type->tp_descr_get(
- descriptor,
- self,
- wrapped_type);
- goto finally;
+ }
+
+ descriptor = _PyType_Lookup(wrapped->ob_type, name);
+ if (descriptor != NULL &&
+ PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS) &&
+ descriptor->ob_type->tp_descr_get != NULL &&
+ (PyObject_TypeCheck(descriptor, &ContextDescriptorType) ||
+ PyObject_TypeCheck(wrapped, &ContextAwareType)
+ )) {
+ wrapped_type = (PyObject *)wrapped->ob_type;
+ if (wrapped_type == NULL)
+ goto finally;
+ res = descriptor->ob_type->tp_descr_get(
+ descriptor,
+ self,
+ wrapped_type);
+ goto finally;
+ }
}
res = PyObject_GetAttr(wrapped, name);
finally:
@@ -721,6 +785,19 @@
else
Py_INCREF(name);
+ descriptor = WrapperType_Lookup(self->ob_type, name, 0);
+ 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,
@@ -837,6 +914,31 @@
);
return -1;
}
+ descriptor = WrapperType_Lookup(self->ob_type, SlotStrings[LEN_IDX], 0);
+ if (descriptor != NULL) {
+ /* There's a __len__ defined in a wrapper subclass, so we need
+ * to call that.
+ */
+ if (PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS)
+ && descriptor->ob_type->tp_descr_get != NULL) {
+ descriptor = descriptor->ob_type->tp_descr_get(
+ descriptor,
+ self,
+ (PyObject *)self->ob_type);
+ if (descriptor == NULL)
+ return -1;
+ res = PyObject_CallFunctionObjArgs(descriptor, NULL);
+ Py_DECREF(descriptor);
+ } else {
+ res = PyObject_CallFunctionObjArgs(descriptor, self, NULL);
+ }
+ if (res == NULL)
+ return -1;
+ result = PyObject_IsTrue(res);
+ Py_DECREF(res);
+ return result;
+ }
+
descriptor = _PyType_Lookup(wrapped->ob_type, SlotStrings[NONZERO_IDX]);
if (descriptor == NULL)
descriptor = _PyType_Lookup(wrapped->ob_type, SlotStrings[LEN_IDX]);
@@ -1584,7 +1686,7 @@
SlotStrings[CALL_IDX] = PyString_InternFromString("__call__");
SlotStrings[STR_IDX] = PyString_InternFromString("__str__");
- WrapperType.tp_base = ProxyType;
+ WrapperType.tp_base = &ProxyType;
WrapperType.tp_alloc = PyType_GenericAlloc;
WrapperType.tp_free = _PyObject_GC_Del;
if (PyType_Ready(&WrapperType) < 0)