deprecate FLASK_ENV

This commit is contained in:
David Lord 2022-08-01 15:11:21 -07:00
parent 4c08e3a2ba
commit ef95998d79
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
5 changed files with 95 additions and 96 deletions

View File

@ -23,6 +23,10 @@ Unreleased
``g`` instead using a unique prefix, like ``g`` instead using a unique prefix, like
``g._extension_name_attr``. ``g._extension_name_attr``.
- The ``FLASK_ENV`` environment variable and ``app.env`` attribute are
deprecated, removing the distinction between development and debug
mode. Debug mode should be controlled directly using the ``--debug``
option or ``app.run(debug=True)``. :issue:`4714`
- Add new customization points to the ``Flask`` app object for many - Add new customization points to the ``Flask`` app object for many
previously global behaviors. previously global behaviors.
@ -60,9 +64,9 @@ Unreleased
instance on every request. :issue:`2520`. instance on every request. :issue:`2520`.
- A ``flask.cli.FlaskGroup`` Click group can be nested as a - A ``flask.cli.FlaskGroup`` Click group can be nested as a
sub-command in a custom CLI. :issue:`3263` sub-command in a custom CLI. :issue:`3263`
- Add ``--app``, ``--env``, and ``--debug`` options to the ``flask`` - Add ``--app`` and ``--debug`` options to the ``flask`` CLI, instead
CLI, instead of requiring that they are set through environment of requiring that they are set through environment variables.
variables. :issue:`2836` :issue:`2836`
- Add ``--env-file`` option to the ``flask`` CLI. This allows - Add ``--env-file`` option to the ``flask`` CLI. This allows
specifying a dotenv file to load in addition to ``.env`` and specifying a dotenv file to load in addition to ``.env`` and
``.flaskenv``. :issue:`3108` ``.flaskenv``. :issue:`3108`

View File

@ -45,7 +45,6 @@ from .globals import request_ctx
from .globals import session from .globals import session
from .helpers import _split_blueprint_path from .helpers import _split_blueprint_path
from .helpers import get_debug_flag from .helpers import get_debug_flag
from .helpers import get_env
from .helpers import get_flashed_messages from .helpers import get_flashed_messages
from .helpers import get_load_dotenv from .helpers import get_load_dotenv
from .helpers import locked_cached_property from .helpers import locked_cached_property
@ -691,7 +690,7 @@ class Flask(Scaffold):
if instance_relative: if instance_relative:
root_path = self.instance_path root_path = self.instance_path
defaults = dict(self.default_config) defaults = dict(self.default_config)
defaults["ENV"] = get_env() defaults["ENV"] = os.environ.get("FLASK_ENV") or "development"
defaults["DEBUG"] = get_debug_flag() defaults["DEBUG"] = get_debug_flag()
return self.config_class(root_path, defaults) return self.config_class(root_path, defaults)
@ -849,31 +848,50 @@ class Flask(Scaffold):
rv.update(processor()) rv.update(processor())
return rv return rv
#: What environment the app is running in. Flask and extensions may @property
#: enable behaviors based on the environment, such as enabling debug def env(self) -> str:
#: mode. This maps to the :data:`ENV` config key. This is set by the """What environment the app is running in. This maps to the :data:`ENV` config
#: :envvar:`FLASK_ENV` environment variable and may not behave as key.
#: expected if set in code.
#: **Do not enable development when deploying in production.**
#: **Do not enable development when deploying in production.**
#: Default: ``'production'``
#: Default: ``'production'``
env = ConfigAttribute("ENV") .. deprecated:: 2.2
Will be removed in Flask 2.3.
"""
import warnings
warnings.warn(
"'app.env' is deprecated and will be removed in Flask 2.3."
" Use 'app.debug' instead.",
DeprecationWarning,
stacklevel=2,
)
return self.config["ENV"]
@env.setter
def env(self, value: str) -> None:
import warnings
warnings.warn(
"'app.env' is deprecated and will be removed in Flask 2.3."
" Use 'app.debug' instead.",
DeprecationWarning,
stacklevel=2,
)
self.config["ENV"] = value
@property @property
def debug(self) -> bool: def debug(self) -> bool:
"""Whether debug mode is enabled. When using ``flask run`` to start """Whether debug mode is enabled. When using ``flask run`` to start the
the development server, an interactive debugger will be shown for development server, an interactive debugger will be shown for unhandled
unhandled exceptions, and the server will be reloaded when code exceptions, and the server will be reloaded when code changes. This maps to the
changes. This maps to the :data:`DEBUG` config key. This is :data:`DEBUG` config key. It may not behave as expected if set late.
enabled when :attr:`env` is ``'development'`` and is overridden
by the ``FLASK_DEBUG`` environment variable. It may not behave as
expected if set in code.
**Do not enable debug mode when deploying in production.** **Do not enable debug mode when deploying in production.**
Default: ``True`` if :attr:`env` is ``'development'``, or Default: ``False``
``False`` otherwise.
""" """
return self.config["DEBUG"] return self.config["DEBUG"]
@ -937,9 +955,7 @@ class Flask(Scaffold):
If installed, python-dotenv will be used to load environment If installed, python-dotenv will be used to load environment
variables from :file:`.env` and :file:`.flaskenv` files. variables from :file:`.env` and :file:`.flaskenv` files.
If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG` The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`.
environment variables will override :attr:`env` and
:attr:`debug`.
Threaded mode is enabled by default. Threaded mode is enabled by default.
@ -966,7 +982,12 @@ class Flask(Scaffold):
# if set, let env vars override previous values # if set, let env vars override previous values
if "FLASK_ENV" in os.environ: if "FLASK_ENV" in os.environ:
self.env = get_env() print(
"'FLASK_ENV' is deprecated and will not be used in"
" Flask 2.3. Use 'FLASK_DEBUG' instead.",
file=sys.stderr,
)
self.config["ENV"] = os.environ.get("FLASK_ENV") or "production"
self.debug = get_debug_flag() self.debug = get_debug_flag()
elif "FLASK_DEBUG" in os.environ: elif "FLASK_DEBUG" in os.environ:
self.debug = get_debug_flag() self.debug = get_debug_flag()
@ -998,7 +1019,7 @@ class Flask(Scaffold):
options.setdefault("use_debugger", self.debug) options.setdefault("use_debugger", self.debug)
options.setdefault("threaded", True) options.setdefault("threaded", True)
cli.show_server_banner(self.env, self.debug, self.name) cli.show_server_banner(self.debug, self.name)
from werkzeug.serving import run_simple from werkzeug.serving import run_simple

View File

@ -13,12 +13,12 @@ from operator import attrgetter
import click import click
from click.core import ParameterSource from click.core import ParameterSource
from werkzeug import run_simple
from werkzeug.serving import is_running_from_reloader from werkzeug.serving import is_running_from_reloader
from werkzeug.utils import import_string from werkzeug.utils import import_string
from .globals import current_app from .globals import current_app
from .helpers import get_debug_flag from .helpers import get_debug_flag
from .helpers import get_env
from .helpers import get_load_dotenv from .helpers import get_load_dotenv
if t.TYPE_CHECKING: if t.TYPE_CHECKING:
@ -418,29 +418,6 @@ _app_option = click.Option(
) )
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: 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 # If the flag isn't provided, it will default to False. Don't use
# that, let debug be set by env in that case. # that, let debug be set by env in that case.
@ -460,7 +437,7 @@ def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | N
_debug_option = click.Option( _debug_option = click.Option(
["--debug/--no-debug"], ["--debug/--no-debug"],
help="Set 'app.debug' separately from '--env'.", help="Set debug mode.",
expose_value=False, expose_value=False,
callback=_set_debug, callback=_set_debug,
) )
@ -516,12 +493,10 @@ class FlaskGroup(AppGroup):
:param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
files to set environment variables. Will also change the working files to set environment variables. Will also change the working
directory to the directory containing the first file found. directory to the directory containing the first file found.
:param set_debug_flag: Set the app's debug flag based on the active :param set_debug_flag: Set the app's debug flag.
environment
.. versionchanged:: 2.2 .. versionchanged:: 2.2
Added the ``-A/--app``, ``-E/--env``, ``--debug/--no-debug``, Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options.
and ``-e/--env-file`` options.
.. versionchanged:: 2.2 .. versionchanged:: 2.2
An app context is pushed when running ``app.cli`` commands, so An app context is pushed when running ``app.cli`` commands, so
@ -546,7 +521,7 @@ class FlaskGroup(AppGroup):
# callback. This allows users to make a custom group callback # callback. This allows users to make a custom group callback
# without losing the behavior. --env-file must come first so # without losing the behavior. --env-file must come first so
# that it is eagerly evaluated before --app. # that it is eagerly evaluated before --app.
params.extend((_env_file_option, _app_option, _env_option, _debug_option)) params.extend((_env_file_option, _app_option, _debug_option))
if add_version_option: if add_version_option:
params.append(version_option) params.append(version_option)
@ -737,26 +712,23 @@ def load_dotenv(path: str | os.PathLike | None = None) -> bool:
return loaded # True if 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): def show_server_banner(debug, app_import_path):
"""Show extra startup messages the first time the server is run, """Show extra startup messages the first time the server is run,
ignoring the reloader. ignoring the reloader.
""" """
if is_running_from_reloader(): if is_running_from_reloader():
return return
click.secho(
"WARNING: This is a development server. Do not use it in a production"
" deployment. Use a production WSGI server instead.",
fg="red",
bold=True,
)
if app_import_path is not None: if app_import_path is not None:
click.echo(f" * Serving Flask app '{app_import_path}'") click.echo(f" * Serving Flask app '{app_import_path}'")
click.echo(f" * Environment: {env}")
if env == "production":
click.secho(
" WARNING: This is a development server. Do not use it in"
" a production deployment.\n Use a production WSGI server"
" instead.",
fg="red",
)
if debug is not None: if debug is not None:
click.echo(f" * Debug mode: {'on' if debug else 'off'}") click.echo(f" * Debug mode: {'on' if debug else 'off'}")
@ -925,8 +897,8 @@ def run_command(
This server is for development purposes only. It does not provide This server is for development purposes only. It does not provide
the stability, security, or performance of production WSGI servers. the stability, security, or performance of production WSGI servers.
The reloader and debugger are enabled by default with the The reloader and debugger are enabled by default with the '--debug'
'--env development' or '--debug' options. option.
""" """
try: try:
app = info.load_app() app = info.load_app()
@ -953,9 +925,7 @@ def run_command(
if debugger is None: if debugger is None:
debugger = debug debugger = debug
show_server_banner(get_env(), debug, info.app_import_path) show_server_banner(debug, info.app_import_path)
from werkzeug.serving import run_simple
run_simple( run_simple(
host, host,

View File

@ -29,22 +29,41 @@ def get_env() -> str:
"""Get the environment the app is running in, indicated by the """Get the environment the app is running in, indicated by the
:envvar:`FLASK_ENV` environment variable. The default is :envvar:`FLASK_ENV` environment variable. The default is
``'production'``. ``'production'``.
.. deprecated:: 2.2
Will be removed in Flask 2.3.
""" """
import warnings
warnings.warn(
"'FLASK_ENV' and 'get_env' are deprecated and will be removed"
" in Flask 2.3. Use 'FLASK_DEBUG' instead.",
DeprecationWarning,
stacklevel=2,
)
return os.environ.get("FLASK_ENV") or "production" return os.environ.get("FLASK_ENV") or "production"
def get_debug_flag() -> bool: def get_debug_flag() -> bool:
"""Get whether debug mode should be enabled for the app, indicated """Get whether debug mode should be enabled for the app, indicated by the
by the :envvar:`FLASK_DEBUG` environment variable. The default is :envvar:`FLASK_DEBUG` environment variable. The default is ``False``.
``True`` if :func:`.get_env` returns ``'development'``, or ``False``
otherwise.
""" """
val = os.environ.get("FLASK_DEBUG") val = os.environ.get("FLASK_DEBUG")
if not val: if not val:
return get_env() == "development" env = os.environ.get("FLASK_ENV")
return val.lower() not in ("0", "false", "no") if env is not None:
print(
"'FLASK_ENV' is deprecated and will not be used in"
" Flask 2.3. Use 'FLASK_DEBUG' instead.",
file=sys.stderr,
)
return env == "development"
return False
return val.lower() not in {"0", "false", "no"}
def get_load_dotenv(default: bool = True) -> bool: def get_load_dotenv(default: bool = True) -> bool:

View File

@ -6,7 +6,6 @@ import werkzeug.exceptions
import flask import flask
from flask.helpers import get_debug_flag from flask.helpers import get_debug_flag
from flask.helpers import get_env
class FakePath: class FakePath:
@ -322,20 +321,6 @@ class TestHelpers:
assert get_debug_flag() == expected_flag assert get_debug_flag() == expected_flag
assert get_debug_flag() == expected_default_flag assert get_debug_flag() == expected_default_flag
@pytest.mark.parametrize(
"env, ref_env, debug",
[
("", "production", False),
("production", "production", False),
("development", "development", True),
("other", "other", False),
],
)
def test_get_env(self, monkeypatch, env, ref_env, debug):
monkeypatch.setenv("FLASK_ENV", env)
assert get_debug_flag() == debug
assert get_env() == ref_env
def test_make_response(self): def test_make_response(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
with app.test_request_context(): with app.test_request_context():