diff options
| author | Amos Latteier <amos@latteier.com> | 2013-01-10 14:55:07 -0500 |
|---|---|---|
| committer | Amos Latteier <amos@latteier.com> | 2013-01-10 14:55:07 -0500 |
| commit | b3643d8e587b48711f3224673d6c864d8ce1f93f (patch) | |
| tree | eba1d5b58bce00e67ae336bf65f8c2a4665b8fe2 | |
| parent | 09f43d3ba25ba2189a1b9abf6978e14690034d16 (diff) | |
| download | pyramid-b3643d8e587b48711f3224673d6c864d8ce1f93f.tar.gz pyramid-b3643d8e587b48711f3224673d6c864d8ce1f93f.tar.bz2 pyramid-b3643d8e587b48711f3224673d6c864d8ce1f93f.zip | |
Make predicate mismatches not hide other possible valid views.
This is mostly an issue for REST style views that use request_method
predicates and are registered for context interfaces.
See Issue #409
| -rw-r--r-- | pyramid/router.py | 22 | ||||
| -rw-r--r-- | pyramid/tests/test_router.py | 72 |
2 files changed, 92 insertions, 2 deletions
diff --git a/pyramid/router.py b/pyramid/router.py index 9b6138ea9..bb2466ec3 100644 --- a/pyramid/router.py +++ b/pyramid/router.py @@ -1,4 +1,5 @@ from zope.interface import ( + Interface, implementer, providedBy, ) @@ -24,6 +25,7 @@ from pyramid.events import ( NewResponse, ) +from pyramid.exceptions import PredicateMismatch from pyramid.httpexceptions import HTTPNotFound from pyramid.request import Request from pyramid.threadlocal import manager @@ -158,8 +160,24 @@ class Router(object): msg = request.path_info raise HTTPNotFound(msg) else: - response = view_callable(context, request) - + try: + response = view_callable(context, request) + except PredicateMismatch: + # look for other views that meet the predicate + # criteria + for iface in [i for i in context_iface.flattened() + if i != Interface]: + view_callable = adapters.lookup( + (IViewClassifier, request.request_iface, iface), + IView, name=view_name, default=None) + if view_callable is not None: + try: + response = view_callable(context, request) + break + except PredicateMismatch: + pass + else: + raise return response def invoke_subrequest(self, request, use_tweens=False): diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py index 65152ca05..32e74a3b3 100644 --- a/pyramid/tests/test_router.py +++ b/pyramid/tests/test_router.py @@ -1164,6 +1164,78 @@ class TestRouter(unittest.TestCase): start_response = DummyStartResponse() self.assertRaises(RuntimeError, router, environ, start_response) + def test_call_view_raises_predicate_mismatch(self): + from pyramid.exceptions import PredicateMismatch + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IRequest + view = DummyView(DummyResponse(), raise_exception=PredicateMismatch) + self._registerView(view, '', IViewClassifier, IRequest, None) + environ = self._makeEnviron() + router = self._makeOne() + start_response = DummyStartResponse() + self.assertRaises(PredicateMismatch, router, environ, start_response) + + def test_call_view_predicate_mismatch_doesnt_hide_views(self): + from pyramid.exceptions import PredicateMismatch + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IRequest, IResponse + from pyramid.response import Response + from zope.interface import Interface, implementer + class IContext(Interface): + pass + @implementer(IContext) + class DummyContext: + pass + context = DummyContext() + self._registerTraverserFactory(context) + view = DummyView(DummyResponse(), raise_exception=PredicateMismatch) + self._registerView(view, '', IViewClassifier, IRequest, + DummyContext) + good_view = DummyView('abc') + self._registerView(self.config.derive_view(good_view), + '', IViewClassifier, IRequest, IContext) + router = self._makeOne() + def make_response(s): + return Response(s) + router.registry.registerAdapter(make_response, (str,), IResponse) + environ = self._makeEnviron() + start_response = DummyStartResponse() + app_iter = router(environ, start_response) + self.assertEqual(app_iter, [b'abc']) + + def test_call_view_multiple_predicate_mismatches_dont_hide_views(self): + from pyramid.exceptions import PredicateMismatch + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IRequest, IResponse + from pyramid.response import Response + from zope.interface import Interface, implementer + class IBaseContext(Interface): + pass + class IContext(IBaseContext): + pass + @implementer(IContext) + class DummyContext: + pass + context = DummyContext() + self._registerTraverserFactory(context) + view1 = DummyView(DummyResponse(), raise_exception=PredicateMismatch) + self._registerView(view1, '', IViewClassifier, IRequest, + DummyContext) + view2 = DummyView(DummyResponse(), raise_exception=PredicateMismatch) + self._registerView(view2, '', IViewClassifier, IRequest, + IContext) + good_view = DummyView('abc') + self._registerView(self.config.derive_view(good_view), + '', IViewClassifier, IRequest, IBaseContext) + router = self._makeOne() + def make_response(s): + return Response(s) + router.registry.registerAdapter(make_response, (str,), IResponse) + environ = self._makeEnviron() + start_response = DummyStartResponse() + app_iter = router(environ, start_response) + self.assertEqual(app_iter, [b'abc']) + class DummyPredicate(object): def __call__(self, info, request): return True |
