deprecate passing script_info to factory

This commit is contained in:
David Lord 2020-04-07 15:54:36 -07:00
parent 7e3b8abf99
commit fcac7f11cf
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
5 changed files with 45 additions and 38 deletions

View File

@ -9,6 +9,9 @@ Unreleased
- JSON support no longer uses simplejson. To use another JSON module, - JSON support no longer uses simplejson. To use another JSON module,
override ``app.json_encoder`` and ``json_decoder``. :issue:`3555` override ``app.json_encoder`` and ``json_decoder``. :issue:`3555`
- The ``encoding`` option to JSON functions is deprecated. :pr:`3562` - 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 - Add :meth:`sessions.SessionInterface.get_cookie_name` to allow
setting the session cookie name dynamically. :pr:`3369` setting the session cookie name dynamically. :pr:`3369`
- Add :meth:`Config.from_file` to load config using arbitrary file - Add :meth:`Config.from_file` to load config using arbitrary file

View File

@ -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 found, the command looks for a factory function named ``create_app`` or
``make_app`` that returns an instance. ``make_app`` that returns an instance.
When calling an application factory, if the factory takes an argument named If parentheses follow the factory name, their contents are parsed as
``script_info``, then the :class:`~cli.ScriptInfo` instance is passed as a Python literals and passed as arguments to the function. This means that
keyword argument. If the application factory takes only one argument and no strings must still be in quotes.
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.
Run the Development Server Run the Development Server

View File

@ -5,6 +5,7 @@ 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
@ -91,14 +92,22 @@ def call_factory(script_info, app_factory, arguments=()):
the app_factory depending on that and the arguments provided. the app_factory depending on that and the arguments provided.
""" """
args_spec = inspect.getfullargspec(app_factory) 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) return app_factory(*arguments, script_info=script_info)
elif arguments: elif arguments:
return app_factory(*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(script_info)
return app_factory() return app_factory()
@ -131,10 +140,8 @@ def _called_with_wrong_args(factory):
def find_app_by_string(script_info, module, app_name): 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 """Check if the given string is a variable name or a function. Call
function, it checks for specified arguments and whether it takes a a function to get the app instance, or return the variable directly.
``script_info`` argument and calls the function with the appropriate
arguments.
""" """
from . import Flask from . import Flask

View File

@ -9,9 +9,5 @@ def create_app2(foo, bar):
return Flask("_".join(["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(): def no_app():
pass pass

View File

@ -67,32 +67,40 @@ def test_find_best_app(test_apps):
def create_app(): def create_app():
return Flask("appname") return Flask("appname")
assert isinstance(find_best_app(script_info, Module), Flask) app = find_best_app(script_info, Module)
assert find_best_app(script_info, Module).name == "appname" assert isinstance(app, Flask)
assert app.name == "appname"
class Module: class Module:
@staticmethod @staticmethod
def create_app(foo): def create_app(foo):
return Flask("appname") return Flask("appname")
assert isinstance(find_best_app(script_info, Module), Flask) with pytest.deprecated_call(match="Script info"):
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: class Module:
@staticmethod @staticmethod
def create_app(foo=None, script_info=None): def create_app(foo=None, script_info=None):
return Flask("appname") return Flask("appname")
assert isinstance(find_best_app(script_info, Module), Flask) with pytest.deprecated_call(match="script_info"):
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: class Module:
@staticmethod @staticmethod
def make_app(): def make_app():
return Flask("appname") return Flask("appname")
assert isinstance(find_best_app(script_info, Module), Flask) app = find_best_app(script_info, Module)
assert find_best_app(script_info, Module).name == "appname" assert isinstance(app, Flask)
assert app.name == "appname"
class Module: class Module:
myapp = Flask("appname1") myapp = Flask("appname1")
@ -199,15 +207,12 @@ def test_prepare_import(request, value, path, result):
("cliapp.factory", 'create_app2("foo", "bar")', "app2_foo_bar"), ("cliapp.factory", 'create_app2("foo", "bar")', "app2_foo_bar"),
# trailing comma space # trailing comma space
("cliapp.factory", 'create_app2("foo", "bar", )', "app2_foo_bar"), ("cliapp.factory", 'create_app2("foo", "bar", )', "app2_foo_bar"),
# takes script_info
("cliapp.factory", 'create_app3("foo")', "app3_foo_spam"),
# strip whitespace # strip whitespace
("cliapp.factory", " create_app () ", "app"), ("cliapp.factory", " create_app () ", "app"),
), ),
) )
def test_locate_app(test_apps, iname, aname, result): def test_locate_app(test_apps, iname, aname, result):
info = ScriptInfo() info = ScriptInfo()
info.data["test"] = "spam"
assert locate_app(info, iname, aname).name == result assert locate_app(info, iname, aname).name == result
@ -286,7 +291,7 @@ def test_scriptinfo(test_apps, monkeypatch):
assert app.name == "testapp" assert app.name == "testapp"
assert obj.load_app() is app assert obj.load_app() is app
def create_app(info): def create_app():
return Flask("createapp") return Flask("createapp")
obj = ScriptInfo(create_app=create_app) obj = ScriptInfo(create_app=create_app)
@ -324,7 +329,7 @@ def test_with_appcontext(runner):
def testcmd(): def testcmd():
click.echo(current_app.name) 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) result = runner.invoke(testcmd, obj=obj)
assert result.exit_code == 0 assert result.exit_code == 0
@ -350,7 +355,7 @@ def test_appgroup(runner):
def test2(): def test2():
click.echo(current_app.name) 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) result = runner.invoke(cli, ["test"], obj=obj)
assert result.exit_code == 0 assert result.exit_code == 0
@ -364,7 +369,7 @@ def test_appgroup(runner):
def test_flaskgroup(runner): def test_flaskgroup(runner):
"""Test FlaskGroup.""" """Test FlaskGroup."""
def create_app(info): def create_app():
return Flask("flaskgroup") return Flask("flaskgroup")
@click.group(cls=FlaskGroup, create_app=create_app) @click.group(cls=FlaskGroup, create_app=create_app)
@ -384,7 +389,7 @@ def test_flaskgroup(runner):
def test_flaskgroup_debug(runner, set_debug_flag): def test_flaskgroup_debug(runner, set_debug_flag):
"""Test FlaskGroup debug flag behavior.""" """Test FlaskGroup debug flag behavior."""
def create_app(info): def create_app():
app = Flask("flaskgroup") app = Flask("flaskgroup")
app.debug = True app.debug = True
return app return app
@ -405,7 +410,7 @@ def test_flaskgroup_debug(runner, set_debug_flag):
def test_print_exceptions(runner): def test_print_exceptions(runner):
"""Print the stacktrace if the CLI.""" """Print the stacktrace if the CLI."""
def create_app(info): def create_app():
raise Exception("oh no") raise Exception("oh no")
return Flask("flaskgroup") return Flask("flaskgroup")
@ -422,7 +427,7 @@ def test_print_exceptions(runner):
class TestRoutes: class TestRoutes:
@pytest.fixture @pytest.fixture
def invoke(self, runner): def invoke(self, runner):
def create_app(info): def create_app():
app = Flask(__name__) app = Flask(__name__)
app.testing = True app.testing = True
@ -441,7 +446,7 @@ class TestRoutes:
@pytest.fixture @pytest.fixture
def invoke_no_routes(self, runner): def invoke_no_routes(self, runner):
def create_app(info): def create_app():
app = Flask(__name__, static_folder=None) app = Flask(__name__, static_folder=None)
app.testing = True app.testing = True