Browse Source

Added after_this_request decorator.

pull/502/merge
Armin Ronacher 13 years ago
parent
commit
086348e2f2
  1. 1
      CHANGES
  2. 2
      docs/api.rst
  3. 3
      flask/__init__.py
  4. 2
      flask/app.py
  5. 30
      flask/ctx.py
  6. 15
      flask/testsuite/basic.py

1
CHANGES

@ -70,6 +70,7 @@ Relase date to be decided, codename to be chosen.
be used on creation of the :data:`~flask.g` instance of each request. be used on creation of the :data:`~flask.g` instance of each request.
- Added `required_methods` attribute to view functions to force-add methods - Added `required_methods` attribute to view functions to force-add methods
on registration. on registration.
- Added :func:`flask.after_this_request`.
Version 0.8.1 Version 0.8.1
------------- -------------

2
docs/api.rst

@ -289,6 +289,8 @@ Useful Functions and Classes
.. autofunction:: make_response .. autofunction:: make_response
.. autofunction:: after_this_request
.. autofunction:: send_file .. autofunction:: send_file
.. autofunction:: send_from_directory .. autofunction:: send_from_directory

3
flask/__init__.py

@ -25,7 +25,8 @@ from .helpers import url_for, jsonify, json_available, flash, \
get_template_attribute, make_response, safe_join get_template_attribute, make_response, safe_join
from .globals import current_app, g, request, session, _request_ctx_stack, \ from .globals import current_app, g, request, session, _request_ctx_stack, \
_app_ctx_stack _app_ctx_stack
from .ctx import has_request_context, has_app_context from .ctx import has_request_context, has_app_context, \
after_this_request
from .module import Module from .module import Module
from .blueprints import Blueprint from .blueprints import Blueprint
from .templating import render_template, render_template_string from .templating import render_template, render_template_string

2
flask/app.py

@ -1555,7 +1555,7 @@ class Flask(_PackageBoundObject):
""" """
ctx = _request_ctx_stack.top ctx = _request_ctx_stack.top
bp = ctx.request.blueprint bp = ctx.request.blueprint
funcs = () funcs = ctx._after_request_functions
if bp is not None and bp in self.after_request_funcs: if bp is not None and bp in self.after_request_funcs:
funcs = reversed(self.after_request_funcs[bp]) funcs = reversed(self.after_request_funcs[bp])
if None in self.after_request_funcs: if None in self.after_request_funcs:

30
flask/ctx.py

@ -11,6 +11,7 @@
import sys import sys
from functools import partial
from werkzeug.exceptions import HTTPException from werkzeug.exceptions import HTTPException
from .globals import _request_ctx_stack, _app_ctx_stack from .globals import _request_ctx_stack, _app_ctx_stack
@ -30,6 +31,31 @@ def _push_app_if_necessary(app):
return ctx return ctx
def after_this_request(f):
"""Executes a function after this request. This is useful to modify
response objects. The function is passed the response object and has
to return the same or a new one.
Example::
@app.route('/')
def index():
@after_this_request
def add_header():
response.headers['X-Foo'] = 'Parachute'
return response
return 'Hello World!'
This is more useful if a function other than the view function wants to
modify a response. For instance think of a decorator that wants to add
some headers without converting the return value into a response object.
.. versionadded:: 0.9
"""
_request_ctx_stack.top._after_request_functions.append(f)
return f
def has_request_context(): def has_request_context():
"""If you have code that wants to test if a request context is there or """If you have code that wants to test if a request context is there or
not this function can be used. For instance, you may want to take advantage not this function can be used. For instance, you may want to take advantage
@ -153,6 +179,10 @@ class RequestContext(object):
# context, it will be stored there # context, it will be stored there
self._pushed_application_context = None self._pushed_application_context = None
# Functions that should be executed after the request on the response
# object. These will even be called in case of an error.
self._after_request_functions = []
self.match_request() self.match_request()
# XXX: Support for deprecated functionality. This is going away with # XXX: Support for deprecated functionality. This is going away with

15
flask/testsuite/basic.py

@ -411,6 +411,21 @@ class BasicFunctionalityTestCase(FlaskTestCase):
self.assert_('after' in evts) self.assert_('after' in evts)
self.assert_equal(rv, 'request|after') self.assert_equal(rv, 'request|after')
def test_after_request_processing(self):
app = flask.Flask(__name__)
app.testing = True
@app.route('/')
def index():
@flask.after_this_request
def foo(response):
response.headers['X-Foo'] = 'a header'
return response
return 'Test'
c = app.test_client()
resp = c.get('/')
self.assertEqual(resp.status_code, 200)
self.assertEqual(resp.headers['X-Foo'], 'a header')
def test_teardown_request_handler(self): def test_teardown_request_handler(self):
called = [] called = []
app = flask.Flask(__name__) app = flask.Flask(__name__)

Loading…
Cancel
Save