Browse Source

Refactored script info to allow more advanced patterns.

pull/1040/head
Armin Ronacher 11 years ago
parent
commit
4532e89efe
  1. 60
      flask/cli.py

60
flask/cli.py

@ -110,38 +110,44 @@ class DispatchingApp(object):
errors for import problems into the browser as error. errors for import problems into the browser as error.
""" """
def __init__(self, app_id, debug=None, use_eager_loading=False): def __init__(self, loader, use_eager_loading=False):
self.app_id = app_id self.loader = loader
self.app = None self._app = None
self.debug = debug
self._lock = Lock() self._lock = Lock()
if use_eager_loading: if use_eager_loading:
self._load_unlocked() self._load_unlocked()
def _load_unlocked(self): def _load_unlocked(self):
self.app = rv = locate_app(self.app_id, self.debug) self._app = rv = self.loader()
return rv return rv
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
if self.app is not None: if self._app is not None:
return self.app(environ, start_response) return self._app(environ, start_response)
with self._lock: with self._lock:
if self.app is not None: if self._app is not None:
rv = self.app rv = self._app
else: else:
rv = self._load_unlocked() rv = self._load_unlocked()
return rv(environ, start_response) 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): class ScriptInfo(object):
"""Help object to deal with Flask applications. This is usually not """Help object to deal with Flask applications. This is usually not
necessary to interface with as it's used internally in the dispatching necessary to interface with as it's used internally in the dispatching
to click. 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.app_import_path = app_import_path
self.debug = debug self.debug = debug
self.load_callback = load_callback
self._loaded_app = None self._loaded_app = None
def get_app_import_path(self): def get_app_import_path(self):
@ -150,18 +156,33 @@ class ScriptInfo(object):
""" """
if self.app_import_path is not None: if self.app_import_path is not None:
return self.app_import_path return self.app_import_path
raise NoAppException('Could not locate application. ' _no_such_app()
'You did not provide FLASK_APP or the '
'--app parameter.')
def load_app(self): def load_app(self):
"""Loads the app (if not yet loaded) and returns it.""" """Loads the app (if not yet loaded) and returns it."""
if self._loaded_app is not None: if self._loaded_app is not None:
return self._loaded_app return self._loaded_app
rv = locate_app(self.get_app_import_path(), self.debug) 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 self._loaded_app = rv
return 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 @contextmanager
def conditional_context(self, with_context=True): def conditional_context(self, with_context=True):
"""Creates an application context or not, depending on the """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): with_threads):
"""Runs a local development server for the Flask application.""" """Runs a local development server for the Flask application."""
from werkzeug.serving import run_simple from werkzeug.serving import run_simple
app_id = info.get_app_import_path()
if reload is None: if reload is None:
reload = info.debug reload = info.debug
if debugger is None: if debugger is None:
@ -289,14 +309,20 @@ def run_command(info, host, port, reload, debugger, eager_loading,
if eager_loading is None: if eager_loading is None:
eager_loading = not reload 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 # Extra startup messages. This depends a but on Werkzeug internals to
# not double execute when the reloader kicks in. # not double execute when the reloader kicks in.
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': 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: if info.debug is not None:
print(' * Forcing debug %s' % (info.debug and 'on' or 'off')) 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, run_simple(host, port, app, use_reloader=reload,
use_debugger=debugger, threaded=with_threads) use_debugger=debugger, threaded=with_threads)

Loading…
Cancel
Save