Commit 2c737818 authored by Christian Zagrodnick's avatar Christian Zagrodnick

- LP #374810: ``__bobo_traverse__`` implementation can raise

``ZPublisher.interfaces.UseTraversalDefault`` to indicate that there is no
special casing for the given name and that standard traversal logic should be
applied.
parent 56178d52
...@@ -127,6 +127,11 @@ Restructuring ...@@ -127,6 +127,11 @@ Restructuring
Features Added Features Added
++++++++++++++ ++++++++++++++
- LP #374810: ``__bobo_traverse__`` implementation can raise
``ZPublisher.interfaces.UseTraversalDefault`` to indicate that there is no
special casing for the given name and that standard traversal logic should
be applied.
- LP #142226: Added an extra keyword argument to the HTTPResponse - LP #142226: Added an extra keyword argument to the HTTPResponse
setCookie method to suppress enclosing the cookie value field setCookie method to suppress enclosing the cookie value field
in double quotes. in double quotes.
......
...@@ -30,6 +30,7 @@ from Acquisition import aq_parent ...@@ -30,6 +30,7 @@ from Acquisition import aq_parent
from Acquisition.interfaces import IAcquirer from Acquisition.interfaces import IAcquirer
from OFS.interfaces import ITraversable from OFS.interfaces import ITraversable
from zExceptions import NotFound from zExceptions import NotFound
from ZPublisher.interfaces import UseTraversalDefault
from ZODB.POSException import ConflictError from ZODB.POSException import ConflictError
from zope.interface import implements from zope.interface import implements
...@@ -207,7 +208,10 @@ class Traversable: ...@@ -207,7 +208,10 @@ class Traversable:
except LocationError: except LocationError:
raise AttributeError(name) raise AttributeError(name)
elif bobo_traverse is not None: else:
next = UseTraversalDefault # indicator
try:
if bobo_traverse is not None:
next = bobo_traverse(REQUEST, name) next = bobo_traverse(REQUEST, name)
if restricted: if restricted:
if aq_base(next) is not next: if aq_base(next) is not next:
...@@ -239,7 +243,10 @@ class Traversable: ...@@ -239,7 +243,10 @@ class Traversable:
guarded_getattr(obj, name, _marker) guarded_getattr(obj, name, _marker)
is not next): is not next):
raise Unauthorized(name) raise Unauthorized(name)
else: except UseTraversalDefault:
# behave as if there had been no '__bobo_traverse__'
bobo_traverse = None
if next is UseTraversalDefault:
if getattr(aq_base(obj), name, _marker) is not _marker: if getattr(aq_base(obj), name, _marker) is not _marker:
if restricted: if restricted:
next = guarded_getattr(obj, name) next = guarded_getattr(obj, name)
......
...@@ -354,6 +354,33 @@ class TestTraverse( unittest.TestCase ): ...@@ -354,6 +354,33 @@ class TestTraverse( unittest.TestCase ):
self.failUnlessRaises(Unauthorized, self.failUnlessRaises(Unauthorized,
self.root.folder1.restrictedTraverse, 'stuff') self.root.folder1.restrictedTraverse, 'stuff')
def testBoboTraverseTraversalDefault(self):
from OFS.SimpleItem import SimpleItem
from ZPublisher.interfaces import UseTraversalDefault
class BoboTraversableUseTraversalDefault(SimpleItem):
"""
A BoboTraversable class which may use "UseTraversalDefault"
(dependent on "name") to indicate that standard traversal should
be used.
"""
default = 'Default'
def __bobo_traverse__(self, request, name):
if name == 'normal': return 'Normal'
raise UseTraversalDefault
bb = BoboTraversableUseTraversalDefault()
# normal access -- no traversal default used
self.assertEqual(bb.unrestrictedTraverse('normal'), 'Normal')
# use traversal default
self.assertEqual(bb.unrestrictedTraverse('default'), 'Default')
# test traversal default with acqires attribute
si = SimpleItem()
si.default_acquire = 'Default_Acquire'
si.bb = bb
self.assertEqual(si.unrestrictedTraverse('bb/default_acquire'), 'Default_Acquire')
def testAcquiredAttributeDenial(self): def testAcquiredAttributeDenial(self):
# Verify that restrictedTraverse raises the right kind of exception # Verify that restrictedTraverse raises the right kind of exception
# on denial of access to an acquired attribute. If it raises # on denial of access to an acquired attribute. If it raises
......
...@@ -20,6 +20,7 @@ import xmlrpc ...@@ -20,6 +20,7 @@ import xmlrpc
from Acquisition import aq_base from Acquisition import aq_base
from Acquisition.interfaces import IAcquirer from Acquisition.interfaces import IAcquirer
from ZPublisher.interfaces import UseTraversalDefault
from zExceptions import Forbidden from zExceptions import Forbidden
from zExceptions import NotFound from zExceptions import NotFound
from zope.component import queryMultiAdapter from zope.component import queryMultiAdapter
...@@ -79,6 +80,8 @@ class DefaultPublishTraverse(object): ...@@ -79,6 +80,8 @@ class DefaultPublishTraverse(object):
if name[:1]=='_': if name[:1]=='_':
raise Forbidden("Object name begins with an underscore at: %s" % URL) raise Forbidden("Object name begins with an underscore at: %s" % URL)
subobject = UseTraversalDefault # indicator
try:
if hasattr(object,'__bobo_traverse__'): if hasattr(object,'__bobo_traverse__'):
try: try:
subobject=object.__bobo_traverse__(request, name) subobject=object.__bobo_traverse__(request, name)
...@@ -102,8 +105,10 @@ class DefaultPublishTraverse(object): ...@@ -102,8 +105,10 @@ class DefaultPublishTraverse(object):
return subobject return subobject
# No view found. Reraise the error raised by __bobo_traverse__ # No view found. Reraise the error raised by __bobo_traverse__
raise e raise e
else: except UseTraversalDefault:
# No __bobo_traverse__ pass
if subobject is UseTraversalDefault:
# No __bobo_traverse__ or default traversal requested
# Try with an unacquired attribute: # Try with an unacquired attribute:
if hasattr(aq_base(object), name): if hasattr(aq_base(object), name):
subobject = getattr(object, name) subobject = getattr(object, name)
......
...@@ -58,3 +58,15 @@ class IPubBeforeStreaming(Interface): ...@@ -58,3 +58,15 @@ class IPubBeforeStreaming(Interface):
""" """
response = Attribute(u"The current HTTP response") response = Attribute(u"The current HTTP response")
# Exceptions
class UseTraversalDefault(Exception):
"""Indicate default traversal in ``__bobo_traverse__``
This exception can be raised by '__bobo_traverse__' implementations to
indicate that it has no special casing for the given name and that standard
traversal logic should be applied.
"""
...@@ -124,6 +124,27 @@ class BaseRequest_factory: ...@@ -124,6 +124,27 @@ class BaseRequest_factory:
return self, self._default_path return self, self._default_path
return DummyObjectWithBD() return DummyObjectWithBD()
def _makeObjectWithBBT(self):
from ZPublisher.interfaces import UseTraversalDefault
class _DummyResult(object):
''' '''
def __init__(self, tag):
self.tag = tag
class DummyObjectWithBBT(self._makeBasicObjectClass()):
""" Dummy class with __bobo_traverse__
"""
default = _DummyResult('Default')
def __bobo_traverse__(self, REQUEST, name):
if name == 'normal':
return _DummyResult('Normal')
elif name == 'default':
raise UseTraversalDefault
raise AttributeError(name)
return DummyObjectWithBBT()
def _makeObjectWithBDBBT(self): def _makeObjectWithBDBBT(self):
class DummyObjectWithBDBBT(self._makeBasicObjectClass()): class DummyObjectWithBDBBT(self._makeBasicObjectClass()):
"""Dummy class with __browser_default__.""" """Dummy class with __browser_default__."""
...@@ -255,6 +276,16 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory): ...@@ -255,6 +276,16 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
self.failUnlessRaises(NotFound, r.traverse, self.failUnlessRaises(NotFound, r.traverse,
'folder/objWithBBT/bbt_foo') 'folder/objWithBBT/bbt_foo')
def test_traverse_UseTraversalDefault(self):
root, folder = self._makeRootAndFolder()
folder._setObject('objWithBBT', self._makeObjectWithBBT())
# test non default usage
r = self._makeOne(root)
self.assertEqual(r.traverse('folder/objWithBBT/normal').tag, 'Normal')
# test default usage
r = self._makeOne(root)
self.assertEqual(r.traverse('folder/objWithBBT/default').tag, 'Default')
def test_traverse_withBDBBT(self): def test_traverse_withBDBBT(self):
# Test for an object which has a __browser_default__ # Test for an object which has a __browser_default__
# and __bobo_traverse__ # and __bobo_traverse__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment