Added the ability to trigger functions before the first request to the application
This commit is contained in:
parent
5500986971
commit
02a1317460
4 changed files with 74 additions and 2 deletions
2
CHANGES
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
|
- 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
|
was attached after the first request was handled. This gives earlier
|
||||||
feedback when users forget to import view code ahead of time.
|
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
|
Version 0.7.3
|
||||||
-------------
|
-------------
|
||||||
|
|
|
||||||
52
flask/app.py
52
flask/app.py
|
|
@ -291,6 +291,13 @@ class Flask(_PackageBoundObject):
|
||||||
#: function here, use the :meth:`before_request` decorator.
|
#: function here, use the :meth:`before_request` decorator.
|
||||||
self.before_request_funcs = {}
|
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
|
#: A dictionary with lists of functions that should be called after
|
||||||
#: each request. The key of the dictionary is the name of the blueprint
|
#: 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
|
#: 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
|
# tracks internally if the application already handled at least one
|
||||||
# request.
|
# request.
|
||||||
self._got_first_request = False
|
self._got_first_request = False
|
||||||
|
self._before_request_lock = Lock()
|
||||||
|
|
||||||
# register the static folder for the application. Do that even
|
# register the static folder for the application. Do that even
|
||||||
# if the folder does not exist. First of all it might be created
|
# if the folder does not exist. First of all it might be created
|
||||||
|
|
@ -474,6 +482,15 @@ class Flask(_PackageBoundObject):
|
||||||
|
|
||||||
return rv
|
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):
|
def create_jinja_environment(self):
|
||||||
"""Creates the Jinja2 environment based on :attr:`jinja_options`
|
"""Creates the Jinja2 environment based on :attr:`jinja_options`
|
||||||
and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
|
and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
|
||||||
|
|
@ -581,7 +598,13 @@ class Flask(_PackageBoundObject):
|
||||||
self.debug = options.pop('debug')
|
self.debug = options.pop('debug')
|
||||||
options.setdefault('use_reloader', self.debug)
|
options.setdefault('use_reloader', self.debug)
|
||||||
options.setdefault('use_debugger', 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):
|
def test_client(self, use_cookies=True):
|
||||||
"""Creates a test client for this application. For information
|
"""Creates a test client for this application. For information
|
||||||
|
|
@ -940,6 +963,15 @@ class Flask(_PackageBoundObject):
|
||||||
self.before_request_funcs.setdefault(None, []).append(f)
|
self.before_request_funcs.setdefault(None, []).append(f)
|
||||||
return 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
|
@setupmethod
|
||||||
def after_request(self, f):
|
def after_request(self, f):
|
||||||
"""Register a function to be run after each request. Your function
|
"""Register a function to be run after each request. Your function
|
||||||
|
|
@ -1131,7 +1163,7 @@ class Flask(_PackageBoundObject):
|
||||||
|
|
||||||
.. versionadded:: 0.7
|
.. versionadded:: 0.7
|
||||||
"""
|
"""
|
||||||
self._got_first_request = True
|
self.try_trigger_before_first_request_functions()
|
||||||
try:
|
try:
|
||||||
request_started.send(self)
|
request_started.send(self)
|
||||||
rv = self.preprocess_request()
|
rv = self.preprocess_request()
|
||||||
|
|
@ -1144,6 +1176,22 @@ class Flask(_PackageBoundObject):
|
||||||
request_finished.send(self, response=response)
|
request_finished.send(self, response=response)
|
||||||
return 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):
|
def make_default_options_response(self):
|
||||||
"""This method is called to create the default `OPTIONS` response.
|
"""This method is called to create the default `OPTIONS` response.
|
||||||
This can be changed through subclassing to change the default
|
This can be changed through subclassing to change the default
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,13 @@ class Blueprint(_PackageBoundObject):
|
||||||
.setdefault(None, []).append(f))
|
.setdefault(None, []).append(f))
|
||||||
return 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):
|
def after_request(self, f):
|
||||||
"""Like :meth:`Flask.after_request` but for a blueprint. This function
|
"""Like :meth:`Flask.after_request` but for a blueprint. This function
|
||||||
is only executed after each request that is handled by a function of
|
is only executed after each request that is handled by a function of
|
||||||
|
|
|
||||||
|
|
@ -950,6 +950,7 @@ class BasicFunctionalityTestCase(unittest.TestCase):
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
return 'Awesome'
|
return 'Awesome'
|
||||||
|
self.assert_(not app.got_first_request)
|
||||||
self.assertEqual(app.test_client().get('/').data, 'Awesome')
|
self.assertEqual(app.test_client().get('/').data, 'Awesome')
|
||||||
try:
|
try:
|
||||||
@app.route('/foo')
|
@app.route('/foo')
|
||||||
|
|
@ -965,6 +966,20 @@ class BasicFunctionalityTestCase(unittest.TestCase):
|
||||||
def working():
|
def working():
|
||||||
return 'Meh'
|
return 'Meh'
|
||||||
self.assertEqual(app.test_client().get('/foo').data, '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):
|
class JSONTestCase(unittest.TestCase):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue