mirror of https://github.com/pallets/flask.git
Improve application context popping
Exceptions during teardown handling will no longer leave application contexts lingering around. This fixes #1767
This commit is contained in:
parent
87787b130b
commit
8482ce6b8c
2
CHANGES
2
CHANGES
|
@ -77,6 +77,8 @@ Version 0.11
|
||||||
- ``send_from_directory`` now raises BadRequest if the filename is invalid on
|
- ``send_from_directory`` now raises BadRequest if the filename is invalid on
|
||||||
the server OS (pull request ``#1763``).
|
the server OS (pull request ``#1763``).
|
||||||
- Added the ``JSONIFY_MIMETYPE`` configuration variable (pull request ``#1728``).
|
- Added the ``JSONIFY_MIMETYPE`` configuration variable (pull request ``#1728``).
|
||||||
|
- Exceptions during teardown handling will no longer leave bad application
|
||||||
|
contexts lingering around.
|
||||||
|
|
||||||
Version 0.10.2
|
Version 0.10.2
|
||||||
--------------
|
--------------
|
||||||
|
|
10
flask/ctx.py
10
flask/ctx.py
|
@ -181,11 +181,13 @@ class AppContext(object):
|
||||||
|
|
||||||
def pop(self, exc=_sentinel):
|
def pop(self, exc=_sentinel):
|
||||||
"""Pops the app context."""
|
"""Pops the app context."""
|
||||||
|
try:
|
||||||
self._refcnt -= 1
|
self._refcnt -= 1
|
||||||
if self._refcnt <= 0:
|
if self._refcnt <= 0:
|
||||||
if exc is _sentinel:
|
if exc is _sentinel:
|
||||||
exc = sys.exc_info()[1]
|
exc = sys.exc_info()[1]
|
||||||
self.app.do_teardown_appcontext(exc)
|
self.app.do_teardown_appcontext(exc)
|
||||||
|
finally:
|
||||||
rv = _app_ctx_stack.pop()
|
rv = _app_ctx_stack.pop()
|
||||||
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
|
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
|
||||||
% (rv, self)
|
% (rv, self)
|
||||||
|
@ -341,6 +343,7 @@ class RequestContext(object):
|
||||||
"""
|
"""
|
||||||
app_ctx = self._implicit_app_ctx_stack.pop()
|
app_ctx = self._implicit_app_ctx_stack.pop()
|
||||||
|
|
||||||
|
try:
|
||||||
clear_request = False
|
clear_request = False
|
||||||
if not self._implicit_app_ctx_stack:
|
if not self._implicit_app_ctx_stack:
|
||||||
self.preserved = False
|
self.preserved = False
|
||||||
|
@ -360,10 +363,8 @@ class RequestContext(object):
|
||||||
if request_close is not None:
|
if request_close is not None:
|
||||||
request_close()
|
request_close()
|
||||||
clear_request = True
|
clear_request = True
|
||||||
|
finally:
|
||||||
rv = _request_ctx_stack.pop()
|
rv = _request_ctx_stack.pop()
|
||||||
assert rv is self, 'Popped wrong request context. (%r instead of %r)' \
|
|
||||||
% (rv, self)
|
|
||||||
|
|
||||||
# get rid of circular dependencies at the end of the request
|
# get rid of circular dependencies at the end of the request
|
||||||
# so that we don't require the GC to be active.
|
# so that we don't require the GC to be active.
|
||||||
|
@ -374,6 +375,9 @@ class RequestContext(object):
|
||||||
if app_ctx is not None:
|
if app_ctx is not None:
|
||||||
app_ctx.pop(exc)
|
app_ctx.pop(exc)
|
||||||
|
|
||||||
|
assert rv is self, 'Popped wrong request context. ' \
|
||||||
|
'(%r instead of %r)' % (rv, self)
|
||||||
|
|
||||||
def auto_pop(self, exc):
|
def auto_pop(self, exc):
|
||||||
if self.request.environ.get('flask._preserve_context') or \
|
if self.request.environ.get('flask._preserve_context') or \
|
||||||
(exc is not None and self.app.preserve_context_on_exception):
|
(exc is not None and self.app.preserve_context_on_exception):
|
||||||
|
|
|
@ -146,3 +146,25 @@ def test_context_refcounts():
|
||||||
assert res.status_code == 200
|
assert res.status_code == 200
|
||||||
assert res.data == b''
|
assert res.data == b''
|
||||||
assert called == ['request', 'app']
|
assert called == ['request', 'app']
|
||||||
|
|
||||||
|
|
||||||
|
def test_clean_pop():
|
||||||
|
called = []
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
|
||||||
|
@app.teardown_request
|
||||||
|
def teardown_req(error=None):
|
||||||
|
1 / 0
|
||||||
|
|
||||||
|
@app.teardown_appcontext
|
||||||
|
def teardown_app(error=None):
|
||||||
|
called.append('TEARDOWN')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with app.test_request_context():
|
||||||
|
called.append(flask.current_app.name)
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert called == ['test_appctx', 'TEARDOWN']
|
||||||
|
assert not flask.current_app
|
||||||
|
|
Loading…
Reference in New Issue