diff --git a/flask/app.py b/flask/app.py index fb791f33..63faa5e2 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1484,8 +1484,10 @@ class Flask(_PackageBoundObject): Since a request context typically also manages an application context it would also be called when you pop a request context. - When a teardown function was called because of an exception it will - be passed an error object. + When a teardown function was called because of an unhandled exception + it will be passed an error object. Note that if a :meth:`errorhandler` + is registered, it will handle the exception and the teardown will not + receive it. The return values of teardown functions are ignored. diff --git a/tests/test_appctx.py b/tests/test_appctx.py index 7ef7b479..bf3474e9 100644 --- a/tests/test_appctx.py +++ b/tests/test_appctx.py @@ -81,7 +81,7 @@ def test_app_tearing_down_with_previous_exception(app): assert cleanup_stuff == [None] -def test_app_tearing_down_with_handled_exception(app): +def test_app_tearing_down_with_handled_exception_by_except_block(app): cleanup_stuff = [] @app.teardown_appcontext @@ -97,6 +97,57 @@ def test_app_tearing_down_with_handled_exception(app): assert cleanup_stuff == [None] +def test_app_tearing_down_with_handled_exception_by_app_handler(app): + cleanup_stuff = [] + + class AppConfig(): + PROPAGATE_EXCEPTIONS = True + app.config.from_object(AppConfig()) + + @app.teardown_appcontext + def cleanup(exception): + cleanup_stuff.append(exception) + + @app.route('/') + def index(): + raise Exception('dummy') + + @app.errorhandler(Exception) + def handler(f): + return flask.jsonify(str(f)) + + test_client = app.test_client() + with app.app_context(): + test_client.get('/') + + assert cleanup_stuff == [None] + + +def test_app_tearing_down_with_unhandled_exception(app): + cleanup_stuff = [] + + class AppConfig(): + PROPAGATE_EXCEPTIONS = True + app.config.from_object(AppConfig()) + + @app.teardown_appcontext + def cleanup(exception): + cleanup_stuff.append(exception) + + @app.route('/') + def index(): + raise Exception('dummy') + + test_client = app.test_client() + with pytest.raises(Exception): + with app.app_context(): + test_client.get('/') + + assert len(cleanup_stuff) == 1 + assert isinstance(cleanup_stuff[0], Exception) + assert str(cleanup_stuff[0]) == 'dummy' + + def test_app_ctx_globals_methods(app, app_ctx): # get assert flask.g.get('foo') is None