Merge pull request #2378 from miguelgrinberg/default-flask-app
Import app from wsgi.py or app.py if FLASK_APP is not defined
This commit is contained in:
commit
29c055a2b4
5 changed files with 75 additions and 19 deletions
12
docs/cli.rst
12
docs/cli.rst
|
|
@ -25,10 +25,14 @@ your Flask application's :attr:`Flask.cli` instance as well as some
|
||||||
built-in commands that are always there. Flask extensions can also
|
built-in commands that are always there. Flask extensions can also
|
||||||
register more commands there if they desire so.
|
register more commands there if they desire so.
|
||||||
|
|
||||||
For the :command:`flask` script to work, an application needs to be
|
For the :command:`flask` script to work, an application needs to be discovered.
|
||||||
discovered. This is achieved by exporting the ``FLASK_APP`` environment
|
Flask looks for a module named :file:`wsgi.py` or :file:`app.py` by default,
|
||||||
variable. It can be either set to an import path or to a filename of a
|
and if it finds one it assumes the application is defined in it.
|
||||||
Python module that contains a Flask application.
|
|
||||||
|
You can instruct Flask to look for the application in a different module by
|
||||||
|
exporting the ``FLASK_APP`` environment variable. It can be either set to an
|
||||||
|
import path or to a filename of a Python module that contains a Flask
|
||||||
|
application.
|
||||||
|
|
||||||
In that imported file the name of the app needs to be called ``app`` or
|
In that imported file the name of the app needs to be called ``app`` or
|
||||||
optionally be specified after a colon. For instance
|
optionally be specified after a colon. For instance
|
||||||
|
|
|
||||||
51
flask/cli.py
51
flask/cli.py
|
|
@ -172,13 +172,16 @@ def prepare_exec_for_file(filename):
|
||||||
if not os.path.isfile(os.path.join(dirpath, '__init__.py')):
|
if not os.path.isfile(os.path.join(dirpath, '__init__.py')):
|
||||||
break
|
break
|
||||||
|
|
||||||
sys.path.insert(0, dirpath)
|
if sys.path[0] != dirpath:
|
||||||
|
sys.path.insert(0, dirpath)
|
||||||
|
|
||||||
return '.'.join(module[::-1])
|
return '.'.join(module[::-1])
|
||||||
|
|
||||||
|
|
||||||
def locate_app(script_info, app_id):
|
def locate_app(script_info, app_id, raise_if_not_found=True):
|
||||||
"""Attempts to locate the application."""
|
"""Attempts to locate the application."""
|
||||||
__traceback_hide__ = True
|
__traceback_hide__ = True
|
||||||
|
|
||||||
if ':' in app_id:
|
if ':' in app_id:
|
||||||
module, app_obj = app_id.split(':', 1)
|
module, app_obj = app_id.split(':', 1)
|
||||||
else:
|
else:
|
||||||
|
|
@ -192,15 +195,23 @@ def locate_app(script_info, app_id):
|
||||||
# Determine this by checking whether the trace has a depth > 1.
|
# Determine this by checking whether the trace has a depth > 1.
|
||||||
if sys.exc_info()[-1].tb_next:
|
if sys.exc_info()[-1].tb_next:
|
||||||
stack_trace = traceback.format_exc()
|
stack_trace = traceback.format_exc()
|
||||||
raise NoAppException('There was an error trying to import'
|
raise NoAppException(
|
||||||
' the app (%s):\n%s' % (module, stack_trace))
|
'There was an error trying to import the app ({module}):\n'
|
||||||
|
'{stack_trace}'.format(
|
||||||
|
module=module, stack_trace=stack_trace
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif raise_if_not_found:
|
||||||
|
raise NoAppException(
|
||||||
|
'The file/path provided (%s) does not appear to exist. Please'
|
||||||
|
' verify the path is correct. If app is not on PYTHONPATH,'
|
||||||
|
' ensure the extension is .py.'.format(module=module)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise NoAppException('The file/path provided (%s) does not appear'
|
return
|
||||||
' to exist. Please verify the path is '
|
|
||||||
'correct. If app is not on PYTHONPATH, '
|
|
||||||
'ensure the extension is .py' % module)
|
|
||||||
|
|
||||||
mod = sys.modules[module]
|
mod = sys.modules[module]
|
||||||
|
|
||||||
if app_obj is None:
|
if app_obj is None:
|
||||||
return find_best_app(script_info, mod)
|
return find_best_app(script_info, mod)
|
||||||
else:
|
else:
|
||||||
|
|
@ -326,14 +337,26 @@ class ScriptInfo(object):
|
||||||
if self.create_app is not None:
|
if self.create_app is not None:
|
||||||
rv = call_factory(self.create_app, self)
|
rv = call_factory(self.create_app, self)
|
||||||
else:
|
else:
|
||||||
if not self.app_import_path:
|
if self.app_import_path:
|
||||||
|
rv = locate_app(self, self.app_import_path)
|
||||||
|
else:
|
||||||
|
for module in ['wsgi.py', 'app.py']:
|
||||||
|
import_path = prepare_exec_for_file(module)
|
||||||
|
rv = locate_app(
|
||||||
|
self, import_path, raise_if_not_found=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if rv:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not rv:
|
||||||
raise NoAppException(
|
raise NoAppException(
|
||||||
'Could not locate Flask application. You did not provide '
|
'Could not locate Flask application. You did not provide '
|
||||||
'the FLASK_APP environment variable.\n\nFor more '
|
'the FLASK_APP environment variable, and a wsgi.py or '
|
||||||
'information see '
|
'app.py module was not found in the current directory.\n\n'
|
||||||
'http://flask.pocoo.org/docs/latest/quickstart/')
|
'For more information see '
|
||||||
|
'http://flask.pocoo.org/docs/latest/quickstart/'
|
||||||
rv = locate_app(self, self.app_import_path)
|
)
|
||||||
|
|
||||||
debug = get_debug_flag()
|
debug = get_debug_flag()
|
||||||
|
|
||||||
|
|
|
||||||
6
tests/test_apps/helloworld/hello.py
Normal file
6
tests/test_apps/helloworld/hello.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def hello():
|
||||||
|
return "Hello World!"
|
||||||
1
tests/test_apps/helloworld/wsgi.py
Normal file
1
tests/test_apps/helloworld/wsgi.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from hello import app
|
||||||
|
|
@ -181,6 +181,9 @@ def test_locate_app(test_apps):
|
||||||
script_info, "cliapp.factory:create_app ()")
|
script_info, "cliapp.factory:create_app ()")
|
||||||
pytest.raises(
|
pytest.raises(
|
||||||
NoAppException, locate_app, script_info, "cliapp.importerrorapp")
|
NoAppException, locate_app, script_info, "cliapp.importerrorapp")
|
||||||
|
assert locate_app(
|
||||||
|
script_info, "notanpp.py", raise_if_not_found=False
|
||||||
|
) is None
|
||||||
|
|
||||||
|
|
||||||
def test_find_default_import_path(test_apps, monkeypatch, tmpdir):
|
def test_find_default_import_path(test_apps, monkeypatch, tmpdir):
|
||||||
|
|
@ -214,7 +217,7 @@ def test_get_version(test_apps, capsys):
|
||||||
assert py_ver in out
|
assert py_ver in out
|
||||||
|
|
||||||
|
|
||||||
def test_scriptinfo(test_apps):
|
def test_scriptinfo(test_apps, monkeypatch):
|
||||||
"""Test of ScriptInfo."""
|
"""Test of ScriptInfo."""
|
||||||
obj = ScriptInfo(app_import_path="cliapp.app:testapp")
|
obj = ScriptInfo(app_import_path="cliapp.app:testapp")
|
||||||
assert obj.load_app().name == "testapp"
|
assert obj.load_app().name == "testapp"
|
||||||
|
|
@ -228,6 +231,25 @@ def test_scriptinfo(test_apps):
|
||||||
assert app.name == "createapp"
|
assert app.name == "createapp"
|
||||||
assert obj.load_app() == app
|
assert obj.load_app() == app
|
||||||
|
|
||||||
|
obj = ScriptInfo()
|
||||||
|
pytest.raises(NoAppException, obj.load_app)
|
||||||
|
|
||||||
|
# import app from wsgi.py in current directory
|
||||||
|
monkeypatch.chdir(os.path.abspath(os.path.join(
|
||||||
|
os.path.dirname(__file__), 'test_apps', 'helloworld'
|
||||||
|
)))
|
||||||
|
obj = ScriptInfo()
|
||||||
|
app = obj.load_app()
|
||||||
|
assert app.name == 'hello'
|
||||||
|
|
||||||
|
# import app from app.py in current directory
|
||||||
|
monkeypatch.chdir(os.path.abspath(os.path.join(
|
||||||
|
os.path.dirname(__file__), 'test_apps', 'cliapp'
|
||||||
|
)))
|
||||||
|
obj = ScriptInfo()
|
||||||
|
app = obj.load_app()
|
||||||
|
assert app.name == 'testapp'
|
||||||
|
|
||||||
|
|
||||||
def test_with_appcontext(runner):
|
def test_with_appcontext(runner):
|
||||||
"""Test of with_appcontext."""
|
"""Test of with_appcontext."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue