Browse Source

Added the ability to trigger functions before the first request to the application

pull/300/head
Armin Ronacher 13 years ago
parent
commit
02a1317460
  1. 2
      CHANGES
  2. 52
      flask/app.py
  3. 7
      flask/blueprints.py
  4. 15
      tests/flask_tests.py

2
CHANGES

@ -21,6 +21,8 @@ Relase date to be decided, codename to be chosen.
- Flask in debug mode will now complain with an assertion error if a view
was attached after the first request was handled. This gives earlier
feedback when users forget to import view code ahead of time.
- Added the ability to register callbacks that are only triggered once at
the beginning of the first request. (:meth:`Flask.before_first_request`)
Version 0.7.3
-------------

52
flask/app.py

@ -291,6 +291,13 @@ class Flask(_PackageBoundObject):
#: function here, use the :meth:`before_request` decorator.
self.before_request_funcs = {}
#: A lists of functions that should be called at the beginning of the
#: first request to this instance. To register a function here, use
#: the :meth:`before_first_request` decorator.
#:
#: .. versionadded:: 0.8
self.before_first_request_funcs = []
#: A dictionary with lists of functions that should be called after
#: each request. The key of the dictionary is the name of the blueprint
#: this function is active for, `None` for all requests. This can for
@ -386,6 +393,7 @@ class Flask(_PackageBoundObject):
# tracks internally if the application already handled at least one
# request.
self._got_first_request = False
self._before_request_lock = Lock()
# register the static folder for the application. Do that even
# if the folder does not exist. First of all it might be created
@ -474,6 +482,15 @@ class Flask(_PackageBoundObject):
return rv
@property
def got_first_request(self):
"""This attribute is set to `True` if the application started
handling the first request.
.. versionadded:: 0.8
"""
return self._got_first_request
def create_jinja_environment(self):
"""Creates the Jinja2 environment based on :attr:`jinja_options`
and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
@ -581,7 +598,13 @@ class Flask(_PackageBoundObject):
self.debug = options.pop('debug')
options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
return run_simple(host, port, self, **options)
try:
run_simple(host, port, self, **options)
finally:
# reset the first request information if the development server
# resetted normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False
def test_client(self, use_cookies=True):
"""Creates a test client for this application. For information
@ -940,6 +963,15 @@ class Flask(_PackageBoundObject):
self.before_request_funcs.setdefault(None, []).append(f)
return f
@setupmethod
def before_first_request(self, f):
"""Registers a function to be run before the first request to this
instance of the application.
.. versionadded:: 0.8
"""
self.before_first_request_funcs.append(f)
@setupmethod
def after_request(self, f):
"""Register a function to be run after each request. Your function
@ -1131,7 +1163,7 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
self._got_first_request = True
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
rv = self.preprocess_request()
@ -1144,6 +1176,22 @@ class Flask(_PackageBoundObject):
request_finished.send(self, response=response)
return response
def try_trigger_before_first_request_functions(self):
"""Called before each request and will ensure that it triggers
the :attr:`before_first_request_funcs` and only exactly once per
application instance (which means process usually).
.. versionadded:: 0.8
"""
if self._got_first_request:
return
with self._before_request_lock:
if self._got_first_request:
return
self._got_first_request = True
for func in self.before_first_request_funcs:
func()
def make_default_options_response(self):
"""This method is called to create the default `OPTIONS` response.
This can be changed through subclassing to change the default

7
flask/blueprints.py

@ -199,6 +199,13 @@ class Blueprint(_PackageBoundObject):
.setdefault(None, []).append(f))
return f
def before_app_first_request(self, f):
"""Like :meth:`Flask.before_first_request`. Such a function is
executed before the first request to the application.
"""
self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
return f
def after_request(self, f):
"""Like :meth:`Flask.after_request` but for a blueprint. This function
is only executed after each request that is handled by a function of

15
tests/flask_tests.py

@ -950,6 +950,7 @@ class BasicFunctionalityTestCase(unittest.TestCase):
@app.route('/')
def index():
return 'Awesome'
self.assert_(not app.got_first_request)
self.assertEqual(app.test_client().get('/').data, 'Awesome')
try:
@app.route('/foo')
@ -965,6 +966,20 @@ class BasicFunctionalityTestCase(unittest.TestCase):
def working():
return 'Meh'
self.assertEqual(app.test_client().get('/foo').data, 'Meh')
self.assert_(app.got_first_request)
def test_before_first_request_functions(self):
got = []
app = flask.Flask(__name__)
@app.before_first_request
def foo():
got.append(42)
c = app.test_client()
c.get('/')
self.assertEqual(got, [42])
c.get('/')
self.assertEqual(got, [42])
self.assert_(app.got_first_request)
class JSONTestCase(unittest.TestCase):

Loading…
Cancel
Save