diff --git a/CHANGES b/CHANGES index 284c95d0..a8543e6c 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ Version 1.0 (release date to be announced, codename to be selected) +- Added before_render_template signal. - Added `**kwargs` to :meth:`flask.Test.test_client` to support passing additional keyword arguments to the constructor of :attr:`flask.Flask.test_client_class`. diff --git a/docs/api.rst b/docs/api.rst index 69ef38b5..70be5ca2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -538,6 +538,23 @@ The following signals exist in Flask: from flask import template_rendered template_rendered.connect(log_template_renders, app) +.. data:: flask.before_render_template + :noindex: + + This signal is sent before template rendering process. The + signal is invoked with the instance of the template as `template` + and the context as dictionary (named `context`). + + Example subscriber:: + + def log_template_renders(sender, template, context, **extra): + sender.logger.debug('Rendering template "%s" with context %s', + template.name or 'string template', + context) + + from flask import before_render_template + before_render_template.connect(log_template_renders, app) + .. data:: request_started This signal is sent when the request context is set up, before diff --git a/flask/__init__.py b/flask/__init__.py index a6ef98ca..7fd7a253 100644 --- a/flask/__init__.py +++ b/flask/__init__.py @@ -34,7 +34,7 @@ from .templating import render_template, render_template_string from .signals import signals_available, template_rendered, request_started, \ request_finished, got_request_exception, request_tearing_down, \ appcontext_tearing_down, appcontext_pushed, \ - appcontext_popped, message_flashed + appcontext_popped, message_flashed, before_render_template # We're not exposing the actual json module but a convenient wrapper around # it. diff --git a/flask/signals.py b/flask/signals.py index ca1c1d90..c9b8a210 100644 --- a/flask/signals.py +++ b/flask/signals.py @@ -45,6 +45,7 @@ _signals = Namespace() # Core signals. For usage examples grep the source code or consult # the API documentation in docs/api.rst as well as docs/signals.rst template_rendered = _signals.signal('template-rendered') +before_render_template = _signals.signal('before-render-template') request_started = _signals.signal('request-started') request_finished = _signals.signal('request-finished') request_tearing_down = _signals.signal('request-tearing-down') diff --git a/flask/templating.py b/flask/templating.py index 1e39b932..59fd988e 100644 --- a/flask/templating.py +++ b/flask/templating.py @@ -12,7 +12,7 @@ from jinja2 import BaseLoader, Environment as BaseEnvironment, \ TemplateNotFound from .globals import _request_ctx_stack, _app_ctx_stack -from .signals import template_rendered +from .signals import template_rendered, before_render_template def _default_template_ctx_processor(): @@ -102,6 +102,8 @@ class DispatchingJinjaLoader(BaseLoader): def _render(template, context, app): """Renders the template and fires the signal""" + + before_render_template.send(app, template=template, context=context) rv = template.render(context) template_rendered.send(app, template=template, context=context) return rv diff --git a/tests/test_signals.py b/tests/test_signals.py index e17acfd4..b687b6e8 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -46,6 +46,30 @@ def test_template_rendered(): finally: flask.template_rendered.disconnect(record, app) +def test_before_render_template(): + app = flask.Flask(__name__) + + @app.route('/') + def index(): + return flask.render_template('simple_template.html', whiskey=42) + + recorded = [] + + def record(sender, template, context): + context['whiskey'] = 43 + recorded.append((template, context)) + + flask.before_render_template.connect(record, app) + try: + rv = app.test_client().get('/') + assert len(recorded) == 1 + template, context = recorded[0] + assert template.name == 'simple_template.html' + assert context['whiskey'] == 43 + assert rv.data == b'

43

' + finally: + flask.before_render_template.disconnect(record, app) + def test_request_signals(): app = flask.Flask(__name__) calls = []