[Grok-dev] Re: implements() works, alsoProvides() breaks

Philipp von Weitershausen philipp at weitershausen.de
Thu Aug 30 11:48:04 EDT 2007

Brandon Craig Rhodes wrote:
>    /myapp/Model_object/index  ... worked
>    /myapp/Model_object        ... worked
>    /myapp/Plain_object/index  ... worked
>    /myapp/Plain_object        ... broke completely :-)
> The solution was to introduce the following code into my application,
> assuming that the class I am trying to View instead of a grok.Model is
> class "Plain":
>     zope.component.provideAdapter('index',
>                                   adapts=(Plain, IBrowserRequest),
>                                   provides=IDefaultViewName)
> I swiped this code from the bootstrap() code of grok._grok, where it
> is run twice to provide a default View name of 'index' to grok.Model
> and grok.Container.

I do recommend doing this declaration in ZCML:

   <browser:defaultView for="Plain" name="index" />

Doing setup at import time isn't such a good idea. Alternatively, grok 
could grow a directive that would allow you to set the default view name 
for objects.

> Oh: and it only seems to work if my class
> implements the interface IContained.  But I can live with that.

Please be more specific. What's the actual error?

If this is about __parent__, grok should take care of it. If the object 
returned by the traverser provides ILocation (IContained is a 
subinterface of that), __parent__ and __name__ will automatically be 
assigned to the object. If not, grok will wrap it in a LocationProxy 
that adds __parent__ and __name__ without altering the object itself.

> I have now found (don't ask how many experiments it took until I
> determined this!) that running provideAdapter() this way on one of my
> own classes only results in a truly functioning default View name if
> my *class itself* provides IContained, but does *not* work if it is
> only the object *instance* returned by traverse() that provides
> IContained!

Again, please be more specific about the error message.

> This is terribly disappointing, because my actual plan had been to
> write traverse() methods that returned arbitrary objects, and that
> used alsoProvides() to slap an IContained interface decorator on each
> object before returning it to the framework.

That's not really what IContained was intended for. The idea is that 
implementations should be free to decide themselves whether they are 
contained/locatable or not. They signal this by implementing ILocation 
or IContained intrinsically. Slapping the interface on as a marker 
interface defeats the purpose of the ILocation and IContained interfaces.

The canonical way is to check for ILocation and set the attributes if 
the object provides them. If not, wrap the object in a LocationProxy:

     if zope.location.interfaces.ILocation.providedBy(obj):
         zope.location.locate(obj, parent, name)
         return obj
     return zope.location.LocationProxy(obj, parent, name)

> This is deeply mystifying to me; my impression from The Book had been
> that Zope 3 would treat as equivalent (at least for these purposes)
> the three above methods for declaring that an instance provides an
> interface.

 From your code:

>   zope.interface.alsoProvides(WorkingObject2, IContained)

alsoProvides takes an *object* as a first parameter. Not a class. This 
is where your problem is.

http://worldcookery.com -- Professional Zope documentation and training

More information about the Grok-dev mailing list