[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);