|
|
|
@ -110,38 +110,44 @@ class DispatchingApp(object):
|
|
|
|
|
errors for import problems into the browser as error. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
def __init__(self, app_id, debug=None, use_eager_loading=False): |
|
|
|
|
self.app_id = app_id |
|
|
|
|
self.app = None |
|
|
|
|
self.debug = debug |
|
|
|
|
def __init__(self, loader, use_eager_loading=False): |
|
|
|
|
self.loader = loader |
|
|
|
|
self._app = None |
|
|
|
|
self._lock = Lock() |
|
|
|
|
if use_eager_loading: |
|
|
|
|
self._load_unlocked() |
|
|
|
|
|
|
|
|
|
def _load_unlocked(self): |
|
|
|
|
self.app = rv = locate_app(self.app_id, self.debug) |
|
|
|
|
self._app = rv = self.loader() |
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
def __call__(self, environ, start_response): |
|
|
|
|
if self.app is not None: |
|
|
|
|
return self.app(environ, start_response) |
|
|
|
|
if self._app is not None: |
|
|
|
|
return self._app(environ, start_response) |
|
|
|
|
with self._lock: |
|
|
|
|
if self.app is not None: |
|
|
|
|
rv = self.app |
|
|
|
|
if self._app is not None: |
|
|
|
|
rv = self._app |
|
|
|
|
else: |
|
|
|
|
rv = self._load_unlocked() |
|
|
|
|
return rv(environ, start_response) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _no_such_app(): |
|
|
|
|
raise NoAppException('Could not locate Flask application. ' |
|
|
|
|
'You did not provide FLASK_APP or the ' |
|
|
|
|
'--app parameter.') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ScriptInfo(object): |
|
|
|
|
"""Help object to deal with Flask applications. This is usually not |
|
|
|
|
necessary to interface with as it's used internally in the dispatching |
|
|
|
|
to click. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
def __init__(self, app_import_path=None, debug=None): |
|
|
|
|
def __init__(self, app_import_path=None, debug=None, load_callback=None): |
|
|
|
|
self.app_import_path = app_import_path |
|
|
|
|
self.debug = debug |
|
|
|
|
self.load_callback = load_callback |
|
|
|
|
self._loaded_app = None |
|
|
|
|
|
|
|
|
|
def get_app_import_path(self): |
|
|
|
@ -150,18 +156,33 @@ class ScriptInfo(object):
|
|
|
|
|
""" |
|
|
|
|
if self.app_import_path is not None: |
|
|
|
|
return self.app_import_path |
|
|
|
|
raise NoAppException('Could not locate application. ' |
|
|
|
|
'You did not provide FLASK_APP or the ' |
|
|
|
|
'--app parameter.') |
|
|
|
|
_no_such_app() |
|
|
|
|
|
|
|
|
|
def load_app(self): |
|
|
|
|
"""Loads the app (if not yet loaded) and returns it.""" |
|
|
|
|
if self._loaded_app is not None: |
|
|
|
|
return self._loaded_app |
|
|
|
|
if self.load_callback is not None: |
|
|
|
|
rv = self.load_callback() |
|
|
|
|
else: |
|
|
|
|
rv = locate_app(self.get_app_import_path(), self.debug) |
|
|
|
|
self._loaded_app = rv |
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
def make_wsgi_app(self, use_eager_loading=False): |
|
|
|
|
"""Returns a WSGI app that loads the actual application at a |
|
|
|
|
later stage. |
|
|
|
|
""" |
|
|
|
|
if self.app_import_path is not None: |
|
|
|
|
def loader(): |
|
|
|
|
return locate_app(self.app_import_path, self.debug) |
|
|
|
|
else: |
|
|
|
|
if self.load_callback is None: |
|
|
|
|
_no_such_app() |
|
|
|
|
def loader(): |
|
|
|
|
return self.load_callback() |
|
|
|
|
return DispatchingApp(loader, use_eager_loading=use_eager_loading) |
|
|
|
|
|
|
|
|
|
@contextmanager |
|
|
|
|
def conditional_context(self, with_context=True): |
|
|
|
|
"""Creates an application context or not, depending on the |
|
|
|
@ -281,7 +302,6 @@ def run_command(info, host, port, reload, debugger, eager_loading,
|
|
|
|
|
with_threads): |
|
|
|
|
"""Runs a local development server for the Flask application.""" |
|
|
|
|
from werkzeug.serving import run_simple |
|
|
|
|
app_id = info.get_app_import_path() |
|
|
|
|
if reload is None: |
|
|
|
|
reload = info.debug |
|
|
|
|
if debugger is None: |
|
|
|
@ -289,14 +309,20 @@ def run_command(info, host, port, reload, debugger, eager_loading,
|
|
|
|
|
if eager_loading is None: |
|
|
|
|
eager_loading = not reload |
|
|
|
|
|
|
|
|
|
app = info.make_wsgi_app(use_eager_loading=eager_loading) |
|
|
|
|
|
|
|
|
|
# Extra startup messages. This depends a but on Werkzeug internals to |
|
|
|
|
# not double execute when the reloader kicks in. |
|
|
|
|
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': |
|
|
|
|
print(' * Serving Flask app "%s"' % app_id) |
|
|
|
|
# If we have an import path we can print it out now which can help |
|
|
|
|
# people understand what's being served. If we do not have an |
|
|
|
|
# import path because the app was loaded through a callback then |
|
|
|
|
# we won't print anything. |
|
|
|
|
if info.app_import_path is not None: |
|
|
|
|
print(' * Serving Flask app "%s"' % info.app_import_path) |
|
|
|
|
if info.debug is not None: |
|
|
|
|
print(' * Forcing debug %s' % (info.debug and 'on' or 'off')) |
|
|
|
|
|
|
|
|
|
app = DispatchingApp(app_id, info.debug, eager_loading) |
|
|
|
|
run_simple(host, port, app, use_reloader=reload, |
|
|
|
|
use_debugger=debugger, threaded=with_threads) |
|
|
|
|
|
|
|
|
|