Merge pull request #4646 from pallets/cli-app-env

This commit is contained in:
David Lord 2022-06-17 09:30:28 -07:00 committed by GitHub
commit ae547270e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 344 additions and 634 deletions

View file

@ -27,6 +27,12 @@ Unreleased
instance on every request. :issue:`2520`.
- A ``flask.cli.FlaskGroup`` Click group can be nested as a
sub-command in a custom CLI. :issue:`3263`
- Add ``--app``, ``--env``, and ``--debug`` options to the ``flask``
CLI, instead of requiring that they are set through environment
variables. :issue:`2836`
- Add ``--env-file`` option to the ``flask`` CLI. This allows
specifying a dotenv file to load in addition to ``.env`` and
``.flaskenv``. :issue:`3108`
Version 2.1.3

View file

@ -15,40 +15,10 @@ Application Discovery
---------------------
The ``flask`` command is installed by Flask, not your application; it must be
told where to find your application in order to use it. The ``FLASK_APP``
environment variable is used to specify how to load the application.
told where to find your application in order to use it. The ``--app``
option is used to specify how to load the application.
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=hello
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP hello
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=hello
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "hello"
> flask run
While ``FLASK_APP`` supports a variety of options for specifying your
While ``--app`` supports a variety of options for specifying your
application, most use cases should be simple. Here are the typical values:
(nothing)
@ -56,32 +26,32 @@ application, most use cases should be simple. Here are the typical values:
automatically detecting an app (``app`` or ``application``) or
factory (``create_app`` or ``make_app``).
``FLASK_APP=hello``
``--app hello``
The given name is imported, automatically detecting an app (``app``
or ``application``) or factory (``create_app`` or ``make_app``).
----
``FLASK_APP`` has three parts: an optional path that sets the current working
``--app`` has three parts: an optional path that sets the current working
directory, a Python file or dotted import path, and an optional variable
name of the instance or factory. If the name is a factory, it can optionally
be followed by arguments in parentheses. The following values demonstrate these
parts:
``FLASK_APP=src/hello``
``--app src/hello``
Sets the current working directory to ``src`` then imports ``hello``.
``FLASK_APP=hello.web``
``--app hello.web``
Imports the path ``hello.web``.
``FLASK_APP=hello:app2``
``--app hello:app2``
Uses the ``app2`` Flask instance in ``hello``.
``FLASK_APP="hello:create_app('dev')"``
``--app 'hello:create_app("dev")'``
The ``create_app`` factory in ``hello`` is called with the string ``'dev'``
as the argument.
If ``FLASK_APP`` is not set, the command will try to import "app" or
If ``--app`` is not set, the command will try to import "app" or
"wsgi" (as a ".py" file, or package) and try to detect an application
instance or factory.
@ -137,8 +107,9 @@ Environments
.. versionadded:: 1.0
The environment in which the Flask app runs is set by the
:envvar:`FLASK_ENV` environment variable. If not set it defaults to
The environment in which the Flask app executes is set by the
``FLASK_ENV`` environment variable. When using the ``flask`` command, it
can also be set with the ``--env`` option. If not set it defaults to
``production``. The other recognized environment is ``development``.
Flask and extensions may choose to enable behaviors based on the
environment.
@ -147,63 +118,16 @@ If the env is set to ``development``, the ``flask`` command will enable
debug mode and ``flask run`` will enable the interactive debugger and
reloader.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
$ flask --app hello --env development run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
Watch Extra Files with the Reloader
@ -211,72 +135,31 @@ Watch Extra Files with the Reloader
When using development mode, the reloader will trigger whenever your
Python code or imported modules change. The reloader can watch
additional files with the ``--extra-files`` option, or the
``FLASK_RUN_EXTRA_FILES`` environment variable. Multiple paths are
additional files with the ``--extra-files`` option. Multiple paths are
separated with ``:``, or ``;`` on Windows.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
# or
$ export FLASK_RUN_EXTRA_FILES=file1:dirA/file2:dirB/
$ flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: Fish
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
# or
$ set -x FLASK_RUN_EXTRA_FILES file1 dirA/file2 dirB/
$ flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: CMD
.. code-block:: text
> flask run --extra-files file1:dirA/file2:dirB/
# or
> set FLASK_RUN_EXTRA_FILES=file1:dirA/file2:dirB/
> flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: Powershell
.. code-block:: text
> flask run --extra-files file1:dirA/file2:dirB/
# or
> $env:FLASK_RUN_EXTRA_FILES = "file1:dirA/file2:dirB/"
> flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
$ flask run --extra-files file1:dirA/file2:dirB/
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
Ignore files with the Reloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reloader can also ignore files using :mod:`fnmatch` patterns with
the ``--exclude-patterns`` option, or the ``FLASK_RUN_EXCLUDE_PATTERNS``
environment variable. Multiple patterns are separated with ``:``, or
``;`` on Windows.
the ``--exclude-patterns`` option. Multiple patterns are separated with
``:``, or ``;`` on Windows.
Debug Mode
----------
Debug mode will be enabled when :envvar:`FLASK_ENV` is ``development``,
as described above. If you want to control debug mode separately, use
:envvar:`FLASK_DEBUG`. The value ``1`` enables it, ``0`` disables it.
Debug mode will be enabled when the execution environment is
``development``, as described above. If you want to control debug mode
separately, use the ``--debug/--no-debug`` option or the ``FLASK_DEBUG``
environment variable.
.. _dotenv:
@ -284,14 +167,21 @@ as described above. If you want to control debug mode separately, use
Environment Variables From dotenv
---------------------------------
Rather than setting ``FLASK_APP`` each time you open a new terminal, you can
use Flask's dotenv support to set environment variables automatically.
The ``flask`` command supports setting any option for any command with
environment variables. The variables are named like ``FLASK_OPTION`` or
``FLASK_COMMAND_OPTION``, for example ``FLASK_APP`` or
``FLASK_RUN_PORT``.
Rather than passing options every time you run a command, or environment
variables every time you open a new terminal, you can use Flask's dotenv
support to set environment variables automatically.
If `python-dotenv`_ is installed, running the ``flask`` command will set
environment variables defined in the files :file:`.env` and :file:`.flaskenv`.
This can be used to avoid having to set ``FLASK_APP`` manually every time you
open a new terminal, and to set configuration using environment variables
similar to how some deployment services work.
environment variables defined in the files ``.env`` and ``.flaskenv``.
You can also specify an extra file to load with the ``--env-file``
option. Dotenv files can be used to avoid having to set ``--app`` or
``FLASK_APP`` manually, and to set configuration using environment
variables similar to how some deployment services work.
Variables set on the command line are used over those set in :file:`.env`,
which are used over those set in :file:`.flaskenv`. :file:`.flaskenv` should be
@ -612,7 +502,7 @@ Custom Scripts
--------------
When you are using the app factory pattern, it may be more convenient to define
your own Click script. Instead of using ``FLASK_APP`` and letting Flask load
your own Click script. Instead of using ``--app`` and letting Flask load
your application, you can create your own Click object and export it as a
`console script`_ entry point.
@ -646,7 +536,7 @@ Define the entry point in :file:`setup.py`::
)
Install the application in the virtualenv in editable mode and the custom
script is available. Note that you don't need to set ``FLASK_APP``. ::
script is available. Note that you don't need to set ``--app``. ::
$ pip install -e .
$ wiki run

View file

@ -47,61 +47,33 @@ Environment and Debug Features
The :data:`ENV` and :data:`DEBUG` config values are special because they
may behave inconsistently if changed after the app has begun setting up.
In order to set the environment and debug mode reliably, Flask uses
environment variables.
In order to set the environment and debug mode reliably, pass options to
the ``flask`` command or use environment variables.
The environment is used to indicate to Flask, extensions, and other
programs, like Sentry, what context Flask is running in. It is
controlled with the :envvar:`FLASK_ENV` environment variable and
defaults to ``production``.
The execution environment is used to indicate to Flask, extensions, and
other programs, like Sentry, what context Flask is running in. It is
controlled with the ``FLASK_ENV`` environment variable, or the
``--env`` option when using the ``flask`` command, and defaults to
``production``.
Setting :envvar:`FLASK_ENV` to ``development`` will enable debug mode.
``flask run`` will use the interactive debugger and reloader by default
in debug mode. To control this separately from the environment, use the
:envvar:`FLASK_DEBUG` flag.
.. versionchanged:: 1.0
Added :envvar:`FLASK_ENV` to control the environment separately
from debug mode. The development environment enables debug mode.
Setting ``--env development`` will enable debug mode. ``flask run`` will
use the interactive debugger and reloader by default in debug mode. To
control this separately from the environment, use the
``--debug/--no-debug`` option or the ``FLASK_DEBUG`` environment
variable.
To switch Flask to the development environment and enable debug mode,
set :envvar:`FLASK_ENV`:
set ``--env``:
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask --app hello --env development run
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
Using the environment variables as described above is recommended. While
it is possible to set :data:`ENV` and :data:`DEBUG` in your config or
code, this is strongly discouraged. They can't be read early by the
``flask`` command, and some systems or extensions may have already
configured themselves based on a previous value.
Using the options or environment variables as described above is
recommended. While it is possible to set :data:`ENV` and :data:`DEBUG`
in your config or code, this is strongly discouraged. They can't be read
early by the ``flask`` command, and some systems or extensions may have
already configured themselves based on a previous value.
Builtin Configuration Values

View file

@ -39,45 +39,19 @@ during a request. This debugger should only be used during development.
security risk. Do not run the development server or debugger in a
production environment.
To enable the debugger, run the development server with the
``FLASK_ENV`` environment variable set to ``development``. This puts
Flask in debug mode, which changes how it handles some errors, and
enables the debugger and reloader.
To enable the debugger, run the development server with the environment
set to ``development``. This puts Flask in debug mode, which changes how
it handles some errors, and enables the debugger and reloader.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask --app hello --env development run
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
``FLASK_ENV`` can only be set as an environment variable. When running
``FLASK_ENV`` can also be set as an environment variable. When running
from Python code, passing ``debug=True`` enables debug mode, which is
mostly equivalent. Debug mode can be controlled separately from
``FLASK_ENV`` with the ``FLASK_DEBUG`` environment variable as well.
mostly equivalent. Debug mode can be controlled separately from the
environment with the ``--debug/--no-debug`` option or the
``FLASK_DEBUG`` environment variable.
.. code-block:: python
@ -102,37 +76,9 @@ When using an external debugger, the app should still be in debug mode,
but it can be useful to disable the built-in debugger and reloader,
which can interfere.
When running from the command line:
.. code-block:: text
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run --no-debugger --no-reload
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run --no-debugger --no-reload
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run --no-debugger --no-reload
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run --no-debugger --no-reload
$ flask --app hello --env development run --no-debugger --no-reload
When running from Python:

View file

@ -89,71 +89,20 @@ Using Applications
To run such an application, you can use the :command:`flask` command:
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask run --app hello run
.. code-block:: text
Flask will automatically detect the factory if it is named
``create_app`` or ``make_app`` in ``hello``. You can also pass arguments
to the factory like this:
$ export FLASK_APP=myapp
$ flask run
.. code-block:: text
.. group-tab:: Fish
$ flask run --app hello:create_app(local_auth=True)``
.. code-block:: text
$ set -x FLASK_APP myapp
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=myapp
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "myapp"
> flask run
Flask will automatically detect the factory (``create_app`` or ``make_app``)
in ``myapp``. You can also pass arguments to the factory like this:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP="myapp:create_app('dev')"
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP "myapp:create_app('dev')"
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP="myapp:create_app('dev')"
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "myapp:create_app('dev')"
> flask run
Then the ``create_app`` factory in ``myapp`` is called with the string
``'dev'`` as the argument. See :doc:`/cli` for more detail.
Then the ``create_app`` factory in ``myapp`` is called with the keyword
argument ``local_auth=True``. See :doc:`/cli` for more detail.
Factory Improvements
--------------------

View file

@ -56,70 +56,17 @@ a big problem, just add a new file called :file:`setup.py` next to the inner
],
)
In order to run the application you need to export an environment variable
that tells Flask where to find the application instance:
Install your application so it is importable:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=yourapplication
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP yourapplication
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=yourapplication
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "yourapplication"
If you are outside of the project directory make sure to provide the exact
path to your application directory. Similarly you can turn on the
development features like this:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
In order to install and run the application you need to issue the following
commands::
.. code-block:: text
$ pip install -e .
$ flask run
To use the ``flask`` command and run your application you need to set
the ``--app`` option that tells Flask where to find the application
instance:
$ flask --app yourapplication run
What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the

View file

@ -39,50 +39,20 @@ Save it as :file:`hello.py` or something similar. Make sure to not call
your application :file:`flask.py` because this would conflict with Flask
itself.
To run the application, use the :command:`flask` command or
:command:`python -m flask`. Before you can do that you need
to tell your terminal the application to work with by exporting the
``FLASK_APP`` environment variable:
To run the application, use the ``flask`` command or
``python -m flask``. You need to tell the Flask where your application
is with the ``-app`` option.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=hello
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP hello
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=hello
> flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "hello"
> flask run
* Running on http://127.0.0.1:5000/
$ flask --app hello run
* Serving Flask app 'hello' (lazy loading)
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
.. admonition:: Application Discovery Behavior
As a shortcut, if the file is named ``app.py`` or ``wsgi.py``, you
don't have to set the ``FLASK_APP`` environment variable. See
:doc:`/cli` for more details.
don't have to use ``--app``. See :doc:`/cli` for more details.
This launches a very simple builtin server, which is good enough for
testing but probably not what you want to use in production. For
@ -114,34 +84,6 @@ handle that.
This tells your operating system to listen on all public IPs.
What to do if the Server does not Start
---------------------------------------
In case the :command:`python -m flask` fails or :command:`flask`
does not exist, there are multiple reasons this might be the case.
First of all you need to look at the error message.
Old Version of Flask
````````````````````
Versions of Flask older than 0.11 used to have different ways to start the
application. In short, the :command:`flask` command did not exist, and
neither did :command:`python -m flask`. In that case you have two options:
either upgrade to newer Flask versions or have a look at :doc:`/server`
to see the alternative method for running a server.
Invalid Import Name
```````````````````
The ``FLASK_APP`` environment variable is the name of the module to import at
:command:`flask run`. In case that module is incorrectly named you will get an
import error upon start (or if debug is enabled when you navigate to the
application). It will tell you what it tried to import and why it failed.
The most common reason is a typo or because you did not actually create an
``app`` object.
Debug Mode
----------
@ -162,38 +104,19 @@ error occurs during a request.
security risk. Do not run the development server or debugger in a
production environment.
To enable all development features, set the ``FLASK_ENV`` environment
variable to ``development`` before calling ``flask run``.
To enable all development features, set the ``--env`` option to
``development``.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
$ flask --app hello --env development run
* Serving Flask app 'hello' (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: nnn-nnn-nnn
See also:

View file

@ -227,8 +227,8 @@ associated with it is destroyed. If an error occurs during development,
it is useful to delay destroying the data for debugging purposes.
When the development server is running in development mode (the
``FLASK_ENV`` environment variable is set to ``'development'``), the
error and data will be preserved and shown in the interactive debugger.
``--env`` option is set to ``'development'``), the error and data will
be preserved and shown in the interactive debugger.
This behavior can be controlled with the
:data:`PRESERVE_CONTEXT_ON_EXCEPTION` config. As described above, it

View file

@ -19,9 +19,16 @@ Command Line
------------
The ``flask run`` command line script is the recommended way to run the
development server. It requires setting the ``FLASK_APP`` environment
variable to point to your application, and ``FLASK_ENV=development`` to
fully enable development mode.
development server. Use the ``--app`` option to point to your
application, and the ``--env development`` option to fully enable
development mode.
.. code-block:: text
$ flask --app hello --env development run
These options (and any others) can also be set using environment
variables.
.. tabs::
@ -65,11 +72,11 @@ and using the CLI.
.. note::
Prior to Flask 1.0 the ``FLASK_ENV`` environment variable was not
supported and you needed to enable debug mode by exporting
``FLASK_DEBUG=1``. This can still be used to control debug mode, but
you should prefer setting the development environment as shown
above.
Debug mode can be controlled separately from the development
environment with the ``--debug/--no-debug`` option or the
``FLASK_DEBUG`` environment variable. This is how older versions of
Flask worked. You should prefer setting the development environment
as shown above.
.. _address-already-in-use:

View file

@ -196,15 +196,13 @@ previous page.
If you're still running the server from the previous page, you can
either stop the server, or run this command in a new terminal. If
you use a new terminal, remember to change to your project directory
and activate the env as described in :doc:`/installation`. You'll
also need to set ``FLASK_APP`` and ``FLASK_ENV`` as shown on the
previous page.
and activate the env as described in :doc:`/installation`.
Run the ``init-db`` command:
.. code-block:: none
$ flask init-db
$ flask --app flaskr init-db
Initialized the database.
There will now be a ``flaskr.sqlite`` file in the ``instance`` folder in

View file

@ -48,35 +48,9 @@ Pip will install your project along with its dependencies.
Since this is a different machine, you need to run ``init-db`` again to
create the database in the instance folder.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=flaskr
$ flask init-db
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP flaskr
$ flask init-db
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=flaskr
> flask init-db
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "flaskr"
> flask init-db
$ flask --app flaskr init-db
When Flask detects that it's installed (not in editable mode), it uses
a different directory for the instance folder. You can find it at
@ -127,7 +101,7 @@ first install it in the virtual environment:
$ pip install waitress
You need to tell Waitress about your application, but it doesn't use
``FLASK_APP`` like ``flask run`` does. You need to tell it to import and
``--app`` like ``flask run`` does. You need to tell it to import and
call the application factory to get an application object.
.. code-block:: none

View file

@ -135,43 +135,13 @@ exception, and restarts the server whenever you make changes to the
code. You can leave it running and just reload the browser page as you
follow the tutorial.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=flaskr
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP flaskr
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=flaskr
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "flaskr"
> $env:FLASK_ENV = "development"
> flask run
$ flask --app flaskr --env development run
You'll see output similar to this:
.. code-block:: none
.. code-block:: text
* Serving Flask app "flaskr"
* Environment: development
@ -179,7 +149,7 @@ You'll see output similar to this:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 855-212-761
* Debugger PIN: nnn-nnn-nnn
Visit http://127.0.0.1:5000/hello in a browser and you should see the
"Hello, World!" message. Congratulations, you're now running your Flask

View file

@ -109,7 +109,7 @@ You can observe that the project is now installed with ``pip list``.
wheel 0.30.0
Nothing changes from how you've been running your project so far.
``FLASK_APP`` is still set to ``flaskr`` and ``flask run`` still runs
``--app`` is still set to ``flaskr`` and ``flask run`` still runs
the application, but you can call it from anywhere, not just the
``flask-tutorial`` directory.

View file

@ -33,8 +33,7 @@ Run
.. code-block:: text
$ export FLASK_APP=js_example
$ flask run
$ flask --app js_example run
Open http://127.0.0.1:5000 in a browser.

View file

@ -45,19 +45,10 @@ installing Flaskr::
Run
---
::
.. code-block:: text
$ export FLASK_APP=flaskr
$ export FLASK_ENV=development
$ flask init-db
$ flask run
Or on Windows cmd::
> set FLASK_APP=flaskr
> set FLASK_ENV=development
> flask init-db
> flask run
$ flask --app flaskr init-db
$ flask --app flaskr --env development run
Open http://127.0.0.1:5000 in a browser.

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import ast
import inspect
import os
@ -12,6 +14,7 @@ from threading import Lock
from threading import Thread
import click
from click.core import ParameterSource
from werkzeug.serving import is_running_from_reloader
from werkzeug.utils import import_string
@ -20,6 +23,9 @@ from .helpers import get_debug_flag
from .helpers import get_env
from .helpers import get_load_dotenv
if t.TYPE_CHECKING:
from .app import Flask
class NoAppException(click.UsageError):
"""Raised if an application cannot be found or loaded."""
@ -46,8 +52,8 @@ def find_best_app(module):
elif len(matches) > 1:
raise NoAppException(
"Detected multiple Flask applications in module"
f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
f" to specify the correct one."
f" '{module.__name__}'. Use '{module.__name__}:name'"
" to specify the correct one."
)
# Search for app factory functions.
@ -65,15 +71,15 @@ def find_best_app(module):
raise
raise NoAppException(
f"Detected factory {attr_name!r} in module {module.__name__!r},"
f"Detected factory '{attr_name}' in module '{module.__name__}',"
" but could not call it without arguments. Use"
f" \"FLASK_APP='{module.__name__}:{attr_name}(args)'\""
f" '{module.__name__}:{attr_name}(args)'"
" to specify arguments."
) from e
raise NoAppException(
"Failed to find Flask application or factory in module"
f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
f" '{module.__name__}'. Use '{module.__name__}:name'"
" to specify one."
)
@ -253,7 +259,7 @@ def get_version(ctx, param, value):
version_option = click.Option(
["--version"],
help="Show the flask version",
help="Show the Flask version.",
expose_value=False,
callback=get_version,
is_flag=True,
@ -338,19 +344,24 @@ class ScriptInfo:
onwards as click object.
"""
def __init__(self, app_import_path=None, create_app=None, set_debug_flag=True):
def __init__(
self,
app_import_path: str | None = None,
create_app: t.Callable[..., Flask] | None = None,
set_debug_flag: bool = True,
) -> None:
#: Optionally the import path for the Flask application.
self.app_import_path = app_import_path or os.environ.get("FLASK_APP")
self.app_import_path = app_import_path
#: Optionally a function that is passed the script info to create
#: the instance of the application.
self.create_app = create_app
#: A dictionary with arbitrary data that can be associated with
#: this script info.
self.data = {}
self.data: t.Dict[t.Any, t.Any] = {}
self.set_debug_flag = set_debug_flag
self._loaded_app = None
self._loaded_app: Flask | None = None
def load_app(self):
def load_app(self) -> Flask:
"""Loads the Flask app (if not yet loaded) and returns it. Calling
this multiple times will just result in the already loaded app to
be returned.
@ -379,9 +390,10 @@ class ScriptInfo:
if not app:
raise NoAppException(
"Could not locate a Flask application. You did not provide "
'the "FLASK_APP" environment variable, and a "wsgi.py" or '
'"app.py" module was not found in the current directory.'
"Could not locate a Flask application. Use the"
" 'flask --app' option, 'FLASK_APP' environment"
" variable, or a 'wsgi.py' or 'app.py' file in the"
" current directory."
)
if self.set_debug_flag:
@ -442,6 +454,117 @@ class AppGroup(click.Group):
return click.Group.group(self, *args, **kwargs)
def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None:
if value is None:
return None
info = ctx.ensure_object(ScriptInfo)
info.app_import_path = value
return value
# This option is eager so the app will be available if --help is given.
# --help is also eager, so --app must be before it in the param list.
# no_args_is_help bypasses eager processing, so this option must be
# processed manually in that case to ensure FLASK_APP gets picked up.
_app_option = click.Option(
["-A", "--app"],
metavar="IMPORT",
help=(
"The Flask application or factory function to load, in the form 'module:name'."
" Module can be a dotted import or file path. Name is not required if it is"
" 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to"
" pass arguments."
),
is_eager=True,
expose_value=False,
callback=_set_app,
)
def _set_env(ctx: click.Context, param: click.Option, value: str | None) -> str | None:
if value is None:
return None
# Set with env var instead of ScriptInfo.load so that it can be
# accessed early during a factory function.
os.environ["FLASK_ENV"] = value
return value
_env_option = click.Option(
["-E", "--env"],
metavar="NAME",
help=(
"The execution environment name to set in 'app.env'. Defaults to"
" 'production'. 'development' will enable 'app.debug' and start the"
" debugger and reloader when running the server."
),
expose_value=False,
callback=_set_env,
)
def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None:
# If the flag isn't provided, it will default to False. Don't use
# that, let debug be set by env in that case.
source = ctx.get_parameter_source(param.name) # type: ignore[arg-type]
if source is not None and source in (
ParameterSource.DEFAULT,
ParameterSource.DEFAULT_MAP,
):
return None
# Set with env var instead of ScriptInfo.load so that it can be
# accessed early during a factory function.
os.environ["FLASK_DEBUG"] = "1" if value else "0"
return value
_debug_option = click.Option(
["--debug/--no-debug"],
help="Set 'app.debug' separately from '--env'.",
expose_value=False,
callback=_set_debug,
)
def _env_file_callback(
ctx: click.Context, param: click.Option, value: str | None
) -> str | None:
if value is None:
return None
import importlib
try:
importlib.import_module("dotenv")
except ImportError:
raise click.BadParameter(
"python-dotenv must be installed to load an env file.",
ctx=ctx,
param=param,
) from None
# Don't check FLASK_SKIP_DOTENV, that only disables automatically
# loading .env and .flaskenv files.
load_dotenv(value)
return value
# This option is eager so env vars are loaded as early as possible to be
# used by other options.
_env_file_option = click.Option(
["-e", "--env-file"],
type=click.Path(exists=True, dir_okay=False),
help="Load environment variables from this file. python-dotenv must be installed.",
is_eager=True,
expose_value=False,
callback=_env_file_callback,
)
class FlaskGroup(AppGroup):
"""Special subclass of the :class:`AppGroup` group that supports
loading more commands from the configured Flask app. Normally a
@ -460,6 +583,10 @@ class FlaskGroup(AppGroup):
:param set_debug_flag: Set the app's debug flag based on the active
environment
.. versionchanged:: 2.2
Added the ``-A/--app``, ``-E/--env``, ``--debug/--no-debug``,
and ``-e/--env-file`` options.
.. versionchanged:: 1.0
If installed, python-dotenv will be used to load environment variables
from :file:`.env` and :file:`.flaskenv` files.
@ -467,14 +594,19 @@ class FlaskGroup(AppGroup):
def __init__(
self,
add_default_commands=True,
create_app=None,
add_version_option=True,
load_dotenv=True,
set_debug_flag=True,
**extra,
):
add_default_commands: bool = True,
create_app: t.Callable[..., Flask] | None = None,
add_version_option: bool = True,
load_dotenv: bool = True,
set_debug_flag: bool = True,
**extra: t.Any,
) -> None:
params = list(extra.pop("params", None) or ())
# Processing is done with option callbacks instead of a group
# callback. This allows users to make a custom group callback
# without losing the behavior. --env-file must come first so
# that it is eagerly evaluated before --app.
params.extend((_env_file_option, _app_option, _env_option, _debug_option))
if add_version_option:
params.append(version_option)
@ -555,11 +687,13 @@ class FlaskGroup(AppGroup):
def make_context(
self,
info_name: t.Optional[str],
args: t.List[str],
parent: t.Optional[click.Context] = None,
info_name: str | None,
args: list[str],
parent: click.Context | None = None,
**extra: t.Any,
) -> click.Context:
# Attempt to load .env and .flask env files. The --env-file
# option can cause another file to be loaded.
if get_load_dotenv(self.load_dotenv):
load_dotenv()
@ -570,6 +704,16 @@ class FlaskGroup(AppGroup):
return super().make_context(info_name, args, parent=parent, **extra)
def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]:
if not args and self.no_args_is_help:
# Attempt to load --env-file and --app early in case they
# were given as env vars. Otherwise no_args_is_help will not
# see commands from app.cli.
_env_file_option.handle_parse_result(ctx, {}, [])
_app_option.handle_parse_result(ctx, {}, [])
return super().parse_args(ctx, args)
def _path_is_ancestor(path, other):
"""Take ``other`` and remove the length of ``path`` from it. Then join it
@ -578,7 +722,7 @@ def _path_is_ancestor(path, other):
return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other
def load_dotenv(path=None):
def load_dotenv(path: str | os.PathLike | None = None) -> bool:
"""Load "dotenv" files in order of precedence to set environment variables.
If an env var is already set it is not overwritten, so earlier files in the
@ -591,13 +735,17 @@ def load_dotenv(path=None):
:param path: Load the file at this location instead of searching.
:return: ``True`` if a file was loaded.
.. versionchanged:: 1.1.0
Returns ``False`` when python-dotenv is not installed, or when
the given path isn't a file.
.. versionchanged:: 2.0
The current directory is not changed to the location of the
loaded file.
.. versionchanged:: 2.0
When loading the env files, set the default encoding to UTF-8.
.. versionchanged:: 1.1.0
Returns ``False`` when python-dotenv is not installed, or when
the given path isn't a file.
.. versionadded:: 1.0
"""
try:
@ -613,15 +761,15 @@ def load_dotenv(path=None):
return False
# if the given path specifies the actual file then return True,
# else False
# Always return after attempting to load a given path, don't load
# the default files.
if path is not None:
if os.path.isfile(path):
return dotenv.load_dotenv(path, encoding="utf-8")
return False
new_dir = None
loaded = False
for name in (".env", ".flaskenv"):
path = dotenv.find_dotenv(name, usecwd=True)
@ -629,12 +777,10 @@ def load_dotenv(path=None):
if not path:
continue
if new_dir is None:
new_dir = os.path.dirname(path)
dotenv.load_dotenv(path, encoding="utf-8")
loaded = True
return new_dir is not None # at least one file was located and loaded
return loaded # True if at least one file was located and loaded.
def show_server_banner(env, debug, app_import_path, eager_loading):
@ -837,9 +983,10 @@ def run_command(
This server is for development purposes only. It does not provide
the stability, security, or performance of production WSGI servers.
The reloader and debugger are enabled by default if
FLASK_ENV=development or FLASK_DEBUG=1.
The reloader and debugger are enabled by default with the
'--env development' or '--debug' options.
"""
app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
debug = get_debug_flag()
if reload is None:
@ -849,7 +996,6 @@ def run_command(
debugger = debug
show_server_banner(get_env(), debug, info.app_import_path, eager_loading)
app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
from werkzeug.serving import run_simple
@ -971,19 +1117,10 @@ cli = FlaskGroup(
help="""\
A general utility script for Flask applications.
Provides commands from Flask, extensions, and the application. Loads the
application defined in the FLASK_APP environment variable, or from a wsgi.py
file. Setting the FLASK_ENV environment variable to 'development' will enable
debug mode.
\b
{prefix}{cmd} FLASK_APP=hello.py
{prefix}{cmd} FLASK_ENV=development
{prefix}flask run
""".format(
cmd="export" if os.name == "posix" else "set",
prefix="$ " if os.name == "posix" else "> ",
),
An application to load must be given with the '--app' option,
'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file
in the current directory.
""",
)

View file

@ -48,9 +48,9 @@ def get_debug_flag() -> bool:
def get_load_dotenv(default: bool = True) -> bool:
"""Get whether the user has disabled loading dotenv files by setting
:envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the
files.
"""Get whether the user has disabled loading default dotenv files by
setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load
the files.
:param default: What to return if the env var isn't set.
"""

View file

@ -18,6 +18,7 @@ def _standard_os_environ():
"""
mp = monkeypatch.MonkeyPatch()
out = (
(os.environ, "FLASK_ENV_FILE", monkeypatch.notset),
(os.environ, "FLASK_APP", monkeypatch.notset),
(os.environ, "FLASK_ENV", monkeypatch.notset),
(os.environ, "FLASK_DEBUG", monkeypatch.notset),