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): ... @zope.proxy.non_overridable def __reduce__(self, proto=None): raise TypeError("Not picklable") ... I also had to change the the descriptors defined in zope.app.decorator 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? JimHi 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) else: proxy = LocationProxy(item) proxy.__name__ = item.__name__ proxy.__parent__ = container return proxy class ContainerLocationProxy(LocationProxy): """Proxy the location of a container an its items.""" # zope.app.conatiner.interfaces.IReadContainer 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__ function. Jim -- Jim Fulton mailto:[EMAIL PROTECTED] Python Powered! CTO (540) 361-1714 http://www.python.org Zope Corporation http://www.zope.com http://www.zope.org _______________________________________________ Zope3-dev mailing list [email protected] Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com
