diff --git a/app/__init__.py b/app/__init__.py index de8afb15..3afa99af 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -60,6 +60,9 @@ def create_app(config: Config = Config) -> Flask: from .errors import init_app as init_error_handlers init_error_handlers(app) + from .cli import init_app as init_cli + init_cli(app) + from .admin import bp as admin_blueprint default_breadcrumb_root(admin_blueprint, '.admin') app.register_blueprint(admin_blueprint, url_prefix='/admin') @@ -69,7 +72,7 @@ def create_app(config: Config = Config) -> Flask: from .auth import bp as auth_blueprint default_breadcrumb_root(auth_blueprint, '.') - app.register_blueprint(auth_blueprint, url_prefix='/') + app.register_blueprint(auth_blueprint) from .contributions import bp as contributions_blueprint default_breadcrumb_root(contributions_blueprint, '.contributions') @@ -85,7 +88,7 @@ def create_app(config: Config = Config) -> Flask: from .main import bp as main_blueprint default_breadcrumb_root(main_blueprint, '.') - app.register_blueprint(main_blueprint, url_prefix='/') + app.register_blueprint(main_blueprint) from .services import bp as services_blueprint default_breadcrumb_root(services_blueprint, '.services') diff --git a/app/cli.py b/app/cli.py deleted file mode 100644 index e59a080d..00000000 --- a/app/cli.py +++ /dev/null @@ -1,77 +0,0 @@ -from flask import current_app -from flask_migrate import upgrade -import click -import os -from app.models import ( - CorpusFollowerRole, - Role, - SpaCyNLPPipelineModel, - TesseractOCRPipelineModel, - User -) - - -def _make_default_dirs(): - base_dir = current_app.config['NOPAQUE_DATA_DIR'] - - default_directories = [ - os.path.join(base_dir, 'tmp'), - os.path.join(base_dir, 'users') - ] - for directory in default_directories: - if os.path.exists(directory): - if not os.path.isdir(directory): - raise NotADirectoryError(f'{directory} is not a directory') - else: - os.mkdir(directory) - - -def register(app): - @app.cli.command() - def deploy(): - ''' Run deployment tasks. ''' - # Make default directories - print('Make default directories') - _make_default_dirs() - - # migrate database to latest revision - print('Migrate database to latest revision') - upgrade() - - # Insert/Update default database values - print('Insert/Update default Roles') - Role.insert_defaults() - print('Insert/Update default Users') - User.insert_defaults() - print('Insert/Update default CorpusFollowerRoles') - CorpusFollowerRole.insert_defaults() - print('Insert/Update default SpaCyNLPPipelineModels') - SpaCyNLPPipelineModel.insert_defaults() - print('Insert/Update default TesseractOCRPipelineModels') - TesseractOCRPipelineModel.insert_defaults() - - @app.cli.group() - def converter(): - ''' Converter commands. ''' - pass - - @converter.command() - @click.argument('json_db') - @click.argument('data_dir') - def sandpaper(json_db, data_dir): - ''' Sandpaper converter ''' - from app.converters.sandpaper import convert - convert(json_db, data_dir) - - @app.cli.group() - def test(): - ''' Test commands. ''' - pass - - @test.command('run') - def run_test(): - ''' Run unit tests. ''' - from unittest import TestLoader, TextTestRunner - from unittest.suite import TestSuite - tests: TestSuite = TestLoader().discover('tests') - TextTestRunner(verbosity=2).run(tests) diff --git a/app/cli/__init__.py b/app/cli/__init__.py new file mode 100644 index 00000000..1803deea --- /dev/null +++ b/app/cli/__init__.py @@ -0,0 +1,10 @@ +from .converter import init_app as converter_init_app +from .corpus import init_app as corpus_init_app +from .main import init_app as main_init_app + + + +def init_app(app): + converter_init_app(app) + corpus_init_app(app) + main_init_app(app) diff --git a/app/cli/converter.py b/app/cli/converter.py new file mode 100644 index 00000000..4d07bc30 --- /dev/null +++ b/app/cli/converter.py @@ -0,0 +1,21 @@ +import click + + +def init_app(app): + @app.cli.group('converter') + def converter(): + ''' Converter commands. ''' + pass + + @converter.group('sandpaper') + def sandpaper_converter(): + ''' Sandpaper converter commands. ''' + pass + + @sandpaper_converter.command('run') + @click.argument('json_db') + @click.argument('data_dir') + def run_sandpaper_converter(json_db, data_dir): + ''' Run the sandpaper converter. ''' + from app.converters.sandpaper import convert + convert(json_db, data_dir) diff --git a/app/cli/corpus.py b/app/cli/corpus.py new file mode 100644 index 00000000..e79269f0 --- /dev/null +++ b/app/cli/corpus.py @@ -0,0 +1,23 @@ +from app.models import Corpus, CorpusStatus + + +def init_app(app): + @app.cli.group('corpus') + def corpus(): + ''' Corpus commands. ''' + pass + + @corpus.command('dismantle') + def dismantle(): + ''' Dismantle built corpora. ''' + status = [ + CorpusStatus.QUEUED, + CorpusStatus.BUILDING, + CorpusStatus.BUILT, + CorpusStatus.STARTING_ANALYSIS_SESSION, + CorpusStatus.RUNNING_ANALYSIS_SESSION, + CorpusStatus.CANCELING_ANALYSIS_SESSION + ] + for corpus in [x for x in Corpus.query.all() if x.status in status]: + corpus.status = CorpusStatus.SUBMITTED + corpus.num_analysis_sessions = 0 diff --git a/app/cli/main.py b/app/cli/main.py new file mode 100644 index 00000000..2022d609 --- /dev/null +++ b/app/cli/main.py @@ -0,0 +1,45 @@ +from flask import current_app +from flask_migrate import upgrade +import os +from app.models import ( + CorpusFollowerRole, + Role, + SpaCyNLPPipelineModel, + TesseractOCRPipelineModel, + User +) + + +def init_app(app): + @app.cli.command('deploy') + def deploy(): + ''' Run deployment tasks. ''' + # Make default directories + print('Make default directories') + base_dir = current_app.config['NOPAQUE_DATA_DIR'] + default_dirs = [ + os.path.join(base_dir, 'tmp'), + os.path.join(base_dir, 'users') + ] + for dir in default_dirs: + if os.path.exists(dir): + if not os.path.isdir(dir): + raise NotADirectoryError(f'{dir} is not a directory') + else: + os.mkdir(dir) + + # migrate database to latest revision + print('Migrate database to latest revision') + upgrade() + + # Insert/Update default database values + print('Insert/Update default Roles') + Role.insert_defaults() + print('Insert/Update default Users') + User.insert_defaults() + print('Insert/Update default CorpusFollowerRoles') + CorpusFollowerRole.insert_defaults() + print('Insert/Update default SpaCyNLPPipelineModels') + SpaCyNLPPipelineModel.insert_defaults() + print('Insert/Update default TesseractOCRPipelineModels') + TesseractOCRPipelineModel.insert_defaults() diff --git a/app/main/__init__.py b/app/main/__init__.py index 65630224..f32fed5f 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -1,5 +1,5 @@ from flask import Blueprint -bp = Blueprint('main', __name__) +bp = Blueprint('main', __name__, cli_group=None) from . import routes diff --git a/app/main/routes.py b/app/main/routes.py index 708262db..56c37116 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -7,7 +7,7 @@ from sqlalchemy import or_ from . import bp -@bp.route('', methods=['GET', 'POST']) +@bp.route('/', methods=['GET', 'POST']) @register_breadcrumb(bp, '.', 'home') def index(): form = LoginForm() diff --git a/app/tests/__init__.py b/app/tests/__init__.py new file mode 100644 index 00000000..4665c05d --- /dev/null +++ b/app/tests/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + + +bp = Blueprint('tests', __name__) +from . import cli diff --git a/app/tests/cli.py b/app/tests/cli.py new file mode 100644 index 00000000..a620bf0b --- /dev/null +++ b/app/tests/cli.py @@ -0,0 +1,9 @@ +from unittest import TestLoader, TextTestRunner +from unittest.suite import TestSuite +from . import bp + +@bp.cli.command('run') +def run_test(): + ''' Run unit tests. ''' + tests: TestSuite = TestLoader().discover('tests') + TextTestRunner(verbosity=2).run(tests) diff --git a/nopaque.py b/nopaque.py index b369556a..bd9a9165 100644 --- a/nopaque.py +++ b/nopaque.py @@ -3,7 +3,7 @@ import eventlet eventlet.monkey_patch() -from app import cli, create_app, db, scheduler, socketio # noqa +from app import create_app, db, scheduler, socketio # noqa from app.models import ( Avatar, Corpus, @@ -23,7 +23,6 @@ from typing import Any, Dict # noqa app: Flask = create_app() -cli.register(app) @app.shell_context_processor