[Zope-CMF] Re: How do deal with cmfcatalog-wrapped objects?

Philipp von Weitershausen philipp at weitershausen.de
Fri Mar 31 07:11:58 EST 2006


yuppie wrote:
> Andreas Jung wrote:
>> we have a CMF-based application where I am trying to migrate from
>> TextIndexNG 2 -> 3.
>>
>> For a content-type class A I have configured an adapter to implement
>> IIndexableContent. However when the object is reindexed CMF wraps
>> the object as IndexableObjectWrapper which by itself implements
>> the IndexableObjectWrapper interface. The low-level indexer of TXNG
>> get the wrapped object and has no idea what to do with the object
>> since the interface of the wrapper  shadows the interface of the
>> wrapped object.
>> Any idea how to deal with this problem?
> 
> I'm currently fighting with the same issue. And I was in the process of
> writing a mail to the Zope-CMF list when your mail came in. AFAICS this
> is more a CMF issue than a Five issue, so I add Zope-CMF to the
> recipients list.
> 
> 
> Just for the records, I'm sure you already figured that out yourself:
> 
> Plone 2.1 doesn't have this issue because it has no interface
> declaration on its ExtensibleIndexableObjectWrapper.  If the wrapper
> doesn't have its own __providedBy__ attribute the __getattr__ method
> looks it up in the wrapped class, making the interface declarations
> completely transparent.
> 
> Plone 2.5 has an interface declaration so I guess it has the same
> problem as the CMF.
> 
> 
> 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.

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())

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.

Philipp


More information about the Zope-CMF mailing list