summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-10-21 16:02:24 +0000
committerChris McDonough <chrism@agendaless.com>2009-10-21 16:02:24 +0000
commitef5149051623da25d24002132828c658b6dcfee4 (patch)
treed608e7156cf2a3b6214951f9cce0f43d185e59ea /repoze
parent7c28d427199a5d2129c129be8f3260cb6bd9f7b0 (diff)
downloadpyramid-ef5149051623da25d24002132828c658b6dcfee4.tar.gz
pyramid-ef5149051623da25d24002132828c658b6dcfee4.tar.bz2
pyramid-ef5149051623da25d24002132828c658b6dcfee4.zip
Add Respond exception.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/exceptions.py26
-rw-r--r--repoze/bfg/router.py3
-rw-r--r--repoze/bfg/tests/test_router.py30
3 files changed, 56 insertions, 3 deletions
diff --git a/repoze/bfg/exceptions.py b/repoze/bfg/exceptions.py
index afd617a2c..bc05fa699 100644
--- a/repoze/bfg/exceptions.py
+++ b/repoze/bfg/exceptions.py
@@ -22,3 +22,29 @@ class NotFound(Exception):
into the WSGI environment under the ``repoze.bfg.message`` key,
for availability to the Not Found view."""
+class Respond(Exception):
+ """\
+ Raise this exception during view execution to return a response
+ immediately without proceeeding any further through the codepath.
+ Use of this exception is effectively a 'goto': its target is the
+ exception handler within the :mod:`repoze.bfg' router that catches
+ the exception and returns a response immediately. Note that
+ because this exception is caught by the router, it will not
+ propagate to any WSGI middleware. Note that this exception is
+ typically only used by the framework itself and by authentication
+ plugins to the framework.
+
+ The exception must be initialized which a single argument, which
+ is a :term:`response` object.
+
+ An example:
+
+ .. code-block:: python
+ :linenos:
+
+ from webob.exc import HTTPFound
+ from repoze.bfg.exceptions import Respond
+ response = HTTPFound(location='http://example.com')
+ raise Respond(response)
+ """
+
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index 1b894129b..c87065e14 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -19,6 +19,7 @@ from repoze.bfg.events import NewResponse
from repoze.bfg.events import WSGIApplicationCreatedEvent
from repoze.bfg.exceptions import Forbidden
from repoze.bfg.exceptions import NotFound
+from repoze.bfg.exceptions import Respond
from repoze.bfg.request import request_factory
from repoze.bfg.threadlocal import manager
from repoze.bfg.traversal import ModelGraphTraverser
@@ -115,6 +116,8 @@ class Router(object):
environ = getattr(request, 'environ', {})
environ['repoze.bfg.message'] = msg
response = self.notfound_view(context, request)
+ except Respond, why:
+ response = why[0]
registry.has_listeners and registry.notify(NewResponse(response))
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 151734b9b..76b33d204 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -334,7 +334,7 @@ class TestRouter(unittest.TestCase):
self.assertEqual(start_response.status, '404 Not Found')
self.failUnless('404' in result[0])
- def test_call_view_raises_unauthorized(self):
+ def test_call_view_raises_forbidden(self):
from zope.interface import Interface
from zope.interface import directlyProvides
class IContext(Interface):
@@ -372,6 +372,25 @@ class TestRouter(unittest.TestCase):
self.assertEqual(start_response.status, '404 Not Found')
self.assertEqual(environ['repoze.bfg.message'], 'notfound')
+ def test_call_view_raises_respond(self):
+ from zope.interface import Interface
+ from zope.interface import directlyProvides
+ class IContext(Interface):
+ pass
+ from repoze.bfg.interfaces import IRequest
+ context = DummyContext()
+ directlyProvides(context, IContext)
+ self._registerTraverserFactory(context, subpath=[''])
+ response = DummyResponse('200 OK')
+ raised = DummyResponse('201 Created')
+ view = DummyView(response, raise_respond=raised)
+ environ = self._makeEnviron()
+ self._registerView(view, '', IContext, IRequest)
+ router = self._makeOne()
+ start_response = DummyStartResponse()
+ response = router(environ, start_response)
+ self.assertEqual(start_response.status, '201 Created')
+
def test_call_eventsends(self):
context = DummyContext()
self._registerTraverserFactory(context)
@@ -466,10 +485,11 @@ class DummyContext:
class DummyView:
def __init__(self, response, raise_unauthorized=False,
- raise_notfound=False):
+ raise_notfound=False, raise_respond=False):
self.response = response
self.raise_unauthorized = raise_unauthorized
self.raise_notfound = raise_notfound
+ self.raise_respond = raise_respond
def __call__(self, context, request):
if self.raise_unauthorized:
@@ -478,6 +498,9 @@ class DummyView:
if self.raise_notfound:
from repoze.bfg.exceptions import NotFound
raise NotFound('notfound')
+ if self.raise_respond:
+ from repoze.bfg.exceptions import Respond
+ raise Respond(self.raise_respond)
return self.response
class DummyRootFactory:
@@ -495,9 +518,10 @@ class DummyStartResponse:
self.headers = headers
class DummyResponse:
- status = '200 OK'
headerlist = ()
app_iter = ()
+ def __init__(self, status='200 OK'):
+ self.status = status
class DummyThreadLocalManager:
def __init__(self):