diff options
| -rw-r--r-- | CHANGES.txt | 31 | ||||
| -rw-r--r-- | repoze/bfg/configuration.py | 9 | ||||
| -rw-r--r-- | repoze/bfg/exceptions.py | 8 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_configuration.py | 17 |
4 files changed, 59 insertions, 6 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 6acb3cde6..9fadd1beb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -35,6 +35,37 @@ Bug Fixes ``TypeError: expected string or buffer`` exception. Now, the predicate returns False as intended. +Backwards Incompatibilities +--------------------------- + +- A new internal exception class (*not* an API) named + ``repoze.bfg.exceptions.PredicateMismatch`` now exists. This + exception is currently raised when no constituent view of a + multiview can be called (due to no predicate match). Previously, in + this situation, a ``repoze.bfg.exceptions.NotFound`` was raised. We + provide backwards compatibility for code that expected a + ``NotFound`` to be raised when no predicates match by causing + ``repoze.bfg.exceptions.PredicateMismatch`` to inherit from + ``NotFound``. This will cause any exception view registered for + ``NotFound`` to be called when a predicate mismatch occurs, as was + the previous behavior. + + There is however, one perverse case that will expose a backwards + incompatibility. If 1) you had a view that was registered as a + member of a multiview 2) this view explicitly raised a ``NotFound`` + exception *in order to* proceed to the next predicate check in the + multiview, that code will now behave differently: rather than + skipping to the next view match, a NotFound will be raised to the + top-level exception handling machinery instead. For code to be + depending upon the behavior of a view raising ``NotFound`` to + proceed to the next predicate match, would be tragic, but not + impossible, given that ``NotFound`` is a public interface. + ``repoze.bfg.exceptions.PredicateMismatch`` is not a public API and + cannot be depended upon by application code, so you should not + change your view code to raise ``PredicateMismatch``. Instead, move + the logic which raised the ``NotFound`` exception in the view out + into a custom view predicate. + 1.3a5 (2010-07-14) ================== diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index 4073719b4..e5e8bc8f6 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -49,6 +49,7 @@ from repoze.bfg.compat import md5 from repoze.bfg.events import WSGIApplicationCreatedEvent from repoze.bfg.exceptions import Forbidden from repoze.bfg.exceptions import NotFound +from repoze.bfg.exceptions import PredicateMismatch from repoze.bfg.exceptions import ConfigurationError from repoze.bfg.i18n import get_localizer from repoze.bfg.log import make_stream_logger @@ -1894,7 +1895,7 @@ class MultiView(object): return view if view.__predicated__(context, request): return view - raise NotFound(self.name) + raise PredicateMismatch(self.name) def __permitted__(self, context, request): view = self.match(context, request) @@ -1911,9 +1912,9 @@ class MultiView(object): for order, view, phash in self.get_views(request): try: return view(context, request) - except NotFound: + except PredicateMismatch: continue - raise NotFound(self.name) + raise PredicateMismatch(self.name) def decorate_view(wrapped_view, original_view): if wrapped_view is original_view: @@ -2130,7 +2131,7 @@ def _predicate_wrap(view, predicates): def predicate_wrapper(context, request): if all((predicate(context, request) for predicate in predicates)): return view(context, request) - raise NotFound('predicate mismatch for view %s' % view) + raise PredicateMismatch('predicate mismatch for view %s' % view) def checker(context, request): return all((predicate(context, request) for predicate in predicates)) diff --git a/repoze/bfg/exceptions.py b/repoze/bfg/exceptions.py index b0922c1e3..00cb76883 100644 --- a/repoze/bfg/exceptions.py +++ b/repoze/bfg/exceptions.py @@ -40,3 +40,11 @@ class URLDecodeError(UnicodeDecodeError): class ConfigurationError(ZCE): """ Raised when inappropriate input values are supplied to an API method of a :term:`Configurator`""" + +class PredicateMismatch(NotFound): + """ Internal exception (not an API) raised by multiviews when no + view matches. This exception subclasses the ``NotFound`` + exception only one reason: if it reaches the main exception + handler, it should be treated like a ``NotFound`` by any exception + view registrations.""" + diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index 4df7af1c2..17708bf63 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -3307,20 +3307,33 @@ class TestMultiView(unittest.TestCase): self.assertRaises(NotFound, mv, context, request) def test___call__intermediate_not_found(self): - from repoze.bfg.exceptions import NotFound + from repoze.bfg.exceptions import PredicateMismatch mv = self._makeOne() context = DummyContext() request = DummyRequest() request.view_name = '' expected_response = DummyResponse() def view1(context, request): - raise NotFound + raise PredicateMismatch def view2(context, request): return expected_response mv.views = [(100, view1, None), (99, view2, None)] response = mv(context, request) self.assertEqual(response, expected_response) + def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + def view1(context, request): + raise NotFound + def view2(context, request): + """ """ + mv.views = [(100, view1, None), (99, view2, None)] + self.assertRaises(NotFound, mv, context, request) + def test___call__(self): mv = self._makeOne() context = DummyContext() |
