[Zope3-checkins] SVN: Zope3/branches/jim-adapter/src/zope/proxy/
Fix a bug that caused non-data descriptors to hide
proxied-object data.
Jim Fulton
jim at zope.com
Sun Apr 2 12:59:05 EDT 2006
Log message for revision 66294:
Fix a bug that caused non-data descriptors to hide proxied-object data.
Changed:
U Zope3/branches/jim-adapter/src/zope/proxy/__init__.py
U Zope3/branches/jim-adapter/src/zope/proxy/_zope_proxy_proxy.c
U Zope3/branches/jim-adapter/src/zope/proxy/tests/test_proxy.py
-=-
Modified: Zope3/branches/jim-adapter/src/zope/proxy/__init__.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/proxy/__init__.py 2006-04-02 10:47:12 UTC (rev 66293)
+++ Zope3/branches/jim-adapter/src/zope/proxy/__init__.py 2006-04-02 16:59:05 UTC (rev 66294)
@@ -29,3 +29,6 @@
while isProxy(p):
p = getProxiedObject(p)
yield p
+
+def non_overridable(func):
+ return property(lambda self: func.__get__(self))
Modified: Zope3/branches/jim-adapter/src/zope/proxy/_zope_proxy_proxy.c
===================================================================
--- Zope3/branches/jim-adapter/src/zope/proxy/_zope_proxy_proxy.c 2006-04-02 10:47:12 UTC (rev 66293)
+++ Zope3/branches/jim-adapter/src/zope/proxy/_zope_proxy_proxy.c 2006-04-02 16:59:05 UTC (rev 66294)
@@ -234,6 +234,18 @@
if (descriptor != NULL) {
if (PyType_HasFeature(descriptor->ob_type, Py_TPFLAGS_HAVE_CLASS)
&& descriptor->ob_type->tp_descr_get != NULL) {
+
+ if (descriptor->ob_type->tp_descr_set == NULL)
+ {
+ res = PyObject_GetAttr(wrapped, name);
+ if (res != NULL)
+ goto finally;
+ if (PyErr_ExceptionMatches(PyExc_AttributeError))
+ PyErr_Clear();
+ else
+ goto finally;
+ }
+
res = descriptor->ob_type->tp_descr_get(
descriptor,
self,
@@ -278,17 +290,13 @@
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));
- }
+ if (descriptor != NULL
+ && 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);
goto finally;
- }
+ }
wrapped = Proxy_GET_OBJECT(self);
if (wrapped == NULL) {
Modified: Zope3/branches/jim-adapter/src/zope/proxy/tests/test_proxy.py
===================================================================
--- Zope3/branches/jim-adapter/src/zope/proxy/tests/test_proxy.py 2006-04-02 10:47:12 UTC (rev 66293)
+++ Zope3/branches/jim-adapter/src/zope/proxy/tests/test_proxy.py 2006-04-02 16:59:05 UTC (rev 66294)
@@ -21,6 +21,7 @@
from zope.testing.doctestunit import DocTestSuite
from zope.proxy import ProxyBase
+import zope.proxy
class Thing:
"""This class is expected to be a classic class."""
@@ -552,7 +553,67 @@
"""
+def test_get_descriptors_in_proxy_class():
+ """
+ A non-data descriptor in a proxy class doesn't hide an attribute on
+ a proxied object or prevent writing the attribute.
+ >>> class ReadDescr(object):
+ ... def __get__(self, i, c):
+ ... return 'read'
+
+ >>> class MyProxy(ProxyBase):
+ ... __slots__ = ()
+ ...
+ ... z = ReadDescr()
+ ... q = ReadDescr()
+
+ >>> class MyOb:
+ ... q = 1
+
+ >>> o = MyOb()
+ >>> p = MyProxy(o)
+ >>> p.q
+ 1
+
+ >>> p.z
+ 'read'
+
+ >>> p.z = 1
+ >>> o.z, p.z
+ (1, 1)
+
+ """
+
+def test_non_overridable():
+ """
+ Normally, methods defined in proxies are overridden by
+ methods of proxied objects. This applies to all non-data
+ descriptors. The non_overridable function can be used to
+ convert a non-data descriptor to a data descriptor that disallows
+ writes. This function can be used as a decorator to make functions
+ defined in proxy classes take precedence over functions defined
+ in proxied objects.
+
+
+ >>> class MyProxy(ProxyBase):
+ ... __slots__ = ()
+ ...
+ ... @zope.proxy.non_overridable
+ ... def foo(self):
+ ... return 'MyProxy foo'
+
+ >>> class MyOb:
+ ... def foo(self):
+ ... return 'MyOb foo'
+
+ >>> o = MyOb()
+ >>> p = MyProxy(o)
+ >>> p.foo()
+ 'MyProxy foo'
+
+ """
+
def test_suite():
suite = unittest.makeSuite(ProxyTestCase)
suite.addTest(DocTestSuite())
More information about the Zope3-Checkins
mailing list