[Zope3-checkins] CVS: Zope3/src/zope/proxy/context - __init__.py:1.4 wrapper.c:1.3

Steve Alexander steve@cat-box.net
Tue, 8 Apr 2003 08:22:09 -0400


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

Modified Files:
	__init__.py wrapper.c 
Log Message:
Merge from branch.

ContextWrappers that rebind the 'self' of certain descriptors is now
implemented in C rather than in Python.
This checkin also fixes a couple of loss-of-context bugs when using
the __call__ method of views.

You'll need to rebuild your C extensions.
You *won't* need to toss your Data.fs ;-)



=== Zope3/src/zope/proxy/context/__init__.py 1.3 => 1.4 ===
--- Zope3/src/zope/proxy/context/__init__.py:1.3	Sat Jan 25 10:32:50 2003
+++ Zope3/src/zope/proxy/context/__init__.py	Tue Apr  8 08:21:38 2003
@@ -18,17 +18,18 @@
 Revision information:
 $Id$
 """
+__metaclass__ = type
 
 from zope.security.proxy import Proxy, getChecker, getObject
 from zope.proxy.context.wrapper import getobject, getdict
 from zope.proxy.context.wrapper import getcontext, getinnercontext
-from zope.proxy.context.wrapper import getinnerwrapper
-from zope.proxy.context.wrapper import Wrapper as _Wrapper, getbaseobject
+from zope.proxy.context.wrapper import getinnerwrapper, getbaseobject
+from zope.proxy.context.wrapper import ContextDescriptor, ContextAware
+from zope.proxy.context.wrapper import ContextMethod, ContextProperty
+from zope.proxy.context.wrapper import Wrapper
 from zope.security.checker import defineChecker, selectChecker, BasicTypes
-
-
-__metaclass__ = type
-
+from types import ClassType
+import inspect
 from zope.proxy.interfaces.context import IContextWrapper
 
 __implements__ = IContextWrapper
@@ -43,13 +44,26 @@
     if type(_ob) in BasicTypes:
         # Don't wrap basic objects
         return _ob
-    elif type(_ob) is Proxy:
+
+    if type(_ob.__class__) is ClassType:
+        # We have an instance of a classic class.
+        # This isn't *too* bad in itself, but we're going to make sure that
+        # it doesn't have any ContextDescriptor members.
+        cls = _ob.__class__
+        for name, member in inspect.getmembers(cls):
+            if isinstance(member, ContextDescriptor):
+                raise TypeError("Class %s is a classic class, but has a"
+                                " ContextDescriptor member '%s'. This member"
+                                " will not work properly." %
+                                (cls, name))
+
+    if type(_ob) is Proxy:
         # insert into proxies
         checker = getChecker(_ob)
         _ob = getObject(_ob)
-        _ob = Proxy(wrapperCreator(_ob, _parent, **kw), checker)
+        _ob = Proxy(Wrapper(_ob, _parent, **kw), checker)
     else:
-        _ob = wrapperCreator(_ob, _parent, **kw)
+        _ob = Wrapper(_ob, _parent, **kw)
 
     return _ob
 
@@ -104,7 +118,7 @@
 class ContainmentIterator:
 
     def __init__(self, obj):
-        self._ob = wrapperCreator(None, obj)
+        self._ob = Wrapper(None, obj)
 
     def __iter__(self):
         return self
@@ -136,128 +150,9 @@
     return ContextWrapper(getattr(collection, name, default),
                           collection, name=name)
 
+wrapperTypes = (Wrapper,)
 
-
-##############################################################################
-#
-# Approach
-#
-# The facilities here work by adding markers on methods or properties
-# that a custom wrapper class looks for.  We rely on the custom
-# wrapper class's __getattribute__ to rebind things on the way out.
-#
-# For further discission, see this wiki page (all on one line):
-# http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/...
-# zope.proxy.context.ContextMethod
-#
-##############################################################################
-
-
-# This method wrapper does not work for builtin methods.
-
-class ContextMethod:
-    def __new__(cls, method):
-        try:
-            method.__Zope_ContextWrapper_contextful_get__ = True
-        except AttributeError:
-            raise TypeError(
-                "Cannot make %s into a contextmethod" % type(method)
-                )
-        return method
-
-class ContextAware:
-    """Marker class indicating that all descriptors should be bound in context
-    """
-
-class ContextProperty(property):
-    """A property that provides a context wrapper to its getter and setter
-    methods"""
-    __Zope_ContextWrapper_contextful_get__ = True
-    __Zope_ContextWrapper_contextful_set__ = True
-
-class ContextGetProperty(property):
-    """A property that provides a context wrapper to its getter method"""
-    __Zope_ContextWrapper_contextful_get__ = True
-
-class ContextSetProperty(property):
-    """A property that provides a context wrapper to its setter method"""
-    __Zope_ContextWrapper_contextful_set__ = True
-
-def wrapperCreator(object, context=None, **data):
-    has_call = (hasattr(object, '__call__') and
-                getattr(object.__call__,
-                        '__Zope_ContextWrapper_contextful_get__', False))
-    has_getitem = (hasattr(object, '__getitem__') and
-                   getattr(object.__getitem__,
-                           '__Zope_ContextWrapper_contextful_get__', False))
-    if has_call and has_getitem:
-        factory = SimpleCallableGetitemMethodWrapper
-    elif has_call:
-        factory = SimpleCallableMethodWrapper
-    elif has_getitem:
-        factory = SimpleGetitemMethodWrapper
-    else:
-        factory = SimpleMethodWrapper
-
-    return factory(object, context, **data)
-
-Wrapper = wrapperCreator
-
-class SimpleMethodWrapper(_Wrapper):
-
-    def __getattribute__(self, name):
-        """Support for ContextMethod and ContextProperty.__get__"""
-        obj = getbaseobject(self)
-        class_ = obj.__class__
-        class_value = getattr(class_, name, None)
-        if hasattr(class_value, '__get__'):
-            if (isinstance(obj, ContextAware)
-                or
-                getattr(class_value,
-                       '__Zope_ContextWrapper_contextful_get__', False)
-                ):
-                return class_value.__get__(self, class_)
-
-        return _Wrapper.__getattribute__(self, name)
-
-    def __setattr__(self, name, value):
-        """Support for ContextProperty.__set__"""
-        obj = getbaseobject(self)
-        class_ = obj.__class__
-        class_value = getattr(class_, name, None)
-        if hasattr(class_value, '__set__'):
-            if (isinstance(obj, ContextAware)
-                or
-                getattr(class_value,
-                       '__Zope_ContextWrapper_contextful_set__', False)
-                ):
-                class_value.__set__(self, value)
-                return
-        setattr(obj, name, value)
-
-
-class SimpleCallableMethodWrapper(SimpleMethodWrapper):
-
-    def __call__(self, *args, **kw):
-        attr = _Wrapper.__getattribute__(self, '__call__')
-        return attr.__get__(self)(*args, **kw)
-
-class SimpleGetitemMethodWrapper(SimpleMethodWrapper):
-
-    def __getitem__(self, key, *args, **kw):
-        attr = _Wrapper.__getattribute__(self, '__getitem__')
-        return attr.__get__(self)(key, *args, **kw)
-
-class SimpleCallableGetitemMethodWrapper(SimpleCallableMethodWrapper,
-                                         SimpleGetitemMethodWrapper):
-    pass
-
-wrapperTypes = (SimpleMethodWrapper, SimpleCallableMethodWrapper,
-                SimpleGetitemMethodWrapper,
-                SimpleCallableGetitemMethodWrapper)
-
-for wrapper_type in wrapperTypes:
-    defineChecker(wrapper_type, _contextWrapperChecker)
+defineChecker(Wrapper, _contextWrapperChecker)
 
 class ContextSuper:
 


=== Zope3/src/zope/proxy/context/wrapper.c 1.2 => 1.3 === (770/870 lines abridged)
--- Zope3/src/zope/proxy/context/wrapper.c:1.2	Wed Dec 25 09:15:16 2002
+++ Zope3/src/zope/proxy/context/wrapper.c	Tue Apr  8 08:21:38 2003
@@ -1,4 +1,5 @@
 #include <Python.h>
+#include "structmember.h"
 #include "modsupport.h"
 #include "zope/proxy/proxy.h"
 #define WRAPPER_MODULE
@@ -16,10 +17,443 @@
 
 
 static PyTypeObject WrapperType;
+static PyTypeObject ContextAwareType;
 
 static PyObject *
 empty_tuple = NULL;
 
+/* ContextAware type
+ *
+ * This is a 'marker' type with no methods or members.
+ * It is used to mark types that should have all of their binding descriptors
+ * rebound to have the self argument be the wrapper instead.
+ */
+
+typedef struct {
+    PyObject_HEAD
+} ContextAwareObject;
+
+statichere PyTypeObject
+ContextAwareType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "wrapper.ContextAware",
+    sizeof(ContextAwareObject),
+    0,
+    0,						/* tp_dealloc */
+    0,						/* tp_print */
+    0,						/* tp_getattr */
+    0,						/* tp_setattr */
+    0,						/* tp_compare */
+    0,						/* tp_repr */
+    0,						/* tp_as_number */
+    0,						/* tp_as_sequence */
+    0,						/* tp_as_mapping */
+    0,						/* tp_hash */
+    0,						/* tp_call */
+    0,						/* tp_str */
+    0,						/* tp_getattro */
+    0,						/* tp_setattro */
+    0,						/* tp_as_buffer */

[-=- -=- -=- 770 lines omitted -=- -=- -=-]

 static PyObject *
 wrapper_getbaseobject(PyObject *unused, PyObject *obj)
@@ -587,7 +1267,7 @@
 setobject__doc__[] =
 "setobject(wrapper, object)\n"
 "\n"
-"Replaced the wrapped object with object.";
+"Replace the wrapped object with object.";
 
 static PyObject *
 wrapper_setobject(PyObject *unused, PyObject *args)
@@ -674,7 +1354,6 @@
     if (m == NULL)
         return;
 
-    WrapperType.ob_type = &PyType_Type;
     WrapperType.tp_base = ProxyType;
     WrapperType.tp_alloc = PyType_GenericAlloc;
     WrapperType.tp_free = _PyObject_GC_Del;
@@ -683,6 +1362,30 @@
 
     Py_INCREF(&WrapperType);
     PyModule_AddObject(m, "Wrapper", (PyObject *)&WrapperType);
+
+    if (PyType_Ready(&ContextAwareType) < 0)
+        return;
+    Py_INCREF(&ContextAwareType);
+    PyModule_AddObject(m, "ContextAware", (PyObject *)&ContextAwareType);
+
+    if (PyType_Ready(&ContextDescriptorType) < 0)
+        return;
+    Py_INCREF(&ContextDescriptorType);
+    PyModule_AddObject(m, "ContextDescriptor",
+                       (PyObject *)&ContextDescriptorType);
+
+    ContextMethod_Type.tp_base = &ContextDescriptorType;
+    if (PyType_Ready(&ContextMethod_Type) < 0)
+        return;
+    Py_INCREF(&ContextMethod_Type);
+    PyModule_AddObject(m, "ContextMethod", (PyObject *)&ContextMethod_Type);
+
+    ContextProperty_Type.tp_base = &ContextDescriptorType;
+    if (PyType_Ready(&ContextProperty_Type) < 0)
+        return;
+    Py_INCREF(&ContextProperty_Type);
+    PyModule_AddObject(m, "ContextProperty",
+                       (PyObject *)&ContextProperty_Type);
 
     if (api_object == NULL) {
         api_object = PyCObject_FromVoidPtr(&wrapper_capi, NULL);