deprecate config attributes

This commit is contained in:
David Lord 2022-08-01 16:53:15 -07:00
parent 98ca00d545
commit bfdd37110c
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
8 changed files with 154 additions and 57 deletions

View File

@ -27,6 +27,11 @@ Unreleased
deprecated, removing the distinction between development and debug deprecated, removing the distinction between development and debug
mode. Debug mode should be controlled directly using the ``--debug`` mode. Debug mode should be controlled directly using the ``--debug``
option or ``app.run(debug=True)``. :issue:`4714` option or ``app.run(debug=True)``. :issue:`4714`
- Some attributes that proxied config keys on ``app`` are deprecated:
``session_cookie_name``, ``send_file_max_age_default``,
``use_x_sendfile``, ``propagate_exceptions``, and
``templates_auto_reload``. Use the relevant config keys instead.
:issue:`4716`
- 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.

View File

@ -125,10 +125,9 @@ implementation that Flask is using.
.. admonition:: Notice .. admonition:: Notice
The ``PERMANENT_SESSION_LIFETIME`` config key can also be an integer The :data:`PERMANENT_SESSION_LIFETIME` config can be an integer or ``timedelta``.
starting with Flask 0.8. Either catch this down yourself or use The :attr:`~flask.Flask.permanent_session_lifetime` attribute is always a
the :attr:`~flask.Flask.permanent_session_lifetime` attribute on the ``timedelta``.
app which converts the result to an integer automatically.
Test Client Test Client

View File

@ -99,7 +99,7 @@ else:
return inspect.iscoroutinefunction(func) return inspect.iscoroutinefunction(func)
def _make_timedelta(value: t.Optional[timedelta]) -> t.Optional[timedelta]: def _make_timedelta(value: t.Union[timedelta, int, None]) -> t.Optional[timedelta]:
if value is None or isinstance(value, timedelta): if value is None or isinstance(value, timedelta):
return value return value
@ -273,11 +273,35 @@ class Flask(Scaffold):
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``. #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
secret_key = ConfigAttribute("SECRET_KEY") secret_key = ConfigAttribute("SECRET_KEY")
#: The secure cookie uses this for the name of the session cookie. @property
#: def session_cookie_name(self) -> str:
#: This attribute can also be configured from the config with the """The name of the cookie set by the session interface.
#: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME") .. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``app.config["SESSION_COOKIE_NAME"]``
instead.
"""
import warnings
warnings.warn(
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
return self.config["SESSION_COOKIE_NAME"]
@session_cookie_name.setter
def session_cookie_name(self, value: str) -> None:
import warnings
warnings.warn(
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
self.config["SESSION_COOKIE_NAME"] = value
#: A :class:`~datetime.timedelta` which is used to set the expiration #: A :class:`~datetime.timedelta` which is used to set the expiration
#: date of a permanent session. The default is 31 days which makes a #: date of a permanent session. The default is 31 days which makes a
@ -290,29 +314,70 @@ class Flask(Scaffold):
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
) )
#: A :class:`~datetime.timedelta` or number of seconds which is used @property
#: as the default ``max_age`` for :func:`send_file`. The default is def send_file_max_age_default(self) -> t.Optional[timedelta]:
#: ``None``, which tells the browser to use conditional requests """The default value for ``max_age`` for :func:`~flask.send_file`. The default
#: instead of a timed cache. is ``None``, which tells the browser to use conditional requests instead of a
#: timed cache.
#: Configured with the :data:`SEND_FILE_MAX_AGE_DEFAULT`
#: configuration key.
#:
#: .. versionchanged:: 2.0
#: Defaults to ``None`` instead of 12 hours.
send_file_max_age_default = ConfigAttribute(
"SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
)
#: Enable this if you want to use the X-Sendfile feature. Keep in .. deprecated:: 2.2
#: mind that the server has to support this. This only affects files Will be removed in Flask 2.3. Use
#: sent with the :func:`send_file` method. ``app.config["SEND_FILE_MAX_AGE_DEFAULT"]`` instead.
#:
#: .. versionadded:: 0.2 .. versionchanged:: 2.0
#: Defaults to ``None`` instead of 12 hours.
#: This attribute can also be configured from the config with the """
#: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``. import warnings
use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
warnings.warn(
"'send_file_max_age_default' is deprecated and will be removed in Flask"
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
return _make_timedelta(self.config["SEND_FILE_MAX_AGE_DEFAULT"])
@send_file_max_age_default.setter
def send_file_max_age_default(self, value: t.Union[int, timedelta, None]) -> None:
import warnings
warnings.warn(
"'send_file_max_age_default' is deprecated and will be removed in Flask"
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
self.config["SEND_FILE_MAX_AGE_DEFAULT"] = _make_timedelta(value)
@property
def use_x_sendfile(self) -> bool:
"""Enable this to use the ``X-Sendfile`` feature, assuming the server supports
it, from :func:`~flask.send_file`.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``app.config["USE_X_SENDFILE"]`` instead.
"""
import warnings
warnings.warn(
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
" 'USE_X_SENDFILE' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
return self.config["USE_X_SENDFILE"]
@use_x_sendfile.setter
def use_x_sendfile(self, value: bool) -> None:
import warnings
warnings.warn(
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
" 'USE_X_SENDFILE' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
self.config["USE_X_SENDFILE"] = value
#: The JSON encoder class to use. Defaults to #: The JSON encoder class to use. Defaults to
#: :class:`~flask.json.JSONEncoder`. #: :class:`~flask.json.JSONEncoder`.
@ -624,8 +689,18 @@ class Flask(Scaffold):
"""Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
value in case it's set, otherwise a sensible default is returned. value in case it's set, otherwise a sensible default is returned.
.. deprecated:: 2.2
Will be removed in Flask 2.3.
.. versionadded:: 0.7 .. versionadded:: 0.7
""" """
import warnings
warnings.warn(
"'propagate_exceptions' is deprecated and will be removed in Flask 2.3.",
DeprecationWarning,
stacklevel=2,
)
rv = self.config["PROPAGATE_EXCEPTIONS"] rv = self.config["PROPAGATE_EXCEPTIONS"]
if rv is not None: if rv is not None:
return rv return rv
@ -734,20 +809,37 @@ class Flask(Scaffold):
@property @property
def templates_auto_reload(self) -> bool: def templates_auto_reload(self) -> bool:
"""Reload templates when they are changed. Used by """Reload templates when they are changed. Used by
:meth:`create_jinja_environment`. :meth:`create_jinja_environment`. It is enabled by default in debug mode.
This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If .. deprecated:: 2.2
not set, it will be enabled in debug mode. Will be removed in Flask 2.3. Use ``app.config["TEMPLATES_AUTO_RELOAD"]``
instead.
.. versionadded:: 1.0 .. versionadded:: 1.0
This property was added but the underlying config and behavior This property was added but the underlying config and behavior
already existed. already existed.
""" """
import warnings
warnings.warn(
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
rv = self.config["TEMPLATES_AUTO_RELOAD"] rv = self.config["TEMPLATES_AUTO_RELOAD"]
return rv if rv is not None else self.debug return rv if rv is not None else self.debug
@templates_auto_reload.setter @templates_auto_reload.setter
def templates_auto_reload(self, value: bool) -> None: def templates_auto_reload(self, value: bool) -> None:
import warnings
warnings.warn(
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
DeprecationWarning,
stacklevel=2,
)
self.config["TEMPLATES_AUTO_RELOAD"] = value self.config["TEMPLATES_AUTO_RELOAD"] = value
def create_jinja_environment(self) -> Environment: def create_jinja_environment(self) -> Environment:
@ -768,7 +860,12 @@ class Flask(Scaffold):
options["autoescape"] = self.select_jinja_autoescape options["autoescape"] = self.select_jinja_autoescape
if "auto_reload" not in options: if "auto_reload" not in options:
options["auto_reload"] = self.templates_auto_reload auto_reload = self.config["TEMPLATES_AUTO_RELOAD"]
if auto_reload is None:
auto_reload = self.debug
options["auto_reload"] = auto_reload
rv = self.jinja_environment(self, **options) rv = self.jinja_environment(self, **options)
rv.globals.update( rv.globals.update(
@ -898,7 +995,9 @@ class Flask(Scaffold):
@debug.setter @debug.setter
def debug(self, value: bool) -> None: def debug(self, value: bool) -> None:
self.config["DEBUG"] = value self.config["DEBUG"] = value
self.jinja_env.auto_reload = self.templates_auto_reload
if self.config["TEMPLATES_AUTO_RELOAD"] is None:
self.jinja_env.auto_reload = value
def run( def run(
self, self,
@ -1541,8 +1640,12 @@ class Flask(Scaffold):
""" """
exc_info = sys.exc_info() exc_info = sys.exc_info()
got_request_exception.send(self, exception=e) got_request_exception.send(self, exception=e)
propagate = self.config["PROPAGATE_EXCEPTIONS"]
if self.propagate_exceptions: if propagate is None:
propagate = self.testing or self.debug
if propagate:
# Re-raise if called with an active exception, otherwise # Re-raise if called with an active exception, otherwise
# raise the passed in exception. # raise the passed in exception.
if exc_info[1] is e: if exc_info[1] is e:

View File

@ -414,7 +414,7 @@ def _prepare_send_file_kwargs(**kwargs: t.Any) -> t.Dict[str, t.Any]:
kwargs.update( kwargs.update(
environ=request.environ, environ=request.environ,
use_x_sendfile=current_app.use_x_sendfile, use_x_sendfile=current_app.config["USE_X_SENDFILE"],
response_class=current_app.response_class, response_class=current_app.response_class,
_root_path=current_app.root_path, # type: ignore _root_path=current_app.root_path, # type: ignore
) )

View File

@ -5,6 +5,7 @@ import pkgutil
import sys import sys
import typing as t import typing as t
from collections import defaultdict from collections import defaultdict
from datetime import timedelta
from functools import update_wrapper from functools import update_wrapper
from jinja2 import FileSystemLoader from jinja2 import FileSystemLoader
@ -302,13 +303,16 @@ class Scaffold:
.. versionadded:: 0.9 .. versionadded:: 0.9
""" """
value = current_app.send_file_max_age_default value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]
if value is None: if value is None:
return None return None
if isinstance(value, timedelta):
return int(value.total_seconds()) return int(value.total_seconds())
return value
def send_static_file(self, filename: str) -> "Response": def send_static_file(self, filename: str) -> "Response":
"""The view function used to serve files from """The view function used to serve files from
:attr:`static_folder`. A route is automatically registered for :attr:`static_folder`. A route is automatically registered for

View File

@ -177,11 +177,8 @@ class SessionInterface:
return isinstance(obj, self.null_session_class) return isinstance(obj, self.null_session_class)
def get_cookie_name(self, app: "Flask") -> str: def get_cookie_name(self, app: "Flask") -> str:
"""Returns the name of the session cookie. """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``."""
return app.config["SESSION_COOKIE_NAME"]
Uses ``app.session_cookie_name`` which is set to ``SESSION_COOKIE_NAME``
"""
return app.session_cookie_name
def get_cookie_domain(self, app: "Flask") -> t.Optional[str]: def get_cookie_domain(self, app: "Flask") -> t.Optional[str]:
"""Returns the domain that should be set for the session cookie. """Returns the domain that should be set for the session cookie.

View File

@ -1,7 +1,6 @@
import json import json
import os import os
import textwrap import textwrap
from datetime import timedelta
import pytest import pytest
@ -207,14 +206,6 @@ def test_session_lifetime():
assert app.permanent_session_lifetime.seconds == 42 assert app.permanent_session_lifetime.seconds == 42
def test_send_file_max_age():
app = flask.Flask(__name__)
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600
assert app.send_file_max_age_default.seconds == 3600
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = timedelta(hours=2)
assert app.send_file_max_age_default.seconds == 7200
def test_get_namespace(): def test_get_namespace():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config["FOO_OPTION_1"] = "foo option 1" app.config["FOO_OPTION_1"] = "foo option 1"

View File

@ -397,11 +397,9 @@ def test_templates_auto_reload_debug_run(app, monkeypatch):
monkeypatch.setattr(werkzeug.serving, "run_simple", run_simple_mock) monkeypatch.setattr(werkzeug.serving, "run_simple", run_simple_mock)
app.run() app.run()
assert not app.templates_auto_reload
assert not app.jinja_env.auto_reload assert not app.jinja_env.auto_reload
app.run(debug=True) app.run(debug=True)
assert app.templates_auto_reload
assert app.jinja_env.auto_reload assert app.jinja_env.auto_reload