mirror of https://github.com/pallets/flask.git
Added the ability to trigger functions before the first request to the application
This commit is contained in:
parent
5500986971
commit
02a1317460
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
|
||||
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
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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…
Reference in New Issue