diff --git a/requirements.txt b/requirements.txt index a347a9f338711..80af3c7b7a2d2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,6 @@ flask-appbuilder==1.10.0 flask-caching==1.4.0 flask-compress==1.4.0 flask-migrate==2.1.1 -flask-script==2.0.6 flask-testing==0.7.1 flask-wtf==0.14.2 flower==0.9.2 diff --git a/setup.py b/setup.py index 614d882ae06c4..8db1597c0c537 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,6 @@ def get_git_sha(): 'flask-caching', 'flask-compress', 'flask-migrate', - 'flask-script', 'flask-testing', 'flask-wtf', 'flower', # deprecated diff --git a/superset/bin/superset b/superset/bin/superset index ed77176f086dc..8b8588eeabe15 100755 --- a/superset/bin/superset +++ b/superset/bin/superset @@ -6,10 +6,16 @@ from __future__ import print_function from __future__ import unicode_literals import warnings +import click +from flask.cli import FlaskGroup from flask.exthook import ExtDeprecationWarning +from superset.cli import create_app + warnings.simplefilter('ignore', ExtDeprecationWarning) -from superset.cli import manager +@click.group(cls=FlaskGroup, create_app=create_app) +def cli(): + """This is a management script for the superset application.""" -if __name__ == "__main__": - manager.run() +if __name__ == '__main__': + cli() diff --git a/superset/cli.py b/superset/cli.py index fc2f7510bcf75..714b1a6a3fe30 100755 --- a/superset/cli.py +++ b/superset/cli.py @@ -11,23 +11,30 @@ from subprocess import Popen from sys import stdout +import click from colorama import Fore, Style -from flask_migrate import MigrateCommand -from flask_script import Manager from pathlib2 import Path import werkzeug.serving import yaml -from superset import app, data, db, dict_import_export_util, security_manager, utils +from superset import ( + app, data, db, dict_import_export_util, security_manager, utils, +) config = app.config celery_app = utils.get_celery_app(config) -manager = Manager(app) -manager.add_command('db', MigrateCommand) +def create_app(script_info=None): + return app + + +@app.shell_context_processor +def make_shell_context(): + return dict(app=app, db=db) -@manager.command + +@app.cli.command() def init(): """Inits the Superset application""" utils.get_or_create_main_db() @@ -65,34 +72,26 @@ def run(): run() -@manager.option( - '-d', '--debug', action='store_true', - help='Start the web server in debug mode') -@manager.option( - '--console-log', action='store_true', - help='Create logger that logs to the browser console (implies -d)') -@manager.option( - '-n', '--no-reload', action='store_false', dest='use_reloader', - default=config.get('FLASK_USE_RELOAD'), - help="Don't use the reloader in debug mode") -@manager.option( - '-a', '--address', default=config.get('SUPERSET_WEBSERVER_ADDRESS'), - help='Specify the address to which to bind the web server') -@manager.option( - '-p', '--port', default=config.get('SUPERSET_WEBSERVER_PORT'), - help='Specify the port on which to run the web server') -@manager.option( - '-w', '--workers', - default=config.get('SUPERSET_WORKERS', 2), - help='Number of gunicorn web server workers to fire up [DEPRECATED]') -@manager.option( - '-t', '--timeout', default=config.get('SUPERSET_WEBSERVER_TIMEOUT'), - help='Specify the timeout (seconds) for the gunicorn web server [DEPRECATED]') -@manager.option( - '-s', '--socket', default=config.get('SUPERSET_WEBSERVER_SOCKET'), - help='Path to a UNIX socket as an alternative to address:port, e.g. ' - '/var/run/superset.sock. ' - 'Will override the address and port values. [DEPRECATED]') +@app.cli.command() +@click.option('--debug', '-d', is_flag=True, help='Start the web server in debug mode') +@click.option('--console-log', is_flag=True, + help='Create logger that logs to the browser console (implies -d)') +@click.option('--no-reload', '-n', 'use_reloader', flag_value=False, + default=config.get('FLASK_USE_RELOAD'), + help='Don\'t use the reloader in debug mode') +@click.option('--address', '-a', default=config.get('SUPERSET_WEBSERVER_ADDRESS'), + help='Specify the address to which to bind the web server') +@click.option('--port', '-p', default=config.get('SUPERSET_WEBSERVER_PORT'), + help='Specify the port on which to run the web server') +@click.option('--workers', '-w', default=config.get('SUPERSET_WORKERS', 2), + help='Number of gunicorn web server workers to fire up [DEPRECATED]') +@click.option('--timeout', '-t', default=config.get('SUPERSET_WEBSERVER_TIMEOUT'), + help='Specify the timeout (seconds) for the ' + 'gunicorn web server [DEPRECATED]') +@click.option('--socket', '-s', default=config.get('SUPERSET_WEBSERVER_SOCKET'), + help='Path to a UNIX socket as an alternative to address:port, e.g. ' + '/var/run/superset.sock. ' + 'Will override the address and port values. [DEPRECATED]') def runserver(debug, console_log, use_reloader, address, port, timeout, workers, socket): """Starts a Superset web server.""" debug = debug or config.get('DEBUG') or console_log @@ -127,9 +126,8 @@ def runserver(debug, console_log, use_reloader, address, port, timeout, workers, Popen(cmd, shell=True).wait() -@manager.option( - '-v', '--verbose', action='store_true', - help='Show extra information') +@app.cli.command() +@click.option('--verbose', '-v', is_flag=True, help='Show extra information') def version(verbose): """Prints the current version number""" print(Fore.BLUE + '-=' * 15) @@ -141,11 +139,7 @@ def version(verbose): print(Style.RESET_ALL) -@manager.option( - '-t', '--load-test-data', action='store_true', - help='Load additional test data') -def load_examples(load_test_data): - """Loads a set of Slices and Dashboards and a supporting dataset """ +def load_examples_run(load_test_data): print('Loading examples into {}'.format(db)) data.load_css_templates() @@ -197,19 +191,19 @@ def load_examples(load_test_data): data.load_deck_dash() -@manager.option( - '-d', '--datasource', - help=( - 'Specify which datasource name to load, if omitted, all ' - 'datasources will be refreshed' - ), -) -@manager.option( - '-m', '--merge', - action='store_true', - help="Specify using 'merge' property during operation.", - default=False, -) +@app.cli.command() +@click.option('--load-test-data', '-t', is_flag=True, help='Load additional test data') +def load_examples(load_test_data): + """Loads a set of Slices and Dashboards and a supporting dataset """ + load_examples_run(load_test_data) + + +@app.cli.command() +@click.option('--datasource', '-d', help='Specify which datasource name to load, if ' + 'omitted, all datasources will be refreshed') +@click.option('--merge', '-m', is_flag=True, default=False, + help='Specify using \'merge\' property during operation. ' + 'Default value is False.') def refresh_druid(datasource, merge): """Refresh druid datasources""" session = db.session() @@ -230,17 +224,18 @@ def refresh_druid(datasource, merge): session.commit() -@manager.option( - '-p', '--path', dest='path', +@app.cli.command() +@click.option( + '--path', '-p', help='Path to a single YAML file or path containing multiple YAML ' 'files to import (*.yaml or *.yml)') -@manager.option( - '-s', '--sync', dest='sync', default='', - help='comma separated list of element types to synchronize ' +@click.option( + '--sync', '-s', 'sync', default='', + help='comma seperated list of element types to synchronize ' 'e.g. "metrics,columns" deletes metrics and columns in the DB ' 'that are not specified in the YAML file') -@manager.option( - '-r', '--recursive', dest='recursive', action='store_true', +@click.option( + '--recursive', '-r', help='recursively search the path for yaml files') def import_datasources(path, sync, recursive=False): """Import datasources from YAML""" @@ -268,17 +263,18 @@ def import_datasources(path, sync, recursive=False): logging.error(e) -@manager.option( - '-f', '--datasource-file', default=None, dest='datasource_file', +@app.cli.command() +@click.option( + '--datasource-file', '-f', default=None, help='Specify the the file to export to') -@manager.option( - '-p', '--print', action='store_true', dest='print_stdout', +@click.option( + '--print', '-p', help='Print YAML to stdout') -@manager.option( - '-b', '--back-references', action='store_true', dest='back_references', +@click.option( + '--back-references', '-b', help='Include parent back references') -@manager.option( - '-d', '--include-defaults', action='store_true', dest='include_defaults', +@click.option( + '--include-defaults', '-d', help='Include fields containing defaults') def export_datasources(print_stdout, datasource_file, back_references, include_defaults): @@ -296,8 +292,9 @@ def export_datasources(print_stdout, datasource_file, yaml.safe_dump(data, data_stream, default_flow_style=False) -@manager.option( - '-b', '--back-references', action='store_false', +@app.cli.command() +@click.option( + '--back-references', '-b', help='Include parent back references') def export_datasource_schema(back_references): """Export datasource YAML schema to stdout""" @@ -306,7 +303,7 @@ def export_datasource_schema(back_references): yaml.safe_dump(data, stdout, default_flow_style=False) -@manager.command +@app.cli.command() def update_datasources_cache(): """Refresh sqllab datasources cache""" from superset.models.core import Database @@ -319,8 +316,9 @@ def update_datasources_cache(): print('{}'.format(str(e))) -@manager.option( - '-w', '--workers', +@app.cli.command() +@click.option( + '--workers', '-w', type=int, help='Number of celery server workers to fire up') def worker(workers): @@ -338,14 +336,15 @@ def worker(workers): worker.start() -@manager.option( +@app.cli.command() +@click.option( '-p', '--port', default='5555', - help=('Port on which to start the Flower process')) -@manager.option( + help='Port on which to start the Flower process') +@click.option( '-a', '--address', default='localhost', - help=('Address on which to run the service')) + help='Address on which to run the service') def flower(port, address): """Runs a Celery Flower web server diff --git a/tests/base_tests.py b/tests/base_tests.py index eefd3d98b8b43..a5af0a19cb46c 100644 --- a/tests/base_tests.py +++ b/tests/base_tests.py @@ -31,7 +31,7 @@ def __init__(self, *args, **kwargs): not os.environ.get('examples_loaded') ): logging.info('Loading examples') - cli.load_examples(load_test_data=True) + cli.load_examples_run(load_test_data=True) logging.info('Done loading examples') security_manager.sync_role_definitions() os.environ['examples_loaded'] = '1' diff --git a/tests/celery_tests.py b/tests/celery_tests.py index afaeea9dfb3a2..71adb2df43d1e 100644 --- a/tests/celery_tests.py +++ b/tests/celery_tests.py @@ -109,7 +109,7 @@ def setUpClass(cls): 'admin', 'admin', ' user', 'admin@fab.org', security_manager.find_role('Admin'), password='general') - cli.load_examples(load_test_data=True) + cli.load_examples_run(load_test_data=True) @classmethod def tearDownClass(cls): diff --git a/tox.ini b/tox.ini index 292170127abad..6f3c9fd6bd471 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,7 @@ accept-encodings = utf-8 application-import-names = superset exclude = .tox + build docs superset/assets superset/data