forked from orbit-oss/flask
Merge pull request #4337 from pallets/remove-deprecated-code
remove deprecated code
This commit is contained in:
commit
7620cb70db
10 changed files with 68 additions and 259 deletions
24
CHANGES.rst
24
CHANGES.rst
|
|
@ -5,7 +5,29 @@ Version 2.1.0
|
||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
|
|
||||||
- Update Click dependency to >= 8.0.
|
- Drop support for Python 3.6. :pr:`4335`
|
||||||
|
- Update Click dependency to >= 8.0. :pr:`4008`
|
||||||
|
- Remove previously deprecated code. :pr:`4337`
|
||||||
|
|
||||||
|
- The CLI does not pass ``script_info`` to app factory functions.
|
||||||
|
- ``config.from_json`` is replaced by
|
||||||
|
``config.from_file(name, load=json.load)``.
|
||||||
|
- ``json`` functions no longer take an ``encoding`` parameter.
|
||||||
|
- ``safe_join`` is removed, use ``werkzeug.utils.safe_join``
|
||||||
|
instead.
|
||||||
|
- ``total_seconds`` is removed, use ``timedelta.total_seconds``
|
||||||
|
instead.
|
||||||
|
- The same blueprint cannot be registered with the same name. Use
|
||||||
|
``name=`` when registering to specify a unique name.
|
||||||
|
|
||||||
|
- Some parameters in ``send_file`` and ``send_from_directory`` were
|
||||||
|
renamed in 2.0. The deprecation period for the old names is extended
|
||||||
|
to 2.2. Be sure to test with deprecation warnings visible.
|
||||||
|
|
||||||
|
- ``attachment_filename`` is renamed to ``download_name``.
|
||||||
|
- ``cache_timeout`` is renamed to ``max_age``.
|
||||||
|
- ``add_etags`` is renamed to ``etag``.
|
||||||
|
- ``filename`` is renamed to ``path``.
|
||||||
|
|
||||||
|
|
||||||
Version 2.0.2
|
Version 2.0.2
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,6 @@ Useful Functions and Classes
|
||||||
|
|
||||||
.. autofunction:: send_from_directory
|
.. autofunction:: send_from_directory
|
||||||
|
|
||||||
.. autofunction:: safe_join
|
|
||||||
|
|
||||||
.. autofunction:: escape
|
.. autofunction:: escape
|
||||||
|
|
||||||
.. autoclass:: Markup
|
.. autoclass:: Markup
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ from .helpers import flash as flash
|
||||||
from .helpers import get_flashed_messages as get_flashed_messages
|
from .helpers import get_flashed_messages as get_flashed_messages
|
||||||
from .helpers import get_template_attribute as get_template_attribute
|
from .helpers import get_template_attribute as get_template_attribute
|
||||||
from .helpers import make_response as make_response
|
from .helpers import make_response as make_response
|
||||||
from .helpers import safe_join as safe_join
|
|
||||||
from .helpers import send_file as send_file
|
from .helpers import send_file as send_file
|
||||||
from .helpers import send_from_directory as send_from_directory
|
from .helpers import send_from_directory as send_from_directory
|
||||||
from .helpers import stream_with_context as stream_with_context
|
from .helpers import stream_with_context as stream_with_context
|
||||||
|
|
|
||||||
|
|
@ -299,24 +299,14 @@ class Blueprint(Scaffold):
|
||||||
name = f"{name_prefix}.{self_name}".lstrip(".")
|
name = f"{name_prefix}.{self_name}".lstrip(".")
|
||||||
|
|
||||||
if name in app.blueprints:
|
if name in app.blueprints:
|
||||||
|
bp_desc = "this" if app.blueprints[name] is self else "a different"
|
||||||
existing_at = f" '{name}'" if self_name != name else ""
|
existing_at = f" '{name}'" if self_name != name else ""
|
||||||
|
|
||||||
if app.blueprints[name] is not self:
|
raise ValueError(
|
||||||
raise ValueError(
|
f"The name '{self_name}' is already registered for"
|
||||||
f"The name '{self_name}' is already registered for"
|
f" {bp_desc} blueprint{existing_at}. Use 'name=' to"
|
||||||
f" a different blueprint{existing_at}. Use 'name='"
|
f" provide a unique name."
|
||||||
" to provide a unique name."
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
f"The name '{self_name}' is already registered for"
|
|
||||||
f" this blueprint{existing_at}. Use 'name=' to"
|
|
||||||
" provide a unique name. This will become an error"
|
|
||||||
" in Flask 2.1.",
|
|
||||||
stacklevel=4,
|
|
||||||
)
|
|
||||||
|
|
||||||
first_bp_registration = not any(bp is self for bp in app.blueprints.values())
|
first_bp_registration = not any(bp is self for bp in app.blueprints.values())
|
||||||
first_name_registration = name not in app.blueprints
|
first_name_registration = name not in app.blueprints
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import platform
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
@ -34,7 +33,7 @@ class NoAppException(click.UsageError):
|
||||||
"""Raised if an application cannot be found or loaded."""
|
"""Raised if an application cannot be found or loaded."""
|
||||||
|
|
||||||
|
|
||||||
def find_best_app(script_info, module):
|
def find_best_app(module):
|
||||||
"""Given a module instance this tries to find the best possible
|
"""Given a module instance this tries to find the best possible
|
||||||
application in the module or raises an exception.
|
application in the module or raises an exception.
|
||||||
"""
|
"""
|
||||||
|
|
@ -65,7 +64,7 @@ def find_best_app(script_info, module):
|
||||||
|
|
||||||
if inspect.isfunction(app_factory):
|
if inspect.isfunction(app_factory):
|
||||||
try:
|
try:
|
||||||
app = call_factory(script_info, app_factory)
|
app = app_factory()
|
||||||
|
|
||||||
if isinstance(app, Flask):
|
if isinstance(app, Flask):
|
||||||
return app
|
return app
|
||||||
|
|
@ -87,42 +86,6 @@ def find_best_app(script_info, module):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def call_factory(script_info, app_factory, args=None, kwargs=None):
|
|
||||||
"""Takes an app factory, a ``script_info` object and optionally a tuple
|
|
||||||
of arguments. Checks for the existence of a script_info argument and calls
|
|
||||||
the app_factory depending on that and the arguments provided.
|
|
||||||
"""
|
|
||||||
sig = inspect.signature(app_factory)
|
|
||||||
args = [] if args is None else args
|
|
||||||
kwargs = {} if kwargs is None else kwargs
|
|
||||||
|
|
||||||
if "script_info" in sig.parameters:
|
|
||||||
warnings.warn(
|
|
||||||
"The 'script_info' argument is deprecated and will not be"
|
|
||||||
" passed to the app factory function in Flask 2.1.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
kwargs["script_info"] = script_info
|
|
||||||
|
|
||||||
if not args and len(sig.parameters) == 1:
|
|
||||||
first_parameter = next(iter(sig.parameters.values()))
|
|
||||||
|
|
||||||
if (
|
|
||||||
first_parameter.default is inspect.Parameter.empty
|
|
||||||
# **kwargs is reported as an empty default, ignore it
|
|
||||||
and first_parameter.kind is not inspect.Parameter.VAR_KEYWORD
|
|
||||||
):
|
|
||||||
warnings.warn(
|
|
||||||
"Script info is deprecated and will not be passed as the"
|
|
||||||
" single argument to the app factory function in Flask"
|
|
||||||
" 2.1.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
args.append(script_info)
|
|
||||||
|
|
||||||
return app_factory(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def _called_with_wrong_args(f):
|
def _called_with_wrong_args(f):
|
||||||
"""Check whether calling a function raised a ``TypeError`` because
|
"""Check whether calling a function raised a ``TypeError`` because
|
||||||
the call failed or because something in the factory raised the
|
the call failed or because something in the factory raised the
|
||||||
|
|
@ -149,7 +112,7 @@ def _called_with_wrong_args(f):
|
||||||
del tb
|
del tb
|
||||||
|
|
||||||
|
|
||||||
def find_app_by_string(script_info, module, app_name):
|
def find_app_by_string(module, app_name):
|
||||||
"""Check if the given string is a variable name or a function. Call
|
"""Check if the given string is a variable name or a function. Call
|
||||||
a function to get the app instance, or return the variable directly.
|
a function to get the app instance, or return the variable directly.
|
||||||
"""
|
"""
|
||||||
|
|
@ -166,7 +129,8 @@ def find_app_by_string(script_info, module, app_name):
|
||||||
|
|
||||||
if isinstance(expr, ast.Name):
|
if isinstance(expr, ast.Name):
|
||||||
name = expr.id
|
name = expr.id
|
||||||
args = kwargs = None
|
args = []
|
||||||
|
kwargs = {}
|
||||||
elif isinstance(expr, ast.Call):
|
elif isinstance(expr, ast.Call):
|
||||||
# Ensure the function name is an attribute name only.
|
# Ensure the function name is an attribute name only.
|
||||||
if not isinstance(expr.func, ast.Name):
|
if not isinstance(expr.func, ast.Name):
|
||||||
|
|
@ -202,7 +166,7 @@ def find_app_by_string(script_info, module, app_name):
|
||||||
# to get the real application.
|
# to get the real application.
|
||||||
if inspect.isfunction(attr):
|
if inspect.isfunction(attr):
|
||||||
try:
|
try:
|
||||||
app = call_factory(script_info, attr, args, kwargs)
|
app = attr(*args, **kwargs)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
if not _called_with_wrong_args(attr):
|
if not _called_with_wrong_args(attr):
|
||||||
raise
|
raise
|
||||||
|
|
@ -253,7 +217,7 @@ def prepare_import(path):
|
||||||
return ".".join(module_name[::-1])
|
return ".".join(module_name[::-1])
|
||||||
|
|
||||||
|
|
||||||
def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
|
def locate_app(module_name, app_name, raise_if_not_found=True):
|
||||||
__traceback_hide__ = True # noqa: F841
|
__traceback_hide__ = True # noqa: F841
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -273,9 +237,9 @@ def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
|
||||||
module = sys.modules[module_name]
|
module = sys.modules[module_name]
|
||||||
|
|
||||||
if app_name is None:
|
if app_name is None:
|
||||||
return find_best_app(script_info, module)
|
return find_best_app(module)
|
||||||
else:
|
else:
|
||||||
return find_app_by_string(script_info, module, app_name)
|
return find_app_by_string(module, app_name)
|
||||||
|
|
||||||
|
|
||||||
def get_version(ctx, param, value):
|
def get_version(ctx, param, value):
|
||||||
|
|
@ -396,18 +360,18 @@ class ScriptInfo:
|
||||||
return self._loaded_app
|
return self._loaded_app
|
||||||
|
|
||||||
if self.create_app is not None:
|
if self.create_app is not None:
|
||||||
app = call_factory(self, self.create_app)
|
app = self.create_app()
|
||||||
else:
|
else:
|
||||||
if self.app_import_path:
|
if self.app_import_path:
|
||||||
path, name = (
|
path, name = (
|
||||||
re.split(r":(?![\\/])", self.app_import_path, 1) + [None]
|
re.split(r":(?![\\/])", self.app_import_path, 1) + [None]
|
||||||
)[:2]
|
)[:2]
|
||||||
import_name = prepare_import(path)
|
import_name = prepare_import(path)
|
||||||
app = locate_app(self, import_name, name)
|
app = locate_app(import_name, name)
|
||||||
else:
|
else:
|
||||||
for path in ("wsgi.py", "app.py"):
|
for path in ("wsgi.py", "app.py"):
|
||||||
import_name = prepare_import(path)
|
import_name = prepare_import(path)
|
||||||
app = locate_app(self, import_name, None, raise_if_not_found=False)
|
app = locate_app(import_name, None, raise_if_not_found=False)
|
||||||
|
|
||||||
if app:
|
if app:
|
||||||
break
|
break
|
||||||
|
|
@ -983,15 +947,7 @@ debug mode.
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
if int(click.__version__[0]) < 8:
|
cli.main()
|
||||||
warnings.warn(
|
|
||||||
"Using the `flask` cli with Click 7 is deprecated and"
|
|
||||||
" will not be supported starting with Flask 2.1."
|
|
||||||
" Please upgrade to Click 8 as soon as possible.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
# TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed
|
|
||||||
cli.main(args=sys.argv[1:])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,9 @@ class Config(dict):
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
import json
|
||||||
|
app.config.from_file("config.json", load=json.load)
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
app.config.from_file("config.toml", load=toml.load)
|
app.config.from_file("config.toml", load=toml.load)
|
||||||
|
|
||||||
|
|
@ -204,32 +207,6 @@ class Config(dict):
|
||||||
|
|
||||||
return self.from_mapping(obj)
|
return self.from_mapping(obj)
|
||||||
|
|
||||||
def from_json(self, filename: str, silent: bool = False) -> bool:
|
|
||||||
"""Update the values in the config from a JSON file. The loaded
|
|
||||||
data is passed to the :meth:`from_mapping` method.
|
|
||||||
|
|
||||||
:param filename: The path to the JSON file. This can be an
|
|
||||||
absolute path or relative to the config root path.
|
|
||||||
:param silent: Ignore the file if it doesn't exist.
|
|
||||||
:return: ``True`` if the file was loaded successfully.
|
|
||||||
|
|
||||||
.. deprecated:: 2.0.0
|
|
||||||
Will be removed in Flask 2.1. Use :meth:`from_file` instead.
|
|
||||||
This was removed early in 2.0.0, was added back in 2.0.1.
|
|
||||||
|
|
||||||
.. versionadded:: 0.11
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
from . import json
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'from_json' is deprecated and will be removed in Flask"
|
|
||||||
" 2.1. Use 'from_file(path, json.load)' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self.from_file(filename, json.load, silent=silent)
|
|
||||||
|
|
||||||
def from_mapping(
|
def from_mapping(
|
||||||
self, mapping: t.Optional[t.Mapping[str, t.Any]] = None, **kwargs: t.Any
|
self, mapping: t.Optional[t.Mapping[str, t.Any]] = None, **kwargs: t.Any
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,11 @@ import sys
|
||||||
import typing as t
|
import typing as t
|
||||||
import warnings
|
import warnings
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
|
||||||
import werkzeug.utils
|
import werkzeug.utils
|
||||||
from werkzeug.exceptions import NotFound
|
|
||||||
from werkzeug.routing import BuildError
|
from werkzeug.routing import BuildError
|
||||||
from werkzeug.urls import url_quote
|
from werkzeug.urls import url_quote
|
||||||
|
|
||||||
|
|
@ -454,7 +452,7 @@ def _prepare_send_file_kwargs(
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'attachment_filename' parameter has been renamed to"
|
"The 'attachment_filename' parameter has been renamed to"
|
||||||
" 'download_name'. The old name will be removed in Flask"
|
" 'download_name'. The old name will be removed in Flask"
|
||||||
" 2.1.",
|
" 2.2.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=3,
|
||||||
)
|
)
|
||||||
|
|
@ -463,7 +461,7 @@ def _prepare_send_file_kwargs(
|
||||||
if cache_timeout is not None:
|
if cache_timeout is not None:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'cache_timeout' parameter has been renamed to"
|
"The 'cache_timeout' parameter has been renamed to"
|
||||||
" 'max_age'. The old name will be removed in Flask 2.1.",
|
" 'max_age'. The old name will be removed in Flask 2.2.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=3,
|
||||||
)
|
)
|
||||||
|
|
@ -472,7 +470,7 @@ def _prepare_send_file_kwargs(
|
||||||
if add_etags is not None:
|
if add_etags is not None:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'add_etags' parameter has been renamed to 'etag'. The"
|
"The 'add_etags' parameter has been renamed to 'etag'. The"
|
||||||
" old name will be removed in Flask 2.1.",
|
" old name will be removed in Flask 2.2.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=3,
|
||||||
)
|
)
|
||||||
|
|
@ -627,29 +625,6 @@ def send_file(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def safe_join(directory: str, *pathnames: str) -> str:
|
|
||||||
"""Safely join zero or more untrusted path components to a base
|
|
||||||
directory to avoid escaping the base directory.
|
|
||||||
|
|
||||||
:param directory: The trusted base directory.
|
|
||||||
:param pathnames: The untrusted path components relative to the
|
|
||||||
base directory.
|
|
||||||
:return: A safe path, otherwise ``None``.
|
|
||||||
"""
|
|
||||||
warnings.warn(
|
|
||||||
"'flask.helpers.safe_join' is deprecated and will be removed in"
|
|
||||||
" Flask 2.1. Use 'werkzeug.utils.safe_join' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
path = werkzeug.utils.safe_join(directory, *pathnames)
|
|
||||||
|
|
||||||
if path is None:
|
|
||||||
raise NotFound()
|
|
||||||
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def send_from_directory(
|
def send_from_directory(
|
||||||
directory: t.Union[os.PathLike, str],
|
directory: t.Union[os.PathLike, str],
|
||||||
path: t.Union[os.PathLike, str],
|
path: t.Union[os.PathLike, str],
|
||||||
|
|
@ -691,7 +666,7 @@ def send_from_directory(
|
||||||
if filename is not None:
|
if filename is not None:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"The 'filename' parameter has been renamed to 'path'. The"
|
"The 'filename' parameter has been renamed to 'path'. The"
|
||||||
" old name will be removed in Flask 2.1.",
|
" old name will be removed in Flask 2.2.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
@ -785,27 +760,6 @@ class locked_cached_property(werkzeug.utils.cached_property):
|
||||||
super().__delete__(obj)
|
super().__delete__(obj)
|
||||||
|
|
||||||
|
|
||||||
def total_seconds(td: timedelta) -> int:
|
|
||||||
"""Returns the total seconds from a timedelta object.
|
|
||||||
|
|
||||||
:param timedelta td: the timedelta to be converted in seconds
|
|
||||||
|
|
||||||
:returns: number of seconds
|
|
||||||
:rtype: int
|
|
||||||
|
|
||||||
.. deprecated:: 2.0
|
|
||||||
Will be removed in Flask 2.1. Use
|
|
||||||
:meth:`timedelta.total_seconds` instead.
|
|
||||||
"""
|
|
||||||
warnings.warn(
|
|
||||||
"'total_seconds' is deprecated and will be removed in Flask"
|
|
||||||
" 2.1. Use 'timedelta.total_seconds' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return td.days * 60 * 60 * 24 + td.seconds
|
|
||||||
|
|
||||||
|
|
||||||
def is_ip(value: str) -> bool:
|
def is_ip(value: str) -> bool:
|
||||||
"""Determine if the given string is an IP address.
|
"""Determine if the given string is an IP address.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import decimal
|
import decimal
|
||||||
import io
|
|
||||||
import json as _json
|
import json as _json
|
||||||
import typing as t
|
import typing as t
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
|
from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
|
||||||
|
|
@ -124,20 +122,7 @@ def dumps(obj: t.Any, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> str:
|
||||||
context for configuration.
|
context for configuration.
|
||||||
"""
|
"""
|
||||||
_dump_arg_defaults(kwargs, app=app)
|
_dump_arg_defaults(kwargs, app=app)
|
||||||
encoding = kwargs.pop("encoding", None)
|
return _json.dumps(obj, **kwargs)
|
||||||
rv = _json.dumps(obj, **kwargs)
|
|
||||||
|
|
||||||
if encoding is not None:
|
|
||||||
warnings.warn(
|
|
||||||
"'encoding' is deprecated and will be removed in Flask 2.1.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(rv, str):
|
|
||||||
return rv.encode(encoding) # type: ignore
|
|
||||||
|
|
||||||
return rv
|
|
||||||
|
|
||||||
|
|
||||||
def dump(
|
def dump(
|
||||||
|
|
@ -159,23 +144,6 @@ def dump(
|
||||||
deprecated and will be removed in Flask 2.1.
|
deprecated and will be removed in Flask 2.1.
|
||||||
"""
|
"""
|
||||||
_dump_arg_defaults(kwargs, app=app)
|
_dump_arg_defaults(kwargs, app=app)
|
||||||
encoding = kwargs.pop("encoding", None)
|
|
||||||
show_warning = encoding is not None
|
|
||||||
|
|
||||||
try:
|
|
||||||
fp.write("")
|
|
||||||
except TypeError:
|
|
||||||
show_warning = True
|
|
||||||
fp = io.TextIOWrapper(fp, encoding or "utf-8") # type: ignore
|
|
||||||
|
|
||||||
if show_warning:
|
|
||||||
warnings.warn(
|
|
||||||
"Writing to a binary file, and the 'encoding' argument, is"
|
|
||||||
" deprecated and will be removed in Flask 2.1.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
_json.dump(obj, fp, **kwargs)
|
_json.dump(obj, fp, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -199,19 +167,6 @@ def loads(s: str, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any:
|
||||||
context for configuration.
|
context for configuration.
|
||||||
"""
|
"""
|
||||||
_load_arg_defaults(kwargs, app=app)
|
_load_arg_defaults(kwargs, app=app)
|
||||||
encoding = kwargs.pop("encoding", None)
|
|
||||||
|
|
||||||
if encoding is not None:
|
|
||||||
warnings.warn(
|
|
||||||
"'encoding' is deprecated and will be removed in Flask 2.1."
|
|
||||||
" The data must be a string or UTF-8 bytes.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(s, bytes):
|
|
||||||
s = s.decode(encoding)
|
|
||||||
|
|
||||||
return _json.loads(s, **kwargs)
|
return _json.loads(s, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -231,20 +186,6 @@ def load(fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.A
|
||||||
file must be text mode, or binary mode with UTF-8 bytes.
|
file must be text mode, or binary mode with UTF-8 bytes.
|
||||||
"""
|
"""
|
||||||
_load_arg_defaults(kwargs, app=app)
|
_load_arg_defaults(kwargs, app=app)
|
||||||
encoding = kwargs.pop("encoding", None)
|
|
||||||
|
|
||||||
if encoding is not None:
|
|
||||||
warnings.warn(
|
|
||||||
"'encoding' is deprecated and will be removed in Flask 2.1."
|
|
||||||
" The file must be text mode, or binary mode with UTF-8"
|
|
||||||
" bytes.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(fp.read(0), bytes):
|
|
||||||
fp = io.TextIOWrapper(fp, encoding) # type: ignore
|
|
||||||
|
|
||||||
return _json.load(fp, **kwargs)
|
return _json.load(fp, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -954,8 +954,8 @@ def test_unique_blueprint_names(app, client) -> None:
|
||||||
|
|
||||||
app.register_blueprint(bp)
|
app.register_blueprint(bp)
|
||||||
|
|
||||||
with pytest.warns(UserWarning):
|
with pytest.raises(ValueError):
|
||||||
app.register_blueprint(bp) # same bp, same name, warning
|
app.register_blueprint(bp) # same bp, same name, error
|
||||||
|
|
||||||
app.register_blueprint(bp, name="again") # same bp, different name, ok
|
app.register_blueprint(bp, name="again") # same bp, different name, ok
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,29 +49,27 @@ def test_cli_name(test_apps):
|
||||||
|
|
||||||
|
|
||||||
def test_find_best_app(test_apps):
|
def test_find_best_app(test_apps):
|
||||||
script_info = ScriptInfo()
|
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
app = Flask("appname")
|
app = Flask("appname")
|
||||||
|
|
||||||
assert find_best_app(script_info, Module) == Module.app
|
assert find_best_app(Module) == Module.app
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
application = Flask("appname")
|
application = Flask("appname")
|
||||||
|
|
||||||
assert find_best_app(script_info, Module) == Module.application
|
assert find_best_app(Module) == Module.application
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
myapp = Flask("appname")
|
myapp = Flask("appname")
|
||||||
|
|
||||||
assert find_best_app(script_info, Module) == Module.myapp
|
assert find_best_app(Module) == Module.myapp
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_app():
|
def create_app():
|
||||||
return Flask("appname")
|
return Flask("appname")
|
||||||
|
|
||||||
app = find_best_app(script_info, Module)
|
app = find_best_app(Module)
|
||||||
assert isinstance(app, Flask)
|
assert isinstance(app, Flask)
|
||||||
assert app.name == "appname"
|
assert app.name == "appname"
|
||||||
|
|
||||||
|
|
@ -80,29 +78,7 @@ def test_find_best_app(test_apps):
|
||||||
def create_app(**kwargs):
|
def create_app(**kwargs):
|
||||||
return Flask("appname")
|
return Flask("appname")
|
||||||
|
|
||||||
app = find_best_app(script_info, Module)
|
app = find_best_app(Module)
|
||||||
assert isinstance(app, Flask)
|
|
||||||
assert app.name == "appname"
|
|
||||||
|
|
||||||
class Module:
|
|
||||||
@staticmethod
|
|
||||||
def create_app(foo):
|
|
||||||
return Flask("appname")
|
|
||||||
|
|
||||||
with pytest.deprecated_call(match="Script info"):
|
|
||||||
app = find_best_app(script_info, Module)
|
|
||||||
|
|
||||||
assert isinstance(app, Flask)
|
|
||||||
assert app.name == "appname"
|
|
||||||
|
|
||||||
class Module:
|
|
||||||
@staticmethod
|
|
||||||
def create_app(foo=None, script_info=None):
|
|
||||||
return Flask("appname")
|
|
||||||
|
|
||||||
with pytest.deprecated_call(match="script_info"):
|
|
||||||
app = find_best_app(script_info, Module)
|
|
||||||
|
|
||||||
assert isinstance(app, Flask)
|
assert isinstance(app, Flask)
|
||||||
assert app.name == "appname"
|
assert app.name == "appname"
|
||||||
|
|
||||||
|
|
@ -111,7 +87,7 @@ def test_find_best_app(test_apps):
|
||||||
def make_app():
|
def make_app():
|
||||||
return Flask("appname")
|
return Flask("appname")
|
||||||
|
|
||||||
app = find_best_app(script_info, Module)
|
app = find_best_app(Module)
|
||||||
assert isinstance(app, Flask)
|
assert isinstance(app, Flask)
|
||||||
assert app.name == "appname"
|
assert app.name == "appname"
|
||||||
|
|
||||||
|
|
@ -122,7 +98,7 @@ def test_find_best_app(test_apps):
|
||||||
def create_app():
|
def create_app():
|
||||||
return Flask("appname2")
|
return Flask("appname2")
|
||||||
|
|
||||||
assert find_best_app(script_info, Module) == Module.myapp
|
assert find_best_app(Module) == Module.myapp
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
myapp = Flask("appname1")
|
myapp = Flask("appname1")
|
||||||
|
|
@ -131,32 +107,32 @@ def test_find_best_app(test_apps):
|
||||||
def create_app():
|
def create_app():
|
||||||
return Flask("appname2")
|
return Flask("appname2")
|
||||||
|
|
||||||
assert find_best_app(script_info, Module) == Module.myapp
|
assert find_best_app(Module) == Module.myapp
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
pytest.raises(NoAppException, find_best_app, script_info, Module)
|
pytest.raises(NoAppException, find_best_app, Module)
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
myapp1 = Flask("appname1")
|
myapp1 = Flask("appname1")
|
||||||
myapp2 = Flask("appname2")
|
myapp2 = Flask("appname2")
|
||||||
|
|
||||||
pytest.raises(NoAppException, find_best_app, script_info, Module)
|
pytest.raises(NoAppException, find_best_app, Module)
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_app(foo, bar):
|
def create_app(foo, bar):
|
||||||
return Flask("appname2")
|
return Flask("appname2")
|
||||||
|
|
||||||
pytest.raises(NoAppException, find_best_app, script_info, Module)
|
pytest.raises(NoAppException, find_best_app, Module)
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_app():
|
def create_app():
|
||||||
raise TypeError("bad bad factory!")
|
raise TypeError("bad bad factory!")
|
||||||
|
|
||||||
pytest.raises(TypeError, find_best_app, script_info, Module)
|
pytest.raises(TypeError, find_best_app, Module)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
@ -220,8 +196,7 @@ def test_prepare_import(request, value, path, result):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_locate_app(test_apps, iname, aname, result):
|
def test_locate_app(test_apps, iname, aname, result):
|
||||||
info = ScriptInfo()
|
assert locate_app(iname, aname).name == result
|
||||||
assert locate_app(info, iname, aname).name == result
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
@ -243,20 +218,17 @@ def test_locate_app(test_apps, iname, aname, result):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_locate_app_raises(test_apps, iname, aname):
|
def test_locate_app_raises(test_apps, iname, aname):
|
||||||
info = ScriptInfo()
|
|
||||||
|
|
||||||
with pytest.raises(NoAppException):
|
with pytest.raises(NoAppException):
|
||||||
locate_app(info, iname, aname)
|
locate_app(iname, aname)
|
||||||
|
|
||||||
|
|
||||||
def test_locate_app_suppress_raise(test_apps):
|
def test_locate_app_suppress_raise(test_apps):
|
||||||
info = ScriptInfo()
|
app = locate_app("notanapp.py", None, raise_if_not_found=False)
|
||||||
app = locate_app(info, "notanapp.py", None, raise_if_not_found=False)
|
|
||||||
assert app is None
|
assert app is None
|
||||||
|
|
||||||
# only direct import error is suppressed
|
# only direct import error is suppressed
|
||||||
with pytest.raises(NoAppException):
|
with pytest.raises(NoAppException):
|
||||||
locate_app(info, "cliapp.importerrorapp", None, raise_if_not_found=False)
|
locate_app("cliapp.importerrorapp", None, raise_if_not_found=False)
|
||||||
|
|
||||||
|
|
||||||
def test_get_version(test_apps, capsys):
|
def test_get_version(test_apps, capsys):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue