summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt31
-rw-r--r--repoze/bfg/configuration.py9
-rw-r--r--repoze/bfg/exceptions.py8
-rw-r--r--repoze/bfg/tests/test_configuration.py17
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()