From b5d69b5624f3e359c3c0c898e2b2dd23f85af01b Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Tue, 9 Apr 2013 14:00:16 -0400 Subject: Store exceptions raised by ``abort`` in the WSGI environ. This makes it easier to access the original exception later in the request cycle (e.g., other middleware or in custom error handlers). --- docs/source/routing.rst | 7 ++++++ pecan/core.py | 1 + pecan/tests/middleware/test_errordocument.py | 36 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/docs/source/routing.rst b/docs/source/routing.rst index e27baf6..6ed3524 100644 --- a/docs/source/routing.rst +++ b/docs/source/routing.rst @@ -163,6 +163,13 @@ Pecan also comes with ``abort``, a utility function for raising HTTP errors: abort(404) +Under the hood, ``abort`` raises an instance of +``webob.exc.WSGIHTTPException`` which is used by pecan to render default +response bodies for HTTP errors. This exception is stored in the WSGI request +environ at ``pecan.original_exception``, where it can be accessed later in the +request cycle (by, for example, other middleware or :ref:`errors`). + + Routing to Subcontrollers with ``_lookup`` ------------------------------------------ diff --git a/pecan/core.py b/pecan/core.py index 5897988..e4fdd99 100644 --- a/pecan/core.py +++ b/pecan/core.py @@ -545,6 +545,7 @@ class Pecan(object): # if this is an HTTP Exception, set it as the response if isinstance(e, exc.HTTPException): state.response = e + environ['pecan.original_exception'] = e # if this is not an internal redirect, run error hooks if not isinstance(e, ForwardRequestException): diff --git a/pecan/tests/middleware/test_errordocument.py b/pecan/tests/middleware/test_errordocument.py index 92c4c08..c4faa42 100644 --- a/pecan/tests/middleware/test_errordocument.py +++ b/pecan/tests/middleware/test_errordocument.py @@ -1,5 +1,8 @@ +import json + from webtest import TestApp +import pecan from pecan.middleware.errordocument import ErrorDocumentMiddleware from pecan.middleware.recursive import RecursiveMiddleware from pecan.tests import PecanTestCase @@ -52,3 +55,36 @@ class TestErrorDocumentMiddleware(PecanTestCase): assert r.status_int == 404 assert r.body == ('Error: 404 Not Found. ' '(Error page could not be fetched)') + + def test_original_exception(self): + + class RootController(object): + + @pecan.expose() + def index(self): + if pecan.request.method != 'POST': + pecan.abort(405, 'You have to POST, dummy!') + return 'Hello, World!' + + @pecan.expose('json') + def error(self, status): + return dict( + status=int(status), + reason=pecan.request.environ[ + 'pecan.original_exception' + ].detail + ) + + app = pecan.Pecan(RootController()) + app = RecursiveMiddleware(ErrorDocumentMiddleware(app, { + 405: '/error/405' + })) + app = TestApp(app) + + assert app.post('/').status_int == 200 + r = app.get('/', expect_errors=405) + assert r.status_int == 405 + + resp = json.loads(r.body) + assert resp['status'] == 405 + assert resp['reason'] == 'You have to POST, dummy!' -- cgit v1.2.1