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).
This commit is contained in:
@@ -163,6 +163,13 @@ Pecan also comes with ``abort``, a utility function for raising HTTP errors:
|
|||||||
abort(404)
|
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``
|
Routing to Subcontrollers with ``_lookup``
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -545,6 +545,7 @@ class Pecan(object):
|
|||||||
# if this is an HTTP Exception, set it as the response
|
# if this is an HTTP Exception, set it as the response
|
||||||
if isinstance(e, exc.HTTPException):
|
if isinstance(e, exc.HTTPException):
|
||||||
state.response = e
|
state.response = e
|
||||||
|
environ['pecan.original_exception'] = e
|
||||||
|
|
||||||
# if this is not an internal redirect, run error hooks
|
# if this is not an internal redirect, run error hooks
|
||||||
if not isinstance(e, ForwardRequestException):
|
if not isinstance(e, ForwardRequestException):
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
from webtest import TestApp
|
from webtest import TestApp
|
||||||
|
|
||||||
|
import pecan
|
||||||
from pecan.middleware.errordocument import ErrorDocumentMiddleware
|
from pecan.middleware.errordocument import ErrorDocumentMiddleware
|
||||||
from pecan.middleware.recursive import RecursiveMiddleware
|
from pecan.middleware.recursive import RecursiveMiddleware
|
||||||
from pecan.tests import PecanTestCase
|
from pecan.tests import PecanTestCase
|
||||||
@@ -52,3 +55,36 @@ class TestErrorDocumentMiddleware(PecanTestCase):
|
|||||||
assert r.status_int == 404
|
assert r.status_int == 404
|
||||||
assert r.body == ('Error: 404 Not Found. '
|
assert r.body == ('Error: 404 Not Found. '
|
||||||
'(Error page could not be fetched)')
|
'(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!'
|
||||||
|
|||||||
Reference in New Issue
Block a user