diff --git a/CHANGES.rst b/CHANGES.rst index 23bc99ec..e712ba27 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -9,6 +9,9 @@ Unreleased - JSON support no longer uses simplejson. To use another JSON module, override ``app.json_encoder`` and ``json_decoder``. :issue:`3555` - The ``encoding`` option to JSON functions is deprecated. :pr:`3562` +- Passing ``script_info`` to app factory functions is deprecated. This + was not portable outside the ``flask`` command. Use + ``click.get_current_context().obj`` if it's needed. :issue:`3552` - Add :meth:`sessions.SessionInterface.get_cookie_name` to allow setting the session cookie name dynamically. :pr:`3369` - Add :meth:`Config.from_file` to load config using arbitrary file diff --git a/docs/cli.rst b/docs/cli.rst index d99742a6..759c315a 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -75,13 +75,9 @@ Within the given import, the command looks for an application instance named found, the command looks for a factory function named ``create_app`` or ``make_app`` that returns an instance. -When calling an application factory, if the factory takes an argument named -``script_info``, then the :class:`~cli.ScriptInfo` instance is passed as a -keyword argument. If the application factory takes only one argument and no -parentheses follow the factory name, the :class:`~cli.ScriptInfo` instance -is passed as a positional argument. If parentheses follow the factory name, -their contents are parsed as Python literals and passes as arguments to the -function. This means that strings must still be in quotes. +If parentheses follow the factory name, their contents are parsed as +Python literals and passed as arguments to the function. This means that +strings must still be in quotes. Run the Development Server diff --git a/src/flask/cli.py b/src/flask/cli.py index 83bd4a83..dbf7f37b 100644 --- a/src/flask/cli.py +++ b/src/flask/cli.py @@ -5,6 +5,7 @@ import platform import re import sys import traceback +import warnings from functools import update_wrapper from operator import attrgetter from threading import Lock @@ -91,14 +92,22 @@ def call_factory(script_info, app_factory, arguments=()): the app_factory depending on that and the arguments provided. """ args_spec = inspect.getfullargspec(app_factory) - arg_names = args_spec.args - arg_defaults = args_spec.defaults - if "script_info" in arg_names: + if "script_info" in args_spec.args: + warnings.warn( + "The 'script_info' argument is deprecated and will not be" + " passed to the app factory function in 2.1.", + DeprecationWarning, + ) return app_factory(*arguments, script_info=script_info) elif arguments: return app_factory(*arguments) - elif not arguments and len(arg_names) == 1 and arg_defaults is None: + elif not arguments and len(args_spec.args) == 1 and args_spec.defaults is None: + warnings.warn( + "Script info is deprecated and will not be passed as the" + " first argument to the app factory function in 2.1.", + DeprecationWarning, + ) return app_factory(script_info) return app_factory() @@ -131,10 +140,8 @@ def _called_with_wrong_args(factory): def find_app_by_string(script_info, module, app_name): - """Checks if the given string is a variable name or a function. If it is a - function, it checks for specified arguments and whether it takes a - ``script_info`` argument and calls the function with the appropriate - arguments. + """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. """ from . import Flask diff --git a/tests/test_apps/cliapp/factory.py b/tests/test_apps/cliapp/factory.py index b91967b3..1d27396d 100644 --- a/tests/test_apps/cliapp/factory.py +++ b/tests/test_apps/cliapp/factory.py @@ -9,9 +9,5 @@ def create_app2(foo, bar): return Flask("_".join(["app2", foo, bar])) -def create_app3(foo, script_info): - return Flask("_".join(["app3", foo, script_info.data["test"]])) - - def no_app(): pass diff --git a/tests/test_cli.py b/tests/test_cli.py index 18a29653..14bfc4c9 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -67,32 +67,40 @@ def test_find_best_app(test_apps): def create_app(): return Flask("appname") - assert isinstance(find_best_app(script_info, Module), Flask) - assert find_best_app(script_info, Module).name == "appname" + app = find_best_app(script_info, Module) + assert isinstance(app, Flask) + assert app.name == "appname" class Module: @staticmethod def create_app(foo): return Flask("appname") - assert isinstance(find_best_app(script_info, Module), Flask) - assert find_best_app(script_info, Module).name == "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") - assert isinstance(find_best_app(script_info, Module), Flask) - assert find_best_app(script_info, Module).name == "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 make_app(): return Flask("appname") - assert isinstance(find_best_app(script_info, Module), Flask) - assert find_best_app(script_info, Module).name == "appname" + app = find_best_app(script_info, Module) + assert isinstance(app, Flask) + assert app.name == "appname" class Module: myapp = Flask("appname1") @@ -199,15 +207,12 @@ def test_prepare_import(request, value, path, result): ("cliapp.factory", 'create_app2("foo", "bar")', "app2_foo_bar"), # trailing comma space ("cliapp.factory", 'create_app2("foo", "bar", )', "app2_foo_bar"), - # takes script_info - ("cliapp.factory", 'create_app3("foo")', "app3_foo_spam"), # strip whitespace ("cliapp.factory", " create_app () ", "app"), ), ) def test_locate_app(test_apps, iname, aname, result): info = ScriptInfo() - info.data["test"] = "spam" assert locate_app(info, iname, aname).name == result @@ -286,7 +291,7 @@ def test_scriptinfo(test_apps, monkeypatch): assert app.name == "testapp" assert obj.load_app() is app - def create_app(info): + def create_app(): return Flask("createapp") obj = ScriptInfo(create_app=create_app) @@ -324,7 +329,7 @@ def test_with_appcontext(runner): def testcmd(): click.echo(current_app.name) - obj = ScriptInfo(create_app=lambda info: Flask("testapp")) + obj = ScriptInfo(create_app=lambda: Flask("testapp")) result = runner.invoke(testcmd, obj=obj) assert result.exit_code == 0 @@ -350,7 +355,7 @@ def test_appgroup(runner): def test2(): click.echo(current_app.name) - obj = ScriptInfo(create_app=lambda info: Flask("testappgroup")) + obj = ScriptInfo(create_app=lambda: Flask("testappgroup")) result = runner.invoke(cli, ["test"], obj=obj) assert result.exit_code == 0 @@ -364,7 +369,7 @@ def test_appgroup(runner): def test_flaskgroup(runner): """Test FlaskGroup.""" - def create_app(info): + def create_app(): return Flask("flaskgroup") @click.group(cls=FlaskGroup, create_app=create_app) @@ -384,7 +389,7 @@ def test_flaskgroup(runner): def test_flaskgroup_debug(runner, set_debug_flag): """Test FlaskGroup debug flag behavior.""" - def create_app(info): + def create_app(): app = Flask("flaskgroup") app.debug = True return app @@ -405,7 +410,7 @@ def test_flaskgroup_debug(runner, set_debug_flag): def test_print_exceptions(runner): """Print the stacktrace if the CLI.""" - def create_app(info): + def create_app(): raise Exception("oh no") return Flask("flaskgroup") @@ -422,7 +427,7 @@ def test_print_exceptions(runner): class TestRoutes: @pytest.fixture def invoke(self, runner): - def create_app(info): + def create_app(): app = Flask(__name__) app.testing = True @@ -441,7 +446,7 @@ class TestRoutes: @pytest.fixture def invoke_no_routes(self, runner): - def create_app(info): + def create_app(): app = Flask(__name__, static_folder=None) app.testing = True