Hi Philipp!
Philipp von Weitershausen wrote:
yuppie wrote:
The quick and dirty solution would be to remove the interface
declaration from the wrapper. The clean solution would be to make sure
that all the interfaces that are actually provided - the wrapper
interface *and* the interfaces of the wrapped object - can be looked up.
But implementing that seems to require deeper knowledge of the interface
machinery than I have.
This problem has already been solved in Zope 3. There we like to wrap
objects that don't provide ILocation (__parent__ and __name__
attributes) in something that *does* provide ILocation. The resulting
object is a proxy for the original object and in addition that it
provides __parent__ and __name__ attributes. The proxy provides whatever
the original object provides plus ILocation.
We call this concept a /decorator/. This is not to be confused with
Python 2.4's function decorators. In Zope 3's case, think of decorator
as a proxy that also adds stuff to the object (e.g. the ILocation API).
Hence, it decorates the original object, like a Christmas tree if you will.
Great! Good to know.
There are two options:
1. I think for the long term, IndexableObjectWrapper could be made a
decorator. This works as follows:
from zope.proxy import getProxiedObject
from zope.app.decorator import Decorator
class IndexableObjectWrapper(Decorator):
def allowedRolesAndUsers(self):
ob = getProxiedObject(self)
allowed = {}
for r in rolesForPermissionOn(View, ob):
allowed[r] = 1
localroles = _mergedLocalRoles(ob)
for user, roles in localroles.items():
for role in roles:
if allowed.has_key(role):
allowed['user:' + user] = 1
if allowed.has_key('Owner'):
del allowed['Owner']
return list(allowed.keys())
Why is this your preferred long term option? IndexableObjectWrapper does
a lot of special stuff. It doesn't just proxy to an object and add a new
method. It also allows to pass in a list of vars that are looked up
first by __getattr__. To get this working I did have to provide __new__,
__init__ and __getattr__ as well. So the base class doesn't make the
code much simpler.
2. In the short term we can apply the following trick
(IndexableObjectWrapper needs to be a new style class!):
from zope.interface import providedBy
from zope.interface.declarations import ObjectSpecificationDescriptor
from zope.interface.declarations import getObjectSpecification
from zope.interface.declarations import ObjectSpecification
class IndexableObjectSpecification(ObjectSpecificationDescriptor):
def __get__(self, inst, cls=None):
if inst is None:
return getObjectSpecification(cls)
else:
provided = providedBy(inst.__ob)
cls = type(inst)
return ObjectSpecification(provided, cls)
class IndexableObjectWrapper(object): # new-style!
implements(...) # it can implement as much as it wants
__providedBy__ = IndexableObjectSpecification()
...
This is obviously untested, but I'm pretty confident that this would work.
Yeah, works with a small modification: '__ob' has double leading
underscores, so I did have to use '_IndexableObjectWrapper__ob' instead.
And switching to a new style class has a side effect: 'object' has some
attributes that now mask the attributes of the wrapped object. AFAICS
this is only a problem with '__str__' that is the default method for
getting the binary data of a file object.
I checked in a fix using the second option.
Cheers,
Yuppie
_______________________________________________
Zope-CMF maillist - Zope-CMF@lists.zope.org
http://mail.zope.org/mailman/listinfo/zope-cmf
See http://collector.zope.org/CMF for bug reports and feature requests