From 0d13f6596c2cf38a611183e01a7f73173d5d6faa Mon Sep 17 00:00:00 2001 From: Malthe Borch Date: Mon, 26 Oct 2009 12:27:34 +0000 Subject: The root factory may now return an object which implements ``ITraverser`` directly. In this case, no adaptation is done before traversal. This feature is added such that a routes factory can implement its own traversal logic without establishing an artificial context only to get a hook into the traversal machinery. --- CHANGES.txt | 4 ++++ docs/narr/hooks.rst | 3 +++ repoze/bfg/tests/test_router.py | 40 +++++++++++++++++++++++++++++++++++++--- repoze/bfg/traversal.py | 9 ++++++--- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index b4c04304e..b112a996a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,10 @@ Next release Features -------- +- The root factory may now return an object which implements + ``ITraverser`` directly. In this case, no adaptation is done before + traversal. + - Add ``path_info`` view configuration predicate. - ``paster bfgshell`` now supports IPython if it's available for diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index d2020af0d..6babeace0 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -278,6 +278,9 @@ when the application :term:`root factory` returned an instance of the ``myapp.models.MyRoot`` object. Otherwise it would use the default :mod:`repoze.bfg` traverser to do traversal. +Note that the root object may itself implement ``ITraverser`` in which +case adaptation is skipped. + Example implementations of alternate traversers can be found "in the wild" within `repoze.bfg.traversalwrapper `_ and diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index 13a5bd11a..6c0497653 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -28,10 +28,9 @@ class TestRouter(unittest.TestCase): settings.update(kw) self.registry.registerUtility(settings, ISettings) - def _registerTraverserFactory(self, context, view_name='', subpath=None, + def _makeTraverserFactory(self, context, view_name='', subpath=None, traversed=None, virtual_root=None, virtual_root_path=None, **kw): - from repoze.bfg.interfaces import ITraverser if virtual_root is None: virtual_root = context @@ -42,8 +41,13 @@ class TestRouter(unittest.TestCase): if virtual_root_path is None: virtual_root_path = [] + from zope.interface import implements + from repoze.bfg.interfaces import ITraverser + class DummyTraverserFactory: - def __init__(self, root): + implements(ITraverser) + + def __init__(self, root=None): self.root = root def __call__(self, path): @@ -57,6 +61,11 @@ class TestRouter(unittest.TestCase): kw.update(values) return kw + return DummyTraverserFactory + + def _registerTraverserFactory(self, *args, **kwargs): + DummyTraverserFactory = self._makeTraverserFactory(*args, **kwargs) + from repoze.bfg.interfaces import ITraverser self.registry.registerAdapter(DummyTraverserFactory, (None,), ITraverser, name='') @@ -147,6 +156,31 @@ class TestRouter(unittest.TestCase): self.failIf('debug_notfound' in result[0]) self.assertEqual(len(logger.messages), 0) + def test_call_traverser_model(self): + environ = self._makeEnviron() + from zope.interface import Interface + class IContext(Interface): + pass + context = DummyContext() + from zope.interface import directlyProvides + directlyProvides(context, IContext) + RootFactory = self._makeTraverserFactory(context, view_name='def') + root = RootFactory() + self._registerRootFactory(root) + from repoze.bfg.interfaces import IRequest + response = DummyResponse() + response.app_iter = ['Hello world'] + view = DummyView(response) + self._registerView(view, 'def', IContext, IRequest) + logger = self._registerLogger() + router = self._makeOne() + start_response = DummyStartResponse() + result = router(environ, start_response) + self.assertEqual(result, ['Hello world']) + headers = start_response.headers + status = start_response.status + self.assertEqual(status, '200 OK') + def test_has_webob_adhoc_attrs(self): environ = self._makeEnviron() environ['webob.adhoc_attrs'] = {} diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index 11e5ca806..580225566 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -273,9 +273,12 @@ def traverse(model, path): return _traverse(model, {'PATH_INFO':path}) def _traverse(model, environ): - traverser = queryAdapter(model, ITraverser) - if traverser is None: - traverser = ModelGraphTraverser(model) + if ITraverser.providedBy(model): + traverser = model + else: + traverser = queryAdapter(model, ITraverser) + if traverser is None: + traverser = ModelGraphTraverser(model) result = traverser(environ) return result -- cgit v1.2.3