Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate config attributes #4722

Merged
merged 1 commit into from Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.rst
Expand Up @@ -27,6 +27,11 @@ Unreleased
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`
- 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
previously global behaviors.

Expand Down
7 changes: 3 additions & 4 deletions docs/api.rst
Expand Up @@ -125,10 +125,9 @@ implementation that Flask is using.

.. admonition:: Notice

The ``PERMANENT_SESSION_LIFETIME`` config key can also be an integer
starting with Flask 0.8. Either catch this down yourself or use
the :attr:`~flask.Flask.permanent_session_lifetime` attribute on the
app which converts the result to an integer automatically.
The :data:`PERMANENT_SESSION_LIFETIME` config can be an integer or ``timedelta``.
The :attr:`~flask.Flask.permanent_session_lifetime` attribute is always a
``timedelta``.


Test Client
Expand Down
171 changes: 137 additions & 34 deletions src/flask/app.py
Expand Up @@ -99,7 +99,7 @@ def iscoroutinefunction(func: t.Any) -> bool:
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):
return value

Expand Down Expand Up @@ -273,11 +273,35 @@ class Flask(Scaffold):
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
secret_key = ConfigAttribute("SECRET_KEY")

#: The secure cookie uses this for the name of the session cookie.
#:
#: This attribute can also be configured from the config with the
#: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
@property
def session_cookie_name(self) -> str:
"""The name of the cookie set by the session interface.

.. 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
#: date of a permanent session. The default is 31 days which makes a
Expand All @@ -290,29 +314,70 @@ class Flask(Scaffold):
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
)

#: A :class:`~datetime.timedelta` or number of seconds which is used
#: as the default ``max_age`` for :func:`send_file`. The default 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
)
@property
def send_file_max_age_default(self) -> t.Optional[timedelta]:
"""The default value for ``max_age`` for :func:`~flask.send_file`. The default
is ``None``, which tells the browser to use conditional requests instead of a
timed cache.

#: Enable this if you want to use the X-Sendfile feature. Keep in
#: mind that the server has to support this. This only affects files
#: sent with the :func:`send_file` method.
#:
#: .. versionadded:: 0.2
#:
#: This attribute can also be configured from the config with the
#: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use
``app.config["SEND_FILE_MAX_AGE_DEFAULT"]`` instead.

.. versionchanged:: 2.0
Defaults to ``None`` instead of 12 hours.
"""
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,
)
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
#: :class:`~flask.json.JSONEncoder`.
Expand Down Expand Up @@ -624,8 +689,18 @@ def propagate_exceptions(self) -> bool:
"""Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
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
"""
import warnings

warnings.warn(
"'propagate_exceptions' is deprecated and will be removed in Flask 2.3.",
DeprecationWarning,
stacklevel=2,
)
rv = self.config["PROPAGATE_EXCEPTIONS"]
if rv is not None:
return rv
Expand Down Expand Up @@ -734,20 +809,37 @@ def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyS
@property
def templates_auto_reload(self) -> bool:
"""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
not set, it will be enabled in debug mode.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``app.config["TEMPLATES_AUTO_RELOAD"]``
instead.

.. versionadded:: 1.0
This property was added but the underlying config and behavior
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"]
return rv if rv is not None else self.debug

@templates_auto_reload.setter
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

def create_jinja_environment(self) -> Environment:
Expand All @@ -768,7 +860,12 @@ def create_jinja_environment(self) -> Environment:
options["autoescape"] = self.select_jinja_autoescape

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.globals.update(
Expand Down Expand Up @@ -898,7 +995,9 @@ def debug(self) -> bool:
@debug.setter
def debug(self, value: bool) -> None:
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(
self,
Expand Down Expand Up @@ -1541,8 +1640,12 @@ def handle_exception(self, e: Exception) -> Response:
"""
exc_info = sys.exc_info()
got_request_exception.send(self, exception=e)
propagate = self.config["PROPAGATE_EXCEPTIONS"]

if propagate is None:
propagate = self.testing or self.debug

if self.propagate_exceptions:
if propagate:
# Re-raise if called with an active exception, otherwise
# raise the passed in exception.
if exc_info[1] is e:
Expand Down
2 changes: 1 addition & 1 deletion src/flask/helpers.py
Expand Up @@ -414,7 +414,7 @@ def _prepare_send_file_kwargs(**kwargs: t.Any) -> t.Dict[str, t.Any]:

kwargs.update(
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,
_root_path=current_app.root_path, # type: ignore
)
Expand Down
8 changes: 6 additions & 2 deletions src/flask/scaffold.py
Expand Up @@ -5,6 +5,7 @@
import sys
import typing as t
from collections import defaultdict
from datetime import timedelta
from functools import update_wrapper

from jinja2 import FileSystemLoader
Expand Down Expand Up @@ -302,12 +303,15 @@ def get_send_file_max_age(self, filename: t.Optional[str]) -> t.Optional[int]:

.. versionadded:: 0.9
"""
value = current_app.send_file_max_age_default
value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]

if value is None:
return None

return int(value.total_seconds())
if isinstance(value, timedelta):
return int(value.total_seconds())

return value

def send_static_file(self, filename: str) -> "Response":
"""The view function used to serve files from
Expand Down
7 changes: 2 additions & 5 deletions src/flask/sessions.py
Expand Up @@ -177,11 +177,8 @@ def is_null_session(self, obj: object) -> bool:
return isinstance(obj, self.null_session_class)

def get_cookie_name(self, app: "Flask") -> str:
"""Returns the name of the session cookie.

Uses ``app.session_cookie_name`` which is set to ``SESSION_COOKIE_NAME``
"""
return app.session_cookie_name
"""The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``."""
return app.config["SESSION_COOKIE_NAME"]

def get_cookie_domain(self, app: "Flask") -> t.Optional[str]:
"""Returns the domain that should be set for the session cookie.
Expand Down
9 changes: 0 additions & 9 deletions tests/test_config.py
@@ -1,7 +1,6 @@
import json
import os
import textwrap
from datetime import timedelta

import pytest

Expand Down Expand Up @@ -207,14 +206,6 @@ def test_session_lifetime():
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():
app = flask.Flask(__name__)
app.config["FOO_OPTION_1"] = "foo option 1"
Expand Down
2 changes: 0 additions & 2 deletions tests/test_templating.py
Expand Up @@ -397,11 +397,9 @@ def run_simple_mock(*args, **kwargs):
monkeypatch.setattr(werkzeug.serving, "run_simple", run_simple_mock)

app.run()
assert not app.templates_auto_reload
assert not app.jinja_env.auto_reload

app.run(debug=True)
assert app.templates_auto_reload
assert app.jinja_env.auto_reload


Expand Down