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