Merge pull request #2530 from pallets/feature/factory-detection
Improved bad factory error handling
This commit is contained in:
commit
03a2996bb8
2 changed files with 36 additions and 0 deletions
29
flask/cli.py
29
flask/cli.py
|
|
@ -77,6 +77,8 @@ def find_best_app(script_info, module):
|
||||||
if isinstance(app, Flask):
|
if isinstance(app, Flask):
|
||||||
return app
|
return app
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
if not _called_with_wrong_args(app_factory):
|
||||||
|
raise
|
||||||
raise NoAppException(
|
raise NoAppException(
|
||||||
'Detected factory "{factory}" in module "{module}", but '
|
'Detected factory "{factory}" in module "{module}", but '
|
||||||
'could not call it without arguments. Use '
|
'could not call it without arguments. Use '
|
||||||
|
|
@ -113,6 +115,30 @@ def call_factory(script_info, app_factory, arguments=()):
|
||||||
return app_factory()
|
return app_factory()
|
||||||
|
|
||||||
|
|
||||||
|
def _called_with_wrong_args(factory):
|
||||||
|
"""Check whether calling a function raised a ``TypeError`` because
|
||||||
|
the call failed or because something in the factory raised the
|
||||||
|
error.
|
||||||
|
|
||||||
|
:param factory: the factory function that was called
|
||||||
|
:return: true if the call failed
|
||||||
|
"""
|
||||||
|
tb = sys.exc_info()[2]
|
||||||
|
|
||||||
|
try:
|
||||||
|
while tb is not None:
|
||||||
|
if tb.tb_frame.f_code is factory.__code__:
|
||||||
|
# in the factory, it was called successfully
|
||||||
|
return False
|
||||||
|
|
||||||
|
tb = tb.tb_next
|
||||||
|
|
||||||
|
# didn't reach the factory
|
||||||
|
return True
|
||||||
|
finally:
|
||||||
|
del tb
|
||||||
|
|
||||||
|
|
||||||
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
|
"""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
|
function, it checks for specified arguments and whether it takes a
|
||||||
|
|
@ -150,6 +176,9 @@ def find_app_by_string(script_info, module, app_name):
|
||||||
try:
|
try:
|
||||||
app = call_factory(script_info, attr, args)
|
app = call_factory(script_info, attr, args)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
|
if not _called_with_wrong_args(attr):
|
||||||
|
raise
|
||||||
|
|
||||||
raise NoAppException(
|
raise NoAppException(
|
||||||
'{e}\nThe factory "{app_name}" in module "{module}" could not '
|
'{e}\nThe factory "{app_name}" in module "{module}" could not '
|
||||||
'be called with the specified arguments.'.format(
|
'be called with the specified arguments.'.format(
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,13 @@ def test_find_best_app(test_apps):
|
||||||
|
|
||||||
pytest.raises(NoAppException, find_best_app, script_info, Module)
|
pytest.raises(NoAppException, find_best_app, script_info, Module)
|
||||||
|
|
||||||
|
class Module:
|
||||||
|
@staticmethod
|
||||||
|
def create_app():
|
||||||
|
raise TypeError('bad bad factory!')
|
||||||
|
|
||||||
|
pytest.raises(TypeError, find_best_app, script_info, Module)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('value,path,result', (
|
@pytest.mark.parametrize('value,path,result', (
|
||||||
('test', cwd, 'test'),
|
('test', cwd, 'test'),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue