Merge pull request #3434 from pallets/eager-load

lazy load app on reload only
This commit is contained in:
David Lord 2019-11-18 18:22:38 -08:00 committed by GitHub
commit bfa9aceb03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 41 deletions

View file

@ -10,6 +10,9 @@ Unreleased
- Add :meth:`Config.from_file` to load config using arbitrary file - Add :meth:`Config.from_file` to load config using arbitrary file
loaders, such as ``toml.load`` or ``json.load``. loaders, such as ``toml.load`` or ``json.load``.
:meth:`Config.from_json` is deprecated in favor of this. :pr:`3398` :meth:`Config.from_json` is deprecated in favor of this. :pr:`3398`
- The ``flask run`` command will only defer errors on reload. Errors
present during the initial call will cause the server to exit with
the traceback immediately. :issue:`3431`
Version 1.1.2 Version 1.1.2

View file

@ -108,8 +108,8 @@ Old Version of Flask
Versions of Flask older than 0.11 use to have different ways to start the Versions of Flask older than 0.11 use to have different ways to start the
application. In short, the :command:`flask` command did not exist, and application. In short, the :command:`flask` command did not exist, and
neither did :command:`python -m flask`. In that case you have two options: neither did :command:`python -m flask`. In that case you have two options:
either upgrade to newer Flask versions or have a look at the :ref:`server` either upgrade to newer Flask versions or have a look at :doc:`/server`
docs to see the alternative method for running a server. to see the alternative method for running a server.
Invalid Import Name Invalid Import Name
``````````````````` ```````````````````
@ -153,7 +153,7 @@ This does the following things:
You can also control debug mode separately from the environment by You can also control debug mode separately from the environment by
exporting ``FLASK_DEBUG=1``. exporting ``FLASK_DEBUG=1``.
There are more parameters that are explained in the :ref:`server` docs. There are more parameters that are explained in :doc:`/server`.
.. admonition:: Attention .. admonition:: Attention

View file

@ -1,62 +1,89 @@
.. _server: .. currentmodule:: flask
Development Server Development Server
================== ==================
.. currentmodule:: flask Flask provides a ``run`` command to run the application with a
development server. In development mode, this server provides an
interactive debugger and will reload when code is changed.
Starting with Flask 0.11 there are multiple built-in ways to run a .. warning::
development server. The best one is the :command:`flask` command line utility
but you can also continue using the :meth:`Flask.run` method. Do not use the development server when deploying to production. It
is intended for use only during local development. It is not
designed to be particularly efficient, stable, or secure.
See :doc:`/deploying/index` for deployment options.
Command Line Command Line
------------ ------------
The :command:`flask` command line script (:ref:`cli`) is strongly The ``flask run`` command line script is the recommended way to run the
recommended for development because it provides a superior reload development server. It requires setting the ``FLASK_APP`` environment
experience due to how it loads the application. The basic usage is like variable to point to your application, and ``FLASK_ENV=development`` to
this:: fully enable development mode.
$ export FLASK_APP=my_application .. code-block:: text
$ export FLASK_APP=hello
$ export FLASK_ENV=development $ export FLASK_ENV=development
$ flask run $ flask run
This enables the development environment, including the interactive This enables the development environment, including the interactive
debugger and reloader, and then starts the server on debugger and reloader, and then starts the server on
*http://localhost:5000/*. http://localhost:5000/. Use ``flask run --help`` to see the available
options, and :doc:`/cli` for detailed instructions about configuring
The individual features of the server can be controlled by passing more and using the CLI.
arguments to the ``run`` option. For instance the reloader can be
disabled::
$ flask run --no-reload
.. note:: .. note::
Prior to Flask 1.0 the :envvar:`FLASK_ENV` environment variable was Prior to Flask 1.0 the ``FLASK_ENV`` environment variable was not
not supported and you needed to enable debug mode by exporting supported and you needed to enable debug mode by exporting
``FLASK_DEBUG=1``. This can still be used to control debug mode, but ``FLASK_DEBUG=1``. This can still be used to control debug mode, but
you should prefer setting the development environment as shown you should prefer setting the development environment as shown
above. above.
Lazy or Eager Loading
~~~~~~~~~~~~~~~~~~~~~
When using the ``flask run`` command with the reloader, the server will
continue to run even if you introduce syntax errors or other
initialization errors into the code. Accessing the site will show the
interactive debugger for the error, rather than crashing the server.
This feature is called "lazy loading".
If a syntax error is already present when calling ``flask run``, it will
fail immediately and show the traceback rather than waiting until the
site is accessed. This is intended to make errors more visible initially
while still allowing the server to handle errors on reload.
To override this behavior and always fail immediately, even on reload,
pass the ``--eager-loading`` option. To always keep the server running,
even on the initial call, pass ``--lazy-loading``.
In Code In Code
------- -------
The alternative way to start the application is through the As an alternative to the ``flask run`` command, the development server
:meth:`Flask.run` method. This will immediately launch a local server can also be started from Python with the :meth:`Flask.run` method. This
exactly the same way the :command:`flask` script does. method takes arguments similar to the CLI options to control the server.
The main difference from the CLI command is that the server will crash
if there are errors when reloading.
Example:: ``debug=True`` can be passed to enable the debugger and reloader, but
the ``FLASK_ENV=development`` environment variable is still required to
fully enable development mode.
if __name__ == '__main__': Place the call in a main block, otherwise it will interfere when trying
app.run() to import and run the application with a production server later.
This works well for the common case but it does not work well for .. code-block:: python
development which is why from Flask 0.11 onwards the :command:`flask`
method is recommended. The reason for this is that due to how the reload
mechanism works there are some bizarre side-effects (like executing
certain code twice, sometimes crashing without message or dying when a
syntax or import error happens).
It is however still a perfectly valid method for invoking a non automatic if __name__ == "__main__":
reloading application. app.run(debug=True)
.. code-block:: text
$ python hello.py

View file

@ -296,11 +296,15 @@ class DispatchingApp(object):
of the Werkzeug debugger means that it shows up in the browser. of the Werkzeug debugger means that it shows up in the browser.
""" """
def __init__(self, loader, use_eager_loading=False): def __init__(self, loader, use_eager_loading=None):
self.loader = loader self.loader = loader
self._app = None self._app = None
self._lock = Lock() self._lock = Lock()
self._bg_loading_exc_info = None self._bg_loading_exc_info = None
if use_eager_loading is None:
use_eager_loading = os.environ.get("WERKZEUG_RUN_MAIN") != "true"
if use_eager_loading: if use_eager_loading:
self._load_unlocked() self._load_unlocked()
else: else:
@ -802,7 +806,7 @@ class SeparatedPathType(click.Path):
"is active if debug is enabled.", "is active if debug is enabled.",
) )
@click.option( @click.option(
"--eager-loading/--lazy-loader", "--eager-loading/--lazy-loading",
default=None, default=None,
help="Enable or disable eager loading. By default eager " help="Enable or disable eager loading. By default eager "
"loading is enabled if the reloader is disabled.", "loading is enabled if the reloader is disabled.",
@ -841,9 +845,6 @@ def run_command(
if debugger is None: if debugger is None:
debugger = debug debugger = debug
if eager_loading is None:
eager_loading = not reload
show_server_banner(get_env(), debug, info.app_import_path, eager_loading) show_server_banner(get_env(), debug, info.app_import_path, eager_loading)
app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)