[Zope-dev] Why does restrictedTraverse() in Zope 2 not respect IPublishTraverse adapters?

Laurence Rowe l at lrowe.co.uk
Thu May 14 16:55:40 EDT 2009


Tres Seaver wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Martin Aspeli wrote:
> 
>> There's currently a funny inconsistency in Zope's Traversable class. If 
>> you have a URL like http://localhost:8080/path/to/@@aview/foo, and 
>> @@aview implements IPublishTraverse (and, I presume, if there's a custom 
>> IPublishTraverse adapter for any other path component), URL traversal 
>> will work fine, but calling to.restrictedTraverse('@@aview/foo') or some 
>> variant thereof will fail, because (un)restrictedTraverse() does not 
>> respect custom IPublishTraverse adapters.
> 
> 'restrictedTraverse' is not (and never has been) the same as URL
> traversal.  For instance:
> 
> - - URL traversal does no security checking until it finds the published
>   object.
> 
> - - URL traveresal manages the '__before_publishing_traverse__' hooks.
> 
> 
> If you want your adapter to be respected by *both*, it needs to
> implement the appropriate interfaces for both.
> 
>> I can kind of see why it's done like this since it's called 
>> I*Publish*Traverse, but it is a pain.
>>
>> Note that namespace traversal (like ++skin++) works fine with 
>> restrictedTraverse().
>>
>> I don't think it'd be hard to implement this, but:
>>
>>   - is this a bug?
> 
> No.
> 
>>   - is there a reason not to do this?
> 
> - -1 to adding any more majyk to the over-complicated Z3-style traversal
> dance inside Zope2, especially as it would involve a bunch of subtle
> behavior changes which would be hard to explain.
> 
> For maximum portability across Z2 / Z3 / BFG, you could just do the same
> thing and implement __getitem__ on any object you want to be traversable
> by either the publisher or APIs like (un)restrictedTraverse, and forego
> the over-complicated  component-laden traversal dance. ;)

Minimal example demonstrating this with a view in zope2:

 >>> from zope.component import getSiteManager
 >>> from Testing.makerequest import makerequest
 >>> from zope.publisher.browser import IBrowserView
 >>> from Acquisition import Explicit
 >>> from zope.component import getSiteManager
 >>> app = makerequest(app)
 >>> smgr = getSiteManager()
 >>> class Foo(Explicit):
...   def __init__(self, context, request):
...     self.context, self.request = context, request
...   def __getitem__(self, key):
...     return int(key)
...
 >>> smgr.registerAdapter(Foo, (None, IRequest), IBrowserView, name='foo')
 >>> app.unrestrictedTraverse('@@foo/12345')
12345

Laurence



More information about the Zope-Dev mailing list