Browse Source

Added appcontext_pushed and appcontext_popped signals

pull/764/head
Armin Ronacher 11 years ago
parent
commit
0676bb8ab5
  1. 1
      CHANGES
  2. 17
      docs/api.rst
  3. 39
      docs/signals.rst
  4. 3
      flask/__init__.py
  5. 3
      flask/ctx.py
  6. 2
      flask/signals.py
  7. 24
      flask/testsuite/signals.py

1
CHANGES

@ -70,6 +70,7 @@ Release date to be decided.
- Added the ``JSONIFY_PRETTYPRINT_REGULAR`` configuration variable.
- Flask now orders JSON keys by default to not trash HTTP caches due to
different hash seeds between different workers.
- Added `appcontext_pushed` and `appcontext_popped` signals.
Version 0.9
-----------

17
docs/api.rst

@ -535,7 +535,22 @@ Signals
This signal is sent when the application is tearing down the
application context. This is always called, even if an error happened.
An `exc` keyword argument is passed with the exception that caused the
teardown.
teardown. The sender is the application.
.. data:: appcontext_pushed
This signal is sent when an application context is pushed. The sender
is the application.
.. versionadded:: 0.10
.. data:: appcontext_popped
This signal is sent when an application context is popped. The sender
is the application. This usually falls in line with the
:data:`appcontext_tearing_down` signal.
.. versionadded:: 0.10
.. data:: message_flashed

39
docs/signals.rst

@ -291,6 +291,45 @@ The following signals exist in Flask:
This will also be passed an `exc` keyword argument that has a reference
to the exception that caused the teardown if there was one.
.. data:: flask.appcontext_pushed
:noindex:
This signal is sent when an application context is pushed. The sender
is the application. This is usually useful for unittests in order to
temporarily hook in information. For instance it can be used to
set a resource early onto the `g` object.
Example usage::
from contextlib import contextmanager
from flask import appcontext_pushed
@contextmanager
def user_set(app, user):
def handler(sender, **kwargs):
g.user = user
with appcontext_pushed.connected_to(handler, app):
yield
And in the testcode::
def test_user_me(self):
with user_set(app, 'john'):
c = app.test_client()
resp = c.get('/users/me')
assert resp.data == 'username=john'
.. versionadded:: 0.10
.. data:: appcontext_popped
This signal is sent when an application context is popped. The sender
is the application. This usually falls in line with the
:data:`appcontext_tearing_down` signal.
.. versionadded:: 0.10
.. data:: flask.message_flashed
:noindex:

3
flask/__init__.py

@ -34,7 +34,8 @@ from .templating import render_template, render_template_string
# the signals
from .signals import signals_available, template_rendered, request_started, \
request_finished, got_request_exception, request_tearing_down, \
appcontext_tearing_down, message_flashed
appcontext_tearing_down, appcontext_pushed, \
appcontext_popped, message_flashed
# We're not exposing the actual json module but a convenient wrapper around
# it.

3
flask/ctx.py

@ -18,6 +18,7 @@ from werkzeug.exceptions import HTTPException
from .globals import _request_ctx_stack, _app_ctx_stack
from .module import blueprint_is_module
from .signals import appcontext_pushed, appcontext_popped
class _AppCtxGlobals(object):
@ -166,6 +167,7 @@ class AppContext(object):
"""Binds the app context to the current context."""
self._refcnt += 1
_app_ctx_stack.push(self)
appcontext_pushed.send(self.app)
def pop(self, exc=None):
"""Pops the app context."""
@ -177,6 +179,7 @@ class AppContext(object):
rv = _app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
appcontext_popped.send(self.app)
def __enter__(self):
self.push()

2
flask/signals.py

@ -50,4 +50,6 @@ request_finished = _signals.signal('request-finished')
request_tearing_down = _signals.signal('request-tearing-down')
got_request_exception = _signals.signal('got-request-exception')
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')
appcontext_pushed = _signals.signal('appcontext-pushed')
appcontext_popped = _signals.signal('appcontext-popped')
message_flashed = _signals.signal('message-flashed')

24
flask/testsuite/signals.py

@ -96,6 +96,30 @@ class SignalsTestCase(FlaskTestCase):
finally:
flask.got_request_exception.disconnect(record, app)
def test_appcontext_signals(self):
app = flask.Flask(__name__)
recorded = []
def record_push(sender, **kwargs):
recorded.append('push')
def record_pop(sender, **kwargs):
recorded.append('push')
@app.route('/')
def index():
return 'Hello'
flask.appcontext_pushed.connect(record_push, app)
flask.appcontext_popped.connect(record_pop, app)
try:
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, b'Hello')
self.assert_equal(recorded, ['push'])
self.assert_equal(recorded, ['push', 'pop'])
finally:
flask.appcontext_pushed.disconnect(record_push, app)
flask.appcontext_popped.disconnect(record_pop, app)
def test_flash_signal(self):
app = flask.Flask(__name__)
app.config['SECRET_KEY'] = 'secret'

Loading…
Cancel
Save