Skip to content

Commit bfdd371

Browse files
committed
deprecate config attributes
1 parent 98ca00d commit bfdd371

File tree

8 files changed

+154
-57
lines changed

8 files changed

+154
-57
lines changed

CHANGES.rst

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Unreleased
2727
deprecated, removing the distinction between development and debug
2828
mode. Debug mode should be controlled directly using the ``--debug``
2929
option or ``app.run(debug=True)``. :issue:`4714`
30+
- Some attributes that proxied config keys on ``app`` are deprecated:
31+
``session_cookie_name``, ``send_file_max_age_default``,
32+
``use_x_sendfile``, ``propagate_exceptions``, and
33+
``templates_auto_reload``. Use the relevant config keys instead.
34+
:issue:`4716`
3035
- Add new customization points to the ``Flask`` app object for many
3136
previously global behaviors.
3237

docs/api.rst

+3-4
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,9 @@ implementation that Flask is using.
125125

126126
.. admonition:: Notice
127127

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

133132

134133
Test Client

src/flask/app.py

+137-34
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def iscoroutinefunction(func: t.Any) -> bool:
9999
return inspect.iscoroutinefunction(func)
100100

101101

102-
def _make_timedelta(value: t.Optional[timedelta]) -> t.Optional[timedelta]:
102+
def _make_timedelta(value: t.Union[timedelta, int, None]) -> t.Optional[timedelta]:
103103
if value is None or isinstance(value, timedelta):
104104
return value
105105

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

276-
#: The secure cookie uses this for the name of the session cookie.
277-
#:
278-
#: This attribute can also be configured from the config with the
279-
#: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
280-
session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
276+
@property
277+
def session_cookie_name(self) -> str:
278+
"""The name of the cookie set by the session interface.
279+
280+
.. deprecated:: 2.2
281+
Will be removed in Flask 2.3. Use ``app.config["SESSION_COOKIE_NAME"]``
282+
instead.
283+
"""
284+
import warnings
285+
286+
warnings.warn(
287+
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
288+
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
289+
DeprecationWarning,
290+
stacklevel=2,
291+
)
292+
return self.config["SESSION_COOKIE_NAME"]
293+
294+
@session_cookie_name.setter
295+
def session_cookie_name(self, value: str) -> None:
296+
import warnings
297+
298+
warnings.warn(
299+
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
300+
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
301+
DeprecationWarning,
302+
stacklevel=2,
303+
)
304+
self.config["SESSION_COOKIE_NAME"] = value
281305

282306
#: A :class:`~datetime.timedelta` which is used to set the expiration
283307
#: date of a permanent session. The default is 31 days which makes a
@@ -290,29 +314,70 @@ class Flask(Scaffold):
290314
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
291315
)
292316

293-
#: A :class:`~datetime.timedelta` or number of seconds which is used
294-
#: as the default ``max_age`` for :func:`send_file`. The default is
295-
#: ``None``, which tells the browser to use conditional requests
296-
#: instead of a timed cache.
297-
#:
298-
#: Configured with the :data:`SEND_FILE_MAX_AGE_DEFAULT`
299-
#: configuration key.
300-
#:
301-
#: .. versionchanged:: 2.0
302-
#: Defaults to ``None`` instead of 12 hours.
303-
send_file_max_age_default = ConfigAttribute(
304-
"SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
305-
)
317+
@property
318+
def send_file_max_age_default(self) -> t.Optional[timedelta]:
319+
"""The default value for ``max_age`` for :func:`~flask.send_file`. The default
320+
is ``None``, which tells the browser to use conditional requests instead of a
321+
timed cache.
306322
307-
#: Enable this if you want to use the X-Sendfile feature. Keep in
308-
#: mind that the server has to support this. This only affects files
309-
#: sent with the :func:`send_file` method.
310-
#:
311-
#: .. versionadded:: 0.2
312-
#:
313-
#: This attribute can also be configured from the config with the
314-
#: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
315-
use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
323+
.. deprecated:: 2.2
324+
Will be removed in Flask 2.3. Use
325+
``app.config["SEND_FILE_MAX_AGE_DEFAULT"]`` instead.
326+
327+
.. versionchanged:: 2.0
328+
Defaults to ``None`` instead of 12 hours.
329+
"""
330+
import warnings
331+
332+
warnings.warn(
333+
"'send_file_max_age_default' is deprecated and will be removed in Flask"
334+
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
335+
DeprecationWarning,
336+
stacklevel=2,
337+
)
338+
return _make_timedelta(self.config["SEND_FILE_MAX_AGE_DEFAULT"])
339+
340+
@send_file_max_age_default.setter
341+
def send_file_max_age_default(self, value: t.Union[int, timedelta, None]) -> None:
342+
import warnings
343+
344+
warnings.warn(
345+
"'send_file_max_age_default' is deprecated and will be removed in Flask"
346+
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
347+
DeprecationWarning,
348+
stacklevel=2,
349+
)
350+
self.config["SEND_FILE_MAX_AGE_DEFAULT"] = _make_timedelta(value)
351+
352+
@property
353+
def use_x_sendfile(self) -> bool:
354+
"""Enable this to use the ``X-Sendfile`` feature, assuming the server supports
355+
it, from :func:`~flask.send_file`.
356+
357+
.. deprecated:: 2.2
358+
Will be removed in Flask 2.3. Use ``app.config["USE_X_SENDFILE"]`` instead.
359+
"""
360+
import warnings
361+
362+
warnings.warn(
363+
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
364+
" 'USE_X_SENDFILE' in 'app.config' instead.",
365+
DeprecationWarning,
366+
stacklevel=2,
367+
)
368+
return self.config["USE_X_SENDFILE"]
369+
370+
@use_x_sendfile.setter
371+
def use_x_sendfile(self, value: bool) -> None:
372+
import warnings
373+
374+
warnings.warn(
375+
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
376+
" 'USE_X_SENDFILE' in 'app.config' instead.",
377+
DeprecationWarning,
378+
stacklevel=2,
379+
)
380+
self.config["USE_X_SENDFILE"] = value
316381

317382
#: The JSON encoder class to use. Defaults to
318383
#: :class:`~flask.json.JSONEncoder`.
@@ -624,8 +689,18 @@ def propagate_exceptions(self) -> bool:
624689
"""Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
625690
value in case it's set, otherwise a sensible default is returned.
626691
692+
.. deprecated:: 2.2
693+
Will be removed in Flask 2.3.
694+
627695
.. versionadded:: 0.7
628696
"""
697+
import warnings
698+
699+
warnings.warn(
700+
"'propagate_exceptions' is deprecated and will be removed in Flask 2.3.",
701+
DeprecationWarning,
702+
stacklevel=2,
703+
)
629704
rv = self.config["PROPAGATE_EXCEPTIONS"]
630705
if rv is not None:
631706
return rv
@@ -734,20 +809,37 @@ def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyS
734809
@property
735810
def templates_auto_reload(self) -> bool:
736811
"""Reload templates when they are changed. Used by
737-
:meth:`create_jinja_environment`.
812+
:meth:`create_jinja_environment`. It is enabled by default in debug mode.
738813
739-
This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If
740-
not set, it will be enabled in debug mode.
814+
.. deprecated:: 2.2
815+
Will be removed in Flask 2.3. Use ``app.config["TEMPLATES_AUTO_RELOAD"]``
816+
instead.
741817
742818
.. versionadded:: 1.0
743819
This property was added but the underlying config and behavior
744820
already existed.
745821
"""
822+
import warnings
823+
824+
warnings.warn(
825+
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
826+
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
827+
DeprecationWarning,
828+
stacklevel=2,
829+
)
746830
rv = self.config["TEMPLATES_AUTO_RELOAD"]
747831
return rv if rv is not None else self.debug
748832

749833
@templates_auto_reload.setter
750834
def templates_auto_reload(self, value: bool) -> None:
835+
import warnings
836+
837+
warnings.warn(
838+
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
839+
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
840+
DeprecationWarning,
841+
stacklevel=2,
842+
)
751843
self.config["TEMPLATES_AUTO_RELOAD"] = value
752844

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

770862
if "auto_reload" not in options:
771-
options["auto_reload"] = self.templates_auto_reload
863+
auto_reload = self.config["TEMPLATES_AUTO_RELOAD"]
864+
865+
if auto_reload is None:
866+
auto_reload = self.debug
867+
868+
options["auto_reload"] = auto_reload
772869

773870
rv = self.jinja_environment(self, **options)
774871
rv.globals.update(
@@ -898,7 +995,9 @@ def debug(self) -> bool:
898995
@debug.setter
899996
def debug(self, value: bool) -> None:
900997
self.config["DEBUG"] = value
901-
self.jinja_env.auto_reload = self.templates_auto_reload
998+
999+
if self.config["TEMPLATES_AUTO_RELOAD"] is None:
1000+
self.jinja_env.auto_reload = value
9021001

9031002
def run(
9041003
self,
@@ -1541,8 +1640,12 @@ def handle_exception(self, e: Exception) -> Response:
15411640
"""
15421641
exc_info = sys.exc_info()
15431642
got_request_exception.send(self, exception=e)
1643+
propagate = self.config["PROPAGATE_EXCEPTIONS"]
1644+
1645+
if propagate is None:
1646+
propagate = self.testing or self.debug
15441647

1545-
if self.propagate_exceptions:
1648+
if propagate:
15461649
# Re-raise if called with an active exception, otherwise
15471650
# raise the passed in exception.
15481651
if exc_info[1] is e:

src/flask/helpers.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def _prepare_send_file_kwargs(**kwargs: t.Any) -> t.Dict[str, t.Any]:
414414

415415
kwargs.update(
416416
environ=request.environ,
417-
use_x_sendfile=current_app.use_x_sendfile,
417+
use_x_sendfile=current_app.config["USE_X_SENDFILE"],
418418
response_class=current_app.response_class,
419419
_root_path=current_app.root_path, # type: ignore
420420
)

src/flask/scaffold.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66
import typing as t
77
from collections import defaultdict
8+
from datetime import timedelta
89
from functools import update_wrapper
910

1011
from jinja2 import FileSystemLoader
@@ -302,12 +303,15 @@ def get_send_file_max_age(self, filename: t.Optional[str]) -> t.Optional[int]:
302303
303304
.. versionadded:: 0.9
304305
"""
305-
value = current_app.send_file_max_age_default
306+
value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]
306307

307308
if value is None:
308309
return None
309310

310-
return int(value.total_seconds())
311+
if isinstance(value, timedelta):
312+
return int(value.total_seconds())
313+
314+
return value
311315

312316
def send_static_file(self, filename: str) -> "Response":
313317
"""The view function used to serve files from

src/flask/sessions.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,8 @@ def is_null_session(self, obj: object) -> bool:
177177
return isinstance(obj, self.null_session_class)
178178

179179
def get_cookie_name(self, app: "Flask") -> str:
180-
"""Returns the name of the session cookie.
181-
182-
Uses ``app.session_cookie_name`` which is set to ``SESSION_COOKIE_NAME``
183-
"""
184-
return app.session_cookie_name
180+
"""The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``."""
181+
return app.config["SESSION_COOKIE_NAME"]
185182

186183
def get_cookie_domain(self, app: "Flask") -> t.Optional[str]:
187184
"""Returns the domain that should be set for the session cookie.

tests/test_config.py

-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import json
22
import os
33
import textwrap
4-
from datetime import timedelta
54

65
import pytest
76

@@ -207,14 +206,6 @@ def test_session_lifetime():
207206
assert app.permanent_session_lifetime.seconds == 42
208207

209208

210-
def test_send_file_max_age():
211-
app = flask.Flask(__name__)
212-
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600
213-
assert app.send_file_max_age_default.seconds == 3600
214-
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = timedelta(hours=2)
215-
assert app.send_file_max_age_default.seconds == 7200
216-
217-
218209
def test_get_namespace():
219210
app = flask.Flask(__name__)
220211
app.config["FOO_OPTION_1"] = "foo option 1"

tests/test_templating.py

-2
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,9 @@ def run_simple_mock(*args, **kwargs):
397397
monkeypatch.setattr(werkzeug.serving, "run_simple", run_simple_mock)
398398

399399
app.run()
400-
assert not app.templates_auto_reload
401400
assert not app.jinja_env.auto_reload
402401

403402
app.run(debug=True)
404-
assert app.templates_auto_reload
405403
assert app.jinja_env.auto_reload
406404

407405

0 commit comments

Comments
 (0)