Roger Ineichen wrote:
Jim Fulton schrieb:

A while ago, Gary and I found what appeared to be a bug in
zope.proxy.ProxyBase's handling of non-data descriptors (descriptors
that define __get__, but not __set__ and __delete__) defined in
proxy classes.  Normally, when a class has non-data descriptors,
instance data overrides the descriptor.  ProxyBase let non-data
descriptors override instance data.  For a proxy, instance data almost
always comes from the proxied object.  This behavior of ProxyBase
caused subtle bugs.

I've decided to fix this bug because it was causing my pain on my
jim-adapter branch.  I decided to fix this bug on the branch.  The fix
has a somewhat unexpected side effect. It turns out that some proxy
applications depended on the old behavior.

Consider location proxies:

  class LocationProxy(ProxyBase):

      def __reduce__(self, proto=None):
          raise TypeError("Not picklable")


Here the proxy is trying to prevent pickling by providing a __reduce__
that raises an exception.  Now methods are non-data descriptors.  With
the fix, the __reduce__ of the proxied object is used.  We need to
convert __reduce__ to a data descriptor.  I've added a function to
the branch that can be used as a decorator to do this:

  class LocationProxy(ProxyBase):

      def __reduce__(self, proto=None):
          raise TypeError("Not picklable")


I also had to change the the descriptors defined in
to be data descriptors.

The fix is obviously not backward compatible.  I don't know if this
would effect anything outside of Zope.  If this affects anyone, please
let me know.  If necessary, I can probably provide a ProxyBase2 with
the fix and leave ProxyBase alone, but I'd rather not.

Is anyone using zope.proxy to define custom proxy types?


Hi Jim,

We just use a IContainer location proxy adapter.
But since this adapter isn't persistent I don't think this
is a problem.

def proxify(container, item):
    if IContainer.providedBy(item):
        proxy = ContainerLocationProxy(item)
        proxy = LocationProxy(item)
    proxy.__name__ = item.__name__
    proxy.__parent__ = container
    return proxy

class ContainerLocationProxy(LocationProxy):
    """Proxy the location of a container an its items."""

    def __getitem__(self, key):
        return proxify(self, getProxiedObject(self).__getitem__(key))


Well, with the fix, your __getitem__ won't be called. Is that a
problem? ;)

You will need to use the @non_overridable decorator on your __getitem__


Jim Fulton           mailto:[EMAIL PROTECTED]       Python Powered!
CTO                  (540) 361-1714  
Zope Corporation
Zope3-dev mailing list

Reply via email to