forked from orbit-oss/flask
Implemented simplified CLI interface
This commit is contained in:
parent
92f63a1c1d
commit
523e271183
5 changed files with 51 additions and 91 deletions
2
Makefile
2
Makefile
|
|
@ -3,7 +3,7 @@
|
|||
all: clean-pyc test
|
||||
|
||||
test:
|
||||
py.test tests examples
|
||||
FLASK_DEBUG= py.test tests examples
|
||||
|
||||
tox-test:
|
||||
tox
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ from werkzeug.exceptions import HTTPException, InternalServerError, \
|
|||
MethodNotAllowed, BadRequest, default_exceptions
|
||||
|
||||
from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
|
||||
locked_cached_property, _endpoint_from_view_func, find_package
|
||||
locked_cached_property, _endpoint_from_view_func, find_package, \
|
||||
get_debug_flag
|
||||
from . import json, cli
|
||||
from .wrappers import Request, Response
|
||||
from .config import ConfigAttribute, Config
|
||||
|
|
@ -289,7 +290,7 @@ class Flask(_PackageBoundObject):
|
|||
|
||||
#: Default configuration parameters.
|
||||
default_config = ImmutableDict({
|
||||
'DEBUG': False,
|
||||
'DEBUG': get_debug_flag(default=False),
|
||||
'TESTING': False,
|
||||
'PROPAGATE_EXCEPTIONS': None,
|
||||
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
|
||||
|
|
|
|||
124
flask/cli.py
124
flask/cli.py
|
|
@ -17,6 +17,7 @@ from functools import update_wrapper
|
|||
import click
|
||||
|
||||
from ._compat import iteritems, reraise
|
||||
from .helpers import get_debug_flag
|
||||
|
||||
|
||||
class NoAppException(click.UsageError):
|
||||
|
|
@ -98,6 +99,15 @@ def locate_app(app_id):
|
|||
return app
|
||||
|
||||
|
||||
def find_default_import_path():
|
||||
app = os.environ.get('FLASK_APP')
|
||||
if app is None:
|
||||
return
|
||||
if os.path.isfile(app):
|
||||
return prepare_exec_for_file(app)
|
||||
return app
|
||||
|
||||
|
||||
class DispatchingApp(object):
|
||||
"""Special application that dispatches to a flask application which
|
||||
is imported by name in a background thread. If an error happens
|
||||
|
|
@ -158,12 +168,13 @@ class ScriptInfo(object):
|
|||
to click.
|
||||
"""
|
||||
|
||||
def __init__(self, app_import_path=None, debug=None, create_app=None):
|
||||
#: The application import path
|
||||
self.app_import_path = app_import_path
|
||||
#: The debug flag. If this is not None, the application will
|
||||
#: automatically have it's debug flag overridden with this value.
|
||||
self.debug = debug
|
||||
def __init__(self, app_import_path=None, create_app=None):
|
||||
if create_app is None:
|
||||
if app_import_path is None:
|
||||
app_import_path = find_default_import_path()
|
||||
self.app_import_path = app_import_path
|
||||
else:
|
||||
self.app_import_path = None
|
||||
#: Optionally a function that is passed the script info to create
|
||||
#: the instance of the application.
|
||||
self.create_app = create_app
|
||||
|
|
@ -185,11 +196,12 @@ class ScriptInfo(object):
|
|||
else:
|
||||
if self.app_import_path is None:
|
||||
raise NoAppException('Could not locate Flask application. '
|
||||
'You did not provide FLASK_APP or the '
|
||||
'--app parameter.')
|
||||
'You did not provide the FLASK_APP '
|
||||
'environment variable.')
|
||||
rv = locate_app(self.app_import_path)
|
||||
if self.debug is not None:
|
||||
rv.debug = self.debug
|
||||
debug = get_debug_flag()
|
||||
if debug is not None:
|
||||
rv.debug = debug
|
||||
self._loaded_app = rv
|
||||
return rv
|
||||
|
||||
|
|
@ -210,29 +222,6 @@ def with_appcontext(f):
|
|||
return update_wrapper(decorator, f)
|
||||
|
||||
|
||||
def set_debug_value(ctx, param, value):
|
||||
ctx.ensure_object(ScriptInfo).debug = value
|
||||
|
||||
|
||||
def set_app_value(ctx, param, value):
|
||||
if value is not None:
|
||||
if os.path.isfile(value):
|
||||
value = prepare_exec_for_file(value)
|
||||
elif '.' not in sys.path:
|
||||
sys.path.insert(0, '.')
|
||||
ctx.ensure_object(ScriptInfo).app_import_path = value
|
||||
|
||||
|
||||
debug_option = click.Option(['--debug/--no-debug'],
|
||||
help='Enable or disable debug mode.',
|
||||
default=None, callback=set_debug_value)
|
||||
|
||||
|
||||
app_option = click.Option(['-a', '--app'],
|
||||
help='The application to run',
|
||||
callback=set_app_value, is_eager=True)
|
||||
|
||||
|
||||
class AppGroup(click.Group):
|
||||
"""This works similar to a regular click :class:`~click.Group` but it
|
||||
changes the behavior of the :meth:`command` decorator so that it
|
||||
|
|
@ -273,25 +262,12 @@ class FlaskGroup(AppGroup):
|
|||
|
||||
:param add_default_commands: if this is True then the default run and
|
||||
shell commands wil be added.
|
||||
:param add_app_option: adds the default :option:`--app` option. This gets
|
||||
automatically disabled if a `create_app`
|
||||
callback is defined.
|
||||
:param add_debug_option: adds the default :option:`--debug` option.
|
||||
:param create_app: an optional callback that is passed the script info
|
||||
and returns the loaded app.
|
||||
"""
|
||||
|
||||
def __init__(self, add_default_commands=True, add_app_option=None,
|
||||
add_debug_option=True, create_app=None, **extra):
|
||||
params = list(extra.pop('params', None) or ())
|
||||
if add_app_option is None:
|
||||
add_app_option = create_app is None
|
||||
if add_app_option:
|
||||
params.append(app_option)
|
||||
if add_debug_option:
|
||||
params.append(debug_option)
|
||||
|
||||
AppGroup.__init__(self, params=params, **extra)
|
||||
def __init__(self, add_default_commands=True, create_app=None, **extra):
|
||||
AppGroup.__init__(self, **extra)
|
||||
self.create_app = create_app
|
||||
|
||||
if add_default_commands:
|
||||
|
|
@ -342,33 +318,6 @@ class FlaskGroup(AppGroup):
|
|||
return AppGroup.main(self, *args, **kwargs)
|
||||
|
||||
|
||||
def script_info_option(*args, **kwargs):
|
||||
"""This decorator works exactly like :func:`click.option` but is eager
|
||||
by default and stores the value in the :attr:`ScriptInfo.data`. This
|
||||
is useful to further customize an application factory in very complex
|
||||
situations.
|
||||
|
||||
:param script_info_key: this is a mandatory keyword argument which
|
||||
defines under which data key the value should
|
||||
be stored.
|
||||
"""
|
||||
try:
|
||||
key = kwargs.pop('script_info_key')
|
||||
except LookupError:
|
||||
raise TypeError('script_info_key not provided.')
|
||||
|
||||
real_callback = kwargs.get('callback')
|
||||
def callback(ctx, param, value):
|
||||
if real_callback is not None:
|
||||
value = real_callback(ctx, value)
|
||||
ctx.ensure_object(ScriptInfo).data[key] = value
|
||||
return value
|
||||
|
||||
kwargs['callback'] = callback
|
||||
kwargs.setdefault('is_eager', True)
|
||||
return click.option(*args, **kwargs)
|
||||
|
||||
|
||||
@click.command('run', short_help='Runs a development server.')
|
||||
@click.option('--host', '-h', default='127.0.0.1',
|
||||
help='The interface to bind to.')
|
||||
|
|
@ -400,10 +349,12 @@ def run_command(info, host, port, reload, debugger, eager_loading,
|
|||
Flask is enabled and disabled otherwise.
|
||||
"""
|
||||
from werkzeug.serving import run_simple
|
||||
|
||||
debug = get_debug_flag()
|
||||
if reload is None:
|
||||
reload = info.debug
|
||||
reload = bool(debug)
|
||||
if debugger is None:
|
||||
debugger = info.debug
|
||||
debugger = bool(debug)
|
||||
if eager_loading is None:
|
||||
eager_loading = not reload
|
||||
|
||||
|
|
@ -418,12 +369,9 @@ def run_command(info, host, port, reload, debugger, eager_loading,
|
|||
# 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'))
|
||||
|
||||
run_simple(host, port, app, use_reloader=reload,
|
||||
use_debugger=debugger, threaded=with_threads,
|
||||
passthrough_errors=True)
|
||||
use_debugger=debugger, threaded=with_threads)
|
||||
|
||||
|
||||
@click.command('shell', short_help='Runs a shell in the app context.')
|
||||
|
|
@ -464,15 +412,21 @@ cli = FlaskGroup(help="""\
|
|||
This shell command acts as general utility script for Flask applications.
|
||||
|
||||
It loads the application configured (either through the FLASK_APP environment
|
||||
variable or the --app parameter) and then provides commands either provided
|
||||
by the application or Flask itself.
|
||||
variable) and then provides commands either provided by the application or
|
||||
Flask itself.
|
||||
|
||||
The most useful commands are the "run" and "shell" command.
|
||||
|
||||
Example usage:
|
||||
|
||||
flask --app=hello --debug run
|
||||
""")
|
||||
\b
|
||||
%(prefix)s%(cmd)s FLASK_APP=hello
|
||||
%(prefix)s%(cmd)s FLASK_DEBUG=1
|
||||
%(prefix)sflask run
|
||||
""" % {
|
||||
'cmd': os.name == 'posix' and 'export' or 'set',
|
||||
'prefix': os.name == 'posix' and '$ ' or '',
|
||||
})
|
||||
|
||||
|
||||
def main(as_module=False):
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import sys
|
|||
import pkgutil
|
||||
import posixpath
|
||||
import mimetypes
|
||||
from datetime import timedelta
|
||||
from time import time
|
||||
from zlib import adler32
|
||||
from threading import RLock
|
||||
|
|
@ -54,6 +53,13 @@ _os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
|
|||
if sep not in (None, '/'))
|
||||
|
||||
|
||||
def get_debug_flag(default=None):
|
||||
val = os.environ.get('FLASK_DEBUG')
|
||||
if not val:
|
||||
return default
|
||||
return val not in ('0', 'false', 'no')
|
||||
|
||||
|
||||
def _endpoint_from_view_func(view_func):
|
||||
"""Internal helper that returns the default endpoint for a given
|
||||
function. This always is the function name.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from click.testing import CliRunner
|
|||
from flask import Flask, current_app
|
||||
|
||||
from flask.cli import AppGroup, FlaskGroup, NoAppException, ScriptInfo, \
|
||||
find_best_app, locate_app, script_info_option, with_appcontext
|
||||
find_best_app, locate_app, with_appcontext
|
||||
|
||||
|
||||
def test_cli_name(test_apps):
|
||||
|
|
@ -123,7 +123,6 @@ def test_flaskgroup():
|
|||
return Flask("flaskgroup")
|
||||
|
||||
@click.group(cls=FlaskGroup, create_app=create_app)
|
||||
@script_info_option('--config', script_info_key='config')
|
||||
def cli(**params):
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue