remove previously deprecated code

This commit is contained in:
David Lord 2023-02-23 08:35:16 -08:00
parent 604de4b1dc
commit 6650764e97
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
16 changed files with 81 additions and 946 deletions

View File

@ -3,6 +3,24 @@ Version 2.3.0
Unreleased
- Remove previously deprecated code. :pr:`4995`
- The ``push`` and ``pop`` methods of the deprecated ``_app_ctx_stack`` and
``_request_ctx_stack`` objects are removed. ``top`` still exists to give
extensions more time to update, but it will be removed.
- The ``FLASK_ENV`` environment variable, ``ENV`` config key, and ``app.env``
property are removed.
- The ``session_cookie_name``, ``send_file_max_age_default``, ``use_x_sendfile``,
``propagate_exceptions``, and ``templates_auto_reload`` properties on ``app``
are removed.
- The ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
``JSONIFY_PRETTYPRINT_REGULAR`` config keys are removed.
- The ``app.before_first_request`` and ``bp.before_app_first_request`` decorators
are removed.
- ``json_encoder`` and ``json_decoder`` attributes on app and blueprint, and the
corresponding ``json.JSONEncoder`` and ``JSONDecoder`` classes, are removed.
- The ``json.htmlsafe_dumps`` and ``htmlsafe_dump`` functions are removed.
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.
:pr:`4947`
- Ensure subdomains are applied with nested blueprints. :issue:`4834`

View File

@ -270,12 +270,6 @@ HTML ``<script>`` tags.
:members:
:member-order: bysource
.. autoclass:: JSONEncoder
:members:
.. autoclass:: JSONDecoder
:members:
.. automodule:: flask.json.tag

View File

@ -65,18 +65,6 @@ Builtin Configuration Values
The following configuration values are used internally by Flask:
.. py:data:: ENV
What environment the app is running in. The :attr:`~flask.Flask.env` attribute maps
to this config key.
Default: ``'production'``
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``--debug`` instead.
.. versionadded:: 1.0
.. py:data:: DEBUG
Whether debug mode is enabled. When using ``flask run`` to start the development
@ -271,52 +259,6 @@ The following configuration values are used internally by Flask:
Default: ``None``
.. py:data:: JSON_AS_ASCII
Serialize objects to ASCII-encoded JSON. If this is disabled, the
JSON returned from ``jsonify`` will contain Unicode characters. This
has security implications when rendering the JSON into JavaScript in
templates, and should typically remain enabled.
Default: ``True``
.. deprecated:: 2.2
Will be removed in Flask 2.3. Set ``app.json.ensure_ascii``
instead.
.. py:data:: JSON_SORT_KEYS
Sort the keys of JSON objects alphabetically. This is useful for caching
because it ensures the data is serialized the same way no matter what
Python's hash seed is. While not recommended, you can disable this for a
possible performance improvement at the cost of caching.
Default: ``True``
.. deprecated:: 2.2
Will be removed in Flask 2.3. Set ``app.json.sort_keys``
instead.
.. py:data:: JSONIFY_PRETTYPRINT_REGULAR
:func:`~flask.jsonify` responses will be output with newlines,
spaces, and indentation for easier reading by humans. Always enabled
in debug mode.
Default: ``False``
.. deprecated:: 2.2
Will be removed in Flask 2.3. Set ``app.json.compact`` instead.
.. py:data:: JSONIFY_MIMETYPE
The mimetype of ``jsonify`` responses.
Default: ``'application/json'``
.. deprecated:: 2.2
Will be removed in Flask 2.3. Set ``app.json.mimetype`` instead.
.. py:data:: TEMPLATES_AUTO_RELOAD
Reload templates when they are changed. If not set, it will be enabled in
@ -381,14 +323,13 @@ The following configuration values are used internally by Flask:
.. versionchanged:: 2.2
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
.. versionchanged:: 2.2
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``,
``JSONIFY_MIMETYPE``, and ``JSONIFY_PRETTYPRINT_REGULAR`` will be
removed in Flask 2.3. The default ``app.json`` provider has
.. versionchanged:: 2.3
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
``JSONIFY_PRETTYPRINT_REGULAR`` were removed. The default ``app.json`` provider has
equivalent attributes instead.
.. versionchanged:: 2.2
``ENV`` will be removed in Flask 2.3. Use ``--debug`` instead.
.. versionchanged:: 2.3
``ENV`` was removed.
Configuring from Python Files

View File

@ -51,7 +51,7 @@ def __getattr__(name):
from .globals import __app_ctx_stack
warnings.warn(
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.3.",
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.",
DeprecationWarning,
stacklevel=2,
)
@ -62,7 +62,7 @@ def __getattr__(name):
from .globals import __request_ctx_stack
warnings.warn(
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.3.",
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.",
DeprecationWarning,
stacklevel=2,
)

View File

@ -1,6 +1,5 @@
import functools
import inspect
import json
import logging
import os
import sys
@ -75,9 +74,6 @@ if t.TYPE_CHECKING: # pragma: no cover
from .testing import FlaskClient
from .testing import FlaskCliRunner
T_before_first_request = t.TypeVar(
"T_before_first_request", bound=ft.BeforeFirstRequestCallable
)
T_shell_context_processor = t.TypeVar(
"T_shell_context_processor", bound=ft.ShellContextProcessorCallable
)
@ -274,36 +270,6 @@ class Flask(Scaffold):
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
secret_key = ConfigAttribute("SECRET_KEY")
@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
#: permanent session survive for roughly one month.
@ -315,152 +281,6 @@ class Flask(Scaffold):
"PERMANENT_SESSION_LIFETIME", 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.
.. 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
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
@property # type: ignore[override]
def json_encoder(self) -> t.Type[json.JSONEncoder]:
"""The JSON encoder class to use. Defaults to
:class:`~flask.json.JSONEncoder`.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.
.. versionadded:: 0.10
"""
import warnings
warnings.warn(
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
if self._json_encoder is None:
from . import json
return json.JSONEncoder
return self._json_encoder
@json_encoder.setter
def json_encoder(self, value: t.Type[json.JSONEncoder]) -> None:
import warnings
warnings.warn(
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_encoder = value
@property # type: ignore[override]
def json_decoder(self) -> t.Type[json.JSONDecoder]:
"""The JSON decoder class to use. Defaults to
:class:`~flask.json.JSONDecoder`.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.
.. versionadded:: 0.10
"""
import warnings
warnings.warn(
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
if self._json_decoder is None:
from . import json
return json.JSONDecoder
return self._json_decoder
@json_decoder.setter
def json_decoder(self, value: t.Type[json.JSONDecoder]) -> None:
import warnings
warnings.warn(
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_decoder = value
json_provider_class: t.Type[JSONProvider] = DefaultJSONProvider
"""A subclass of :class:`~flask.json.provider.JSONProvider`. An
instance is created and assigned to :attr:`app.json` when creating
@ -487,7 +307,6 @@ class Flask(Scaffold):
#: Default configuration parameters.
default_config = ImmutableDict(
{
"ENV": None,
"DEBUG": None,
"TESTING": False,
"PROPAGATE_EXCEPTIONS": None,
@ -509,10 +328,6 @@ class Flask(Scaffold):
"TRAP_HTTP_EXCEPTIONS": False,
"EXPLAIN_TEMPLATE_LOADING": False,
"PREFERRED_URL_SCHEME": "http",
"JSON_AS_ASCII": None,
"JSON_SORT_KEYS": None,
"JSONIFY_PRETTYPRINT_REGULAR": None,
"JSONIFY_MIMETYPE": None,
"TEMPLATES_AUTO_RELOAD": None,
"MAX_COOKIE_SIZE": 4093,
}
@ -625,17 +440,6 @@ class Flask(Scaffold):
t.Callable[[Exception, str, t.Dict[str, t.Any]], str]
] = []
#: A list of functions that will be called at the beginning of the
#: first request to this instance. To register a function, use the
#: :meth:`before_first_request` decorator.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3. Run setup code when
#: creating the application instead.
#:
#: .. versionadded:: 0.8
self.before_first_request_funcs: t.List[ft.BeforeFirstRequestCallable] = []
#: A list of functions that are called when the application context
#: is destroyed. Since the application context is also torn down
#: if the request ends this is the place to store code that disconnects
@ -746,28 +550,6 @@ class Flask(Scaffold):
return os.path.splitext(os.path.basename(fn))[0]
return self.import_name
@property
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
return self.testing or self.debug
@locked_cached_property
def logger(self) -> logging.Logger:
"""A standard Python :class:`~logging.Logger` for the app, with
@ -827,7 +609,6 @@ class Flask(Scaffold):
if instance_relative:
root_path = self.instance_path
defaults = dict(self.default_config)
defaults["ENV"] = os.environ.get("FLASK_ENV") or "production"
defaults["DEBUG"] = get_debug_flag()
return self.config_class(root_path, defaults)
@ -868,42 +649,6 @@ class Flask(Scaffold):
"""
return open(os.path.join(self.instance_path, resource), mode)
@property
def templates_auto_reload(self) -> bool:
"""Reload templates when they are changed. Used by
:meth:`create_jinja_environment`. It is enabled by default 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:
"""Create the Jinja environment based on :attr:`jinja_options`
and the various Jinja-related methods of the app. Changing
@ -1010,40 +755,6 @@ class Flask(Scaffold):
rv.update(processor())
return rv
@property
def env(self) -> str:
"""What environment the app is running in. This maps to the :data:`ENV` config
key.
**Do not enable development when deploying in production.**
Default: ``'production'``
.. 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
def debug(self) -> bool:
"""Whether debug mode is enabled. When using ``flask run`` to start the
@ -1144,16 +855,8 @@ class Flask(Scaffold):
if get_load_dotenv(load_dotenv):
cli.load_dotenv()
# if set, let env vars override previous values
if "FLASK_ENV" in os.environ:
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()
elif "FLASK_DEBUG" in os.environ:
# if set, env var overrides existing value
if "FLASK_DEBUG" in os.environ:
self.debug = get_debug_flag()
# debug passed to method overrides all other sources
@ -1479,32 +1182,6 @@ class Flask(Scaffold):
"""
self.jinja_env.globals[name or f.__name__] = f
@setupmethod
def before_first_request(self, f: T_before_first_request) -> T_before_first_request:
"""Registers a function to be run before the first request to this
instance of the application.
The function will be called without any arguments and its return
value is ignored.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Run setup code when creating
the application instead.
.. versionadded:: 0.8
"""
import warnings
warnings.warn(
"'before_first_request' is deprecated and will be removed"
" in Flask 2.3. Run setup code while creating the"
" application instead.",
DeprecationWarning,
stacklevel=2,
)
self.before_first_request_funcs.append(f)
return f
@setupmethod
def teardown_appcontext(self, f: T_teardown) -> T_teardown:
"""Registers a function to be called when the application
@ -1682,7 +1359,7 @@ class Flask(Scaffold):
Always sends the :data:`got_request_exception` signal.
If :attr:`propagate_exceptions` is ``True``, such as in debug
If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug
mode, the error will be re-raised so that the debugger can
display it. Otherwise, the original exception is logged, and
an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
@ -1805,16 +1482,7 @@ class Flask(Scaffold):
.. versionadded:: 0.7
"""
# Run before_first_request functions if this is the thread's first request.
# Inlined to avoid a method call on subsequent requests.
# This is deprecated, will be removed in Flask 2.3.
if not self._got_first_request:
with self._before_request_lock:
if not self._got_first_request:
for func in self.before_first_request_funcs:
self.ensure_sync(func)()
self._got_first_request = True
self._got_first_request = True
try:
request_started.send(self)

View File

@ -1,4 +1,3 @@
import json
import os
import typing as t
from collections import defaultdict
@ -15,9 +14,6 @@ if t.TYPE_CHECKING: # pragma: no cover
DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable)
T_before_first_request = t.TypeVar(
"T_before_first_request", bound=ft.BeforeFirstRequestCallable
)
T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable)
T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable)
T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)
@ -173,77 +169,6 @@ class Blueprint(Scaffold):
_got_registered_once = False
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
@property
def json_encoder(
self,
) -> t.Union[t.Type[json.JSONEncoder], None]:
"""Blueprint-local JSON encoder class to use. Set to ``None`` to use the app's.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.
.. versionadded:: 0.10
"""
import warnings
warnings.warn(
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
return self._json_encoder
@json_encoder.setter
def json_encoder(self, value: t.Union[t.Type[json.JSONEncoder], None]) -> None:
import warnings
warnings.warn(
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_encoder = value
@property
def json_decoder(
self,
) -> t.Union[t.Type[json.JSONDecoder], None]:
"""Blueprint-local JSON decoder class to use. Set to ``None`` to use the app's.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.
.. versionadded:: 0.10
"""
import warnings
warnings.warn(
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
return self._json_decoder
@json_decoder.setter
def json_decoder(self, value: t.Union[t.Type[json.JSONDecoder], None]) -> None:
import warnings
warnings.warn(
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_decoder = value
def __init__(
self,
name: str,
@ -361,6 +286,10 @@ class Blueprint(Scaffold):
.. versionchanged:: 2.3
Nested blueprints now correctly apply subdomains.
.. versionchanged:: 2.1
Registering the same blueprint with the same name multiple
times is an error.
.. versionchanged:: 2.0.1
Nested blueprints are registered with their dotted name.
This allows different blueprints with the same name to be
@ -371,10 +300,6 @@ class Blueprint(Scaffold):
name the blueprint is registered with. This allows the same
blueprint to be registered multiple times with unique names
for ``url_for``.
.. versionchanged:: 2.0.1
Registering the same blueprint with the same name multiple
times is deprecated and will become an error in Flask 2.1.
"""
name_prefix = options.get("name_prefix", "")
self_name = options.get("name", self.name)
@ -634,29 +559,6 @@ class Blueprint(Scaffold):
)
return f
@setupmethod
def before_app_first_request(
self, f: T_before_first_request
) -> T_before_first_request:
"""Register a function to run before the first request to the application is
handled by the worker. Equivalent to :meth:`.Flask.before_first_request`.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Run setup code when creating
the application instead.
"""
import warnings
warnings.warn(
"'before_app_first_request' is deprecated and will be"
" removed in Flask 2.3. Use 'record_once' instead to run"
" setup code when registering the blueprint.",
DeprecationWarning,
stacklevel=2,
)
self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
return f
@setupmethod
def after_app_request(self, f: T_after_request) -> T_after_request:
"""Like :meth:`after_request`, but after every request, not only those handled

View File

@ -17,30 +17,17 @@ class _FakeStack:
self.name = name
self.cv = cv
def _warn(self):
@property
def top(self) -> t.Optional[t.Any]:
import warnings
warnings.warn(
f"'_{self.name}_ctx_stack' is deprecated and will be"
" removed in Flask 2.3. Use 'g' to store data, or"
f" '{self.name}_ctx' to access the current context.",
f"'_{self.name}_ctx_stack' is deprecated and will be removed in Flask 2.4."
f" Use 'g' to store data, or '{self.name}_ctx' to access the current"
" context.",
DeprecationWarning,
stacklevel=3,
stacklevel=2,
)
def push(self, obj: t.Any) -> None:
self._warn()
self.cv.set(obj)
def pop(self) -> t.Any:
self._warn()
ctx = self.cv.get(None)
self.cv.set(None)
return ctx
@property
def top(self) -> t.Optional[t.Any]:
self._warn()
return self.cv.get(None)
@ -88,7 +75,7 @@ def __getattr__(name: str) -> t.Any:
import warnings
warnings.warn(
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.3.",
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.",
DeprecationWarning,
stacklevel=2,
)
@ -98,7 +85,7 @@ def __getattr__(name: str) -> t.Any:
import warnings
warnings.warn(
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.3.",
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.",
DeprecationWarning,
stacklevel=2,
)

View File

@ -25,45 +25,12 @@ if t.TYPE_CHECKING: # pragma: no cover
import typing_extensions as te
def get_env() -> str:
"""Get the environment the app is running in, indicated by the
:envvar:`FLASK_ENV` environment variable. The default is
``'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"
def get_debug_flag() -> bool:
"""Get whether debug mode should be enabled for the app, indicated by the
:envvar:`FLASK_DEBUG` environment variable. The default is ``False``.
"""
val = os.environ.get("FLASK_DEBUG")
if not val:
env = os.environ.get("FLASK_ENV")
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"}
return bool(val and val.lower() not in {"0", "false", "no"})
def get_load_dotenv(default: bool = True) -> bool:

View File

@ -3,85 +3,14 @@ from __future__ import annotations
import json as _json
import typing as t
from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
from ..globals import current_app
from .provider import _default
if t.TYPE_CHECKING: # pragma: no cover
from ..app import Flask
from ..wrappers import Response
class JSONEncoder(_json.JSONEncoder):
"""The default JSON encoder. Handles extra types compared to the
built-in :class:`json.JSONEncoder`.
- :class:`datetime.datetime` and :class:`datetime.date` are
serialized to :rfc:`822` strings. This is the same as the HTTP
date format.
- :class:`decimal.Decimal` is serialized to a string.
- :class:`uuid.UUID` is serialized to a string.
- :class:`dataclasses.dataclass` is passed to
:func:`dataclasses.asdict`.
- :class:`~markupsafe.Markup` (or any object with a ``__html__``
method) will call the ``__html__`` method to get a string.
Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
:attr:`flask.Blueprint.json_encoder` to override the default.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``app.json`` instead.
"""
def __init__(self, **kwargs) -> None:
import warnings
warnings.warn(
"'JSONEncoder' is deprecated and will be removed in"
" Flask 2.3. Use 'Flask.json' to provide an alternate"
" JSON implementation instead.",
DeprecationWarning,
stacklevel=3,
)
super().__init__(**kwargs)
def default(self, o: t.Any) -> t.Any:
"""Convert ``o`` to a JSON serializable type. See
:meth:`json.JSONEncoder.default`. Python does not support
overriding how basic types like ``str`` or ``list`` are
serialized, they are handled before this method.
"""
return _default(o)
class JSONDecoder(_json.JSONDecoder):
"""The default JSON decoder.
This does not change any behavior from the built-in
:class:`json.JSONDecoder`.
Assign a subclass of this to :attr:`flask.Flask.json_decoder` or
:attr:`flask.Blueprint.json_decoder` to override the default.
.. deprecated:: 2.2
Will be removed in Flask 2.3. Use ``app.json`` instead.
"""
def __init__(self, **kwargs) -> None:
import warnings
warnings.warn(
"'JSONDecoder' is deprecated and will be removed in"
" Flask 2.3. Use 'Flask.json' to provide an alternate"
" JSON implementation instead.",
DeprecationWarning,
stacklevel=3,
)
super().__init__(**kwargs)
def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
def dumps(obj: t.Any, **kwargs: t.Any) -> str:
"""Serialize data as JSON.
If :data:`~flask.current_app` is available, it will use its
@ -91,13 +20,13 @@ def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
:param obj: The data to serialize.
:param kwargs: Arguments passed to the ``dumps`` implementation.
.. versionchanged:: 2.3
The ``app`` parameter was removed.
.. versionchanged:: 2.2
Calls ``current_app.json.dumps``, allowing an app to override
the behavior.
.. versionchanged:: 2.2
The ``app`` parameter will be removed in Flask 2.3.
.. versionchanged:: 2.0.2
:class:`decimal.Decimal` is supported by converting to a string.
@ -108,28 +37,14 @@ def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
``app`` can be passed directly, rather than requiring an app
context for configuration.
"""
if app is not None:
import warnings
warnings.warn(
"The 'app' parameter is deprecated and will be removed in"
" Flask 2.3. Call 'app.json.dumps' directly instead.",
DeprecationWarning,
stacklevel=2,
)
else:
app = current_app
if app:
return app.json.dumps(obj, **kwargs)
if current_app:
return current_app.json.dumps(obj, **kwargs)
kwargs.setdefault("default", _default)
return _json.dumps(obj, **kwargs)
def dump(
obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **kwargs: t.Any
) -> None:
def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
"""Serialize data as JSON and write to a file.
If :data:`~flask.current_app` is available, it will use its
@ -141,37 +56,25 @@ def dump(
encoding to be valid JSON.
:param kwargs: Arguments passed to the ``dump`` implementation.
.. versionchanged:: 2.3
The ``app`` parameter was removed.
.. versionchanged:: 2.2
Calls ``current_app.json.dump``, allowing an app to override
the behavior.
.. versionchanged:: 2.2
The ``app`` parameter will be removed in Flask 2.3.
.. versionchanged:: 2.0
Writing to a binary file, and the ``encoding`` argument, will be
removed in Flask 2.1.
"""
if app is not None:
import warnings
warnings.warn(
"The 'app' parameter is deprecated and will be removed in"
" Flask 2.3. Call 'app.json.dump' directly instead.",
DeprecationWarning,
stacklevel=2,
)
else:
app = current_app
if app:
app.json.dump(obj, fp, **kwargs)
if current_app:
current_app.json.dump(obj, fp, **kwargs)
else:
kwargs.setdefault("default", _default)
_json.dump(obj, fp, **kwargs)
def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
def loads(s: str | bytes, **kwargs: t.Any) -> t.Any:
"""Deserialize data as JSON.
If :data:`~flask.current_app` is available, it will use its
@ -181,13 +84,13 @@ def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any
:param s: Text or UTF-8 bytes.
:param kwargs: Arguments passed to the ``loads`` implementation.
.. versionchanged:: 2.3
The ``app`` parameter was removed.
.. versionchanged:: 2.2
Calls ``current_app.json.loads``, allowing an app to override
the behavior.
.. versionchanged:: 2.2
The ``app`` parameter will be removed in Flask 2.3.
.. versionchanged:: 2.0
``encoding`` will be removed in Flask 2.1. The data must be a
string or UTF-8 bytes.
@ -196,25 +99,13 @@ def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any
``app`` can be passed directly, rather than requiring an app
context for configuration.
"""
if app is not None:
import warnings
warnings.warn(
"The 'app' parameter is deprecated and will be removed in"
" Flask 2.3. Call 'app.json.loads' directly instead.",
DeprecationWarning,
stacklevel=2,
)
else:
app = current_app
if app:
return app.json.loads(s, **kwargs)
if current_app:
return current_app.json.loads(s, **kwargs)
return _json.loads(s, **kwargs)
def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any:
"""Deserialize data as JSON read from a file.
If :data:`~flask.current_app` is available, it will use its
@ -224,6 +115,9 @@ def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.
:param fp: A file opened for reading text or UTF-8 bytes.
:param kwargs: Arguments passed to the ``load`` implementation.
.. versionchanged:: 2.3
The ``app`` parameter was removed.
.. versionchanged:: 2.2
Calls ``current_app.json.load``, allowing an app to override
the behavior.
@ -235,78 +129,12 @@ def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.
``encoding`` will be removed in Flask 2.1. The file must be text
mode, or binary mode with UTF-8 bytes.
"""
if app is not None:
import warnings
warnings.warn(
"The 'app' parameter is deprecated and will be removed in"
" Flask 2.3. Call 'app.json.load' directly instead.",
DeprecationWarning,
stacklevel=2,
)
else:
app = current_app
if app:
return app.json.load(fp, **kwargs)
if current_app:
return current_app.json.load(fp, **kwargs)
return _json.load(fp, **kwargs)
def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str:
"""Serialize an object to a string of JSON with :func:`dumps`, then
replace HTML-unsafe characters with Unicode escapes and mark the
result safe with :class:`~markupsafe.Markup`.
This is available in templates as the ``|tojson`` filter.
The returned string is safe to render in HTML documents and
``<script>`` tags. The exception is in HTML attributes that are
double quoted; either use single quotes or the ``|forceescape``
filter.
.. deprecated:: 2.2
Will be removed in Flask 2.3. This is built-in to Jinja now.
.. versionchanged:: 2.0
Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned
value is marked safe by wrapping in :class:`~markupsafe.Markup`.
.. versionchanged:: 0.10
Single quotes are escaped, making this safe to use in HTML,
``<script>`` tags, and single-quoted attributes without further
escaping.
"""
import warnings
warnings.warn(
"'htmlsafe_dumps' is deprecated and will be removed in Flask"
" 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
DeprecationWarning,
stacklevel=2,
)
return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs)
def htmlsafe_dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
"""Serialize an object to JSON written to a file object, replacing
HTML-unsafe characters with Unicode escapes. See
:func:`htmlsafe_dumps` and :func:`dumps`.
.. deprecated:: 2.2
Will be removed in Flask 2.3.
"""
import warnings
warnings.warn(
"'htmlsafe_dump' is deprecated and will be removed in Flask"
" 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
DeprecationWarning,
stacklevel=2,
)
fp.write(htmlsafe_dumps(obj, **kwargs))
def jsonify(*args: t.Any, **kwargs: t.Any) -> Response:
"""Serialize the given arguments as JSON, and return a
:class:`~flask.Response` object with the ``application/json``

View File

@ -10,8 +10,6 @@ from datetime import date
from werkzeug.http import http_date
from ..globals import request
if t.TYPE_CHECKING: # pragma: no cover
from ..app import Flask
from ..wrappers import Response
@ -176,57 +174,9 @@ class DefaultJSONProvider(JSONProvider):
:param obj: The data to serialize.
:param kwargs: Passed to :func:`json.dumps`.
"""
cls = self._app._json_encoder
bp = self._app.blueprints.get(request.blueprint) if request else None
if bp is not None and bp._json_encoder is not None:
cls = bp._json_encoder
if cls is not None:
import warnings
warnings.warn(
"Setting 'json_encoder' on the app or a blueprint is"
" deprecated and will be removed in Flask 2.3."
" Customize 'app.json' instead.",
DeprecationWarning,
)
kwargs.setdefault("cls", cls)
if "default" not in cls.__dict__:
kwargs.setdefault("default", self.default)
else:
kwargs.setdefault("default", self.default)
ensure_ascii = self._app.config["JSON_AS_ASCII"]
sort_keys = self._app.config["JSON_SORT_KEYS"]
if ensure_ascii is not None:
import warnings
warnings.warn(
"The 'JSON_AS_ASCII' config key is deprecated and will"
" be removed in Flask 2.3. Set 'app.json.ensure_ascii'"
" instead.",
DeprecationWarning,
)
else:
ensure_ascii = self.ensure_ascii
if sort_keys is not None:
import warnings
warnings.warn(
"The 'JSON_SORT_KEYS' config key is deprecated and will"
" be removed in Flask 2.3. Set 'app.json.sort_keys'"
" instead.",
DeprecationWarning,
)
else:
sort_keys = self.sort_keys
kwargs.setdefault("ensure_ascii", ensure_ascii)
kwargs.setdefault("sort_keys", sort_keys)
kwargs.setdefault("default", self.default)
kwargs.setdefault("ensure_ascii", self.ensure_ascii)
kwargs.setdefault("sort_keys", self.sort_keys)
return json.dumps(obj, **kwargs)
def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any:
@ -235,23 +185,6 @@ class DefaultJSONProvider(JSONProvider):
:param s: Text or UTF-8 bytes.
:param kwargs: Passed to :func:`json.loads`.
"""
cls = self._app._json_decoder
bp = self._app.blueprints.get(request.blueprint) if request else None
if bp is not None and bp._json_decoder is not None:
cls = bp._json_decoder
if cls is not None:
import warnings
warnings.warn(
"Setting 'json_decoder' on the app or a blueprint is"
" deprecated and will be removed in Flask 2.3."
" Customize 'app.json' instead.",
DeprecationWarning,
)
kwargs.setdefault("cls", cls)
return json.loads(s, **kwargs)
def response(self, *args: t.Any, **kwargs: t.Any) -> Response:
@ -272,39 +205,12 @@ class DefaultJSONProvider(JSONProvider):
"""
obj = self._prepare_response_obj(args, kwargs)
dump_args: t.Dict[str, t.Any] = {}
pretty = self._app.config["JSONIFY_PRETTYPRINT_REGULAR"]
mimetype = self._app.config["JSONIFY_MIMETYPE"]
if pretty is not None:
import warnings
warnings.warn(
"The 'JSONIFY_PRETTYPRINT_REGULAR' config key is"
" deprecated and will be removed in Flask 2.3. Set"
" 'app.json.compact' instead.",
DeprecationWarning,
)
compact: bool | None = not pretty
else:
compact = self.compact
if (compact is None and self._app.debug) or compact is False:
if (self.compact is None and self._app.debug) or self.compact is False:
dump_args.setdefault("indent", 2)
else:
dump_args.setdefault("separators", (",", ":"))
if mimetype is not None:
import warnings
warnings.warn(
"The 'JSONIFY_MIMETYPE' config key is deprecated and"
" will be removed in Flask 2.3. Set 'app.json.mimetype'"
" instead.",
DeprecationWarning,
)
else:
mimetype = self.mimetype
return self._app.response_class(
f"{self.dumps(obj, **dump_args)}\n", mimetype=mimetype
f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype
)

View File

@ -1,5 +1,4 @@
import importlib.util
import json
import os
import pathlib
import pkgutil
@ -74,20 +73,6 @@ class Scaffold:
_static_folder: t.Optional[str] = None
_static_url_path: t.Optional[str] = None
#: JSON encoder class used by :func:`flask.json.dumps`. If a
#: blueprint sets this, it will be used instead of the app's value.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
#: JSON decoder class used by :func:`flask.json.loads`. If a
#: blueprint sets this, it will be used instead of the app's value.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
def __init__(
self,
import_name: str,

View File

@ -20,7 +20,6 @@ def _standard_os_environ():
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),
(os.environ, "FLASK_RUN_FROM_CLI", monkeypatch.notset),
(os.environ, "WERKZEUG_RUN_MAIN", monkeypatch.notset),

View File

@ -95,7 +95,6 @@ def test_async_error_handler(path, async_app):
def test_async_before_after_request():
app_first_called = False
app_before_called = False
app_after_called = False
bp_before_called = False
@ -107,13 +106,6 @@ def test_async_before_after_request():
def index():
return ""
with pytest.deprecated_call():
@app.before_first_request
async def before_first():
nonlocal app_first_called
app_first_called = True
@app.before_request
async def before():
nonlocal app_before_called
@ -146,7 +138,6 @@ def test_async_before_after_request():
test_client = app.test_client()
test_client.get("/")
assert app_first_called
assert app_before_called
assert app_after_called
test_client.get("/bp/")

View File

@ -1,13 +1,11 @@
import gc
import re
import time
import uuid
import warnings
import weakref
from datetime import datetime
from datetime import timezone
from platform import python_implementation
from threading import Thread
import pytest
import werkzeug.serving
@ -1667,43 +1665,6 @@ def test_no_setup_after_first_request(app, client):
assert "setup method 'add_url_rule'" in str(exc_info.value)
def test_before_first_request_functions(app, client):
got = []
with pytest.deprecated_call():
@app.before_first_request
def foo():
got.append(42)
client.get("/")
assert got == [42]
client.get("/")
assert got == [42]
assert app.got_first_request
def test_before_first_request_functions_concurrent(app, client):
got = []
with pytest.deprecated_call():
@app.before_first_request
def foo():
time.sleep(0.2)
got.append(42)
def get_and_assert():
client.get("/")
assert got == [42]
t = Thread(target=get_and_assert)
t.start()
get_and_assert()
t.join()
assert app.got_first_request
def test_routing_redirect_debugging(monkeypatch, app, client):
app.config["DEBUG"] = True

View File

@ -722,12 +722,6 @@ def test_app_request_processing(app, client):
bp = flask.Blueprint("bp", __name__)
evts = []
with pytest.deprecated_call():
@bp.before_app_first_request
def before_first_request():
evts.append("first")
@bp.before_app_request
def before_app():
evts.append("before")
@ -755,12 +749,12 @@ def test_app_request_processing(app, client):
# first request
resp = client.get("/").data
assert resp == b"request|after"
assert evts == ["first", "before", "after", "teardown"]
assert evts == ["before", "after", "teardown"]
# second request
resp = client.get("/").data
assert resp == b"request|after"
assert evts == ["first"] + ["before", "after", "teardown"] * 2
assert evts == ["before", "after", "teardown"] * 2
def test_app_url_processors(app, client):

View File

@ -302,24 +302,18 @@ class TestStreaming:
class TestHelpers:
@pytest.mark.parametrize(
"debug, expected_flag, expected_default_flag",
("debug", "expect"),
[
("", False, False),
("0", False, False),
("False", False, False),
("No", False, False),
("True", True, True),
("", False),
("0", False),
("False", False),
("No", False),
("True", True),
],
)
def test_get_debug_flag(
self, monkeypatch, debug, expected_flag, expected_default_flag
):
def test_get_debug_flag(self, monkeypatch, debug, expect):
monkeypatch.setenv("FLASK_DEBUG", debug)
if expected_flag is None:
assert get_debug_flag() is None
else:
assert get_debug_flag() == expected_flag
assert get_debug_flag() == expected_default_flag
assert get_debug_flag() == expect
def test_make_response(self):
app = flask.Flask(__name__)