Browse Source

Merge pull request #2530 from pallets/feature/factory-detection

Improved bad factory error handling
pull/2609/head
David Lord 7 years ago committed by GitHub
parent
commit
03a2996bb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      flask/cli.py
  2. 7
      tests/test_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(

7
tests/test_cli.py

@ -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…
Cancel
Save