Browse Source

Invoke after_request on exceptions as well. This fixes #59

pull/124/head
Armin Ronacher 15 years ago
parent
commit
33e7f2b990
  1. 13
      flask.py
  2. 32
      tests/flask_tests.py

13
flask.py

@ -1362,6 +1362,12 @@ class Flask(_PackageBoundObject):
Then you still have the original application object around and Then you still have the original application object around and
can continue to call methods on it. can continue to call methods on it.
.. versionchanged:: 0.4
The :meth:`after_request` functions are now called even if an
error handler took over request processing. This ensures that
even if an exception happens database have the chance to
properly close the connection.
:param environ: a WSGI environment :param environ: a WSGI environment
:param start_response: a callable accepting a status code, :param start_response: a callable accepting a status code,
a list of headers and an optional a list of headers and an optional
@ -1376,6 +1382,13 @@ class Flask(_PackageBoundObject):
response = self.process_response(response) response = self.process_response(response)
except Exception, e: except Exception, e:
response = self.make_response(self.handle_exception(e)) response = self.make_response(self.handle_exception(e))
try:
response = self.process_response(response)
except Exception, e:
self.logger.exception('after_request handler failed '
'to postprocess error response. '
'Depending on uncertain state?')
return response(environ, start_response) return response(environ, start_response)
def request_context(self, environ): def request_context(self, environ):

32
tests/flask_tests.py

@ -16,6 +16,7 @@ import sys
import flask import flask
import unittest import unittest
import tempfile import tempfile
from logging import StreamHandler
from contextlib import contextmanager from contextlib import contextmanager
from datetime import datetime from datetime import datetime
from werkzeug import parse_date, parse_options_header from werkzeug import parse_date, parse_options_header
@ -240,6 +241,37 @@ class BasicFunctionalityTestCase(unittest.TestCase):
assert 'after' in evts assert 'after' in evts
assert rv == 'request|after' assert rv == 'request|after'
def test_after_request_errors(self):
app = flask.Flask(__name__)
called = []
@app.after_request
def after_request(response):
called.append(True)
return response
@app.route('/')
def fails():
1/0
rv = app.test_client().get('/')
assert rv.status_code == 500
assert 'Internal Server Error' in rv.data
assert len(called) == 1
def test_after_request_handler_error(self):
error_out = StringIO()
app = flask.Flask(__name__)
app.logger.addHandler(StreamHandler(error_out))
@app.after_request
def after_request(response):
1/0
return response
@app.route('/')
def fails():
1/0
rv = app.test_client().get('/')
assert rv.status_code == 500
assert 'Internal Server Error' in rv.data
assert 'after_request handler failed' in error_out.getvalue()
def test_error_handling(self): def test_error_handling(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.errorhandler(404) @app.errorhandler(404)

Loading…
Cancel
Save