Skip to content

Commit 0676bb8

Browse files
committed
Added appcontext_pushed and appcontext_popped signals
1 parent fd99abe commit 0676bb8

File tree

7 files changed

+87
-2
lines changed

7 files changed

+87
-2
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Release date to be decided.
7070
- Added the ``JSONIFY_PRETTYPRINT_REGULAR`` configuration variable.
7171
- Flask now orders JSON keys by default to not trash HTTP caches due to
7272
different hash seeds between different workers.
73+
- Added `appcontext_pushed` and `appcontext_popped` signals.
7374

7475
Version 0.9
7576
-----------

docs/api.rst

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,22 @@ Signals
535535
This signal is sent when the application is tearing down the
536536
application context. This is always called, even if an error happened.
537537
An `exc` keyword argument is passed with the exception that caused the
538-
teardown.
538+
teardown. The sender is the application.
539+
540+
.. data:: appcontext_pushed
541+
542+
This signal is sent when an application context is pushed. The sender
543+
is the application.
544+
545+
.. versionadded:: 0.10
546+
547+
.. data:: appcontext_popped
548+
549+
This signal is sent when an application context is popped. The sender
550+
is the application. This usually falls in line with the
551+
:data:`appcontext_tearing_down` signal.
552+
553+
.. versionadded:: 0.10
539554

540555
.. data:: message_flashed
541556

docs/signals.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,45 @@ The following signals exist in Flask:
291291
This will also be passed an `exc` keyword argument that has a reference
292292
to the exception that caused the teardown if there was one.
293293

294+
.. data:: flask.appcontext_pushed
295+
:noindex:
296+
297+
This signal is sent when an application context is pushed. The sender
298+
is the application. This is usually useful for unittests in order to
299+
temporarily hook in information. For instance it can be used to
300+
set a resource early onto the `g` object.
301+
302+
Example usage::
303+
304+
from contextlib import contextmanager
305+
from flask import appcontext_pushed
306+
307+
@contextmanager
308+
def user_set(app, user):
309+
def handler(sender, **kwargs):
310+
g.user = user
311+
with appcontext_pushed.connected_to(handler, app):
312+
yield
313+
314+
And in the testcode::
315+
316+
def test_user_me(self):
317+
with user_set(app, 'john'):
318+
c = app.test_client()
319+
resp = c.get('/users/me')
320+
assert resp.data == 'username=john'
321+
322+
.. versionadded:: 0.10
323+
324+
.. data:: appcontext_popped
325+
326+
This signal is sent when an application context is popped. The sender
327+
is the application. This usually falls in line with the
328+
:data:`appcontext_tearing_down` signal.
329+
330+
.. versionadded:: 0.10
331+
332+
294333
.. data:: flask.message_flashed
295334
:noindex:
296335

flask/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
# the signals
3535
from .signals import signals_available, template_rendered, request_started, \
3636
request_finished, got_request_exception, request_tearing_down, \
37-
appcontext_tearing_down, message_flashed
37+
appcontext_tearing_down, appcontext_pushed, \
38+
appcontext_popped, message_flashed
3839

3940
# We're not exposing the actual json module but a convenient wrapper around
4041
# it.

flask/ctx.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from .globals import _request_ctx_stack, _app_ctx_stack
2020
from .module import blueprint_is_module
21+
from .signals import appcontext_pushed, appcontext_popped
2122

2223

2324
class _AppCtxGlobals(object):
@@ -166,6 +167,7 @@ def push(self):
166167
"""Binds the app context to the current context."""
167168
self._refcnt += 1
168169
_app_ctx_stack.push(self)
170+
appcontext_pushed.send(self.app)
169171

170172
def pop(self, exc=None):
171173
"""Pops the app context."""
@@ -177,6 +179,7 @@ def pop(self, exc=None):
177179
rv = _app_ctx_stack.pop()
178180
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
179181
% (rv, self)
182+
appcontext_popped.send(self.app)
180183

181184
def __enter__(self):
182185
self.push()

flask/signals.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,6 @@ def _fail(self, *args, **kwargs):
5050
request_tearing_down = _signals.signal('request-tearing-down')
5151
got_request_exception = _signals.signal('got-request-exception')
5252
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')
53+
appcontext_pushed = _signals.signal('appcontext-pushed')
54+
appcontext_popped = _signals.signal('appcontext-popped')
5355
message_flashed = _signals.signal('message-flashed')

flask/testsuite/signals.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,30 @@ def record(sender, exception):
9696
finally:
9797
flask.got_request_exception.disconnect(record, app)
9898

99+
def test_appcontext_signals(self):
100+
app = flask.Flask(__name__)
101+
recorded = []
102+
def record_push(sender, **kwargs):
103+
recorded.append('push')
104+
def record_pop(sender, **kwargs):
105+
recorded.append('push')
106+
107+
@app.route('/')
108+
def index():
109+
return 'Hello'
110+
111+
flask.appcontext_pushed.connect(record_push, app)
112+
flask.appcontext_popped.connect(record_pop, app)
113+
try:
114+
with app.test_client() as c:
115+
rv = c.get('/')
116+
self.assert_equal(rv.data, b'Hello')
117+
self.assert_equal(recorded, ['push'])
118+
self.assert_equal(recorded, ['push', 'pop'])
119+
finally:
120+
flask.appcontext_pushed.disconnect(record_push, app)
121+
flask.appcontext_popped.disconnect(record_pop, app)
122+
99123
def test_flash_signal(self):
100124
app = flask.Flask(__name__)
101125
app.config['SECRET_KEY'] = 'secret'

0 commit comments

Comments
 (0)