Skip to content

Commit

Permalink
Merge pull request #283 from NatLibFi/issue210-cli-option-path-to-pro…
Browse files Browse the repository at this point in the history
…jects-file

Inspect sys.argv for --projects with argparse before click
  • Loading branch information
juhoinkinen authored Jun 26, 2019
2 parents a2d3be4 + 738820b commit f9b1294
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 13 deletions.
3 changes: 2 additions & 1 deletion annif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def create_app(script_info=None, config_name=None):
# add CORS support
CORS(cxapp.app)

annif.project.initialize_projects(cxapp.app)
if cxapp.app.config['INITIALIZE_PROJECTS']:
annif.project.initialize_projects(cxapp.app)

# register the views via blueprints
from annif.views import bp
Expand Down
36 changes: 28 additions & 8 deletions annif/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import sys
import click
import click_log
from flask.cli import FlaskGroup
from flask import current_app
from flask.cli import FlaskGroup, ScriptInfo
import annif
import annif.corpus
import annif.eval
Expand Down Expand Up @@ -74,7 +75,25 @@ def generate_filter_batches(subjects):
return filter_batches


def set_project_config_file_path(ctx, param, value):
"""Override the default path or the path given in env by CLI option"""
with ctx.ensure_object(ScriptInfo).load_app().app_context():
if value:
current_app.config['PROJECTS_FILE'] = value


def common_options(f):
"""Decorator to add common options for all CLI commands"""
f = click.option(
'-p', '--projects', help='Set path to projects.cfg',
callback=set_project_config_file_path, expose_value=False,
is_eager=True)(f)
f = click_log.simple_verbosity_option(logger)(f)
return f


@cli.command('list-projects')
@common_options
def run_list_projects():
"""
List available projects.
Expand All @@ -90,6 +109,7 @@ def run_list_projects():

@cli.command('show-project')
@click.argument('project_id')
@common_options
def run_show_project(project_id):
"""
Show information about a project.
Expand All @@ -104,9 +124,9 @@ def run_show_project(project_id):


@cli.command('loadvoc')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('subjectfile', type=click.Path(dir_okay=False))
@common_options
def run_loadvoc(project_id, subjectfile):
"""
Load a vocabulary for a project.
Expand All @@ -122,9 +142,9 @@ def run_loadvoc(project_id, subjectfile):


@cli.command('train')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('paths', type=click.Path(), nargs=-1)
@common_options
def run_train(project_id, paths):
"""
Train a project on a collection of documents.
Expand All @@ -135,9 +155,9 @@ def run_train(project_id, paths):


@cli.command('learn')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('paths', type=click.Path(), nargs=-1)
@common_options
def run_learn(project_id, paths):
"""
Further train an existing project on a collection of documents.
Expand All @@ -148,12 +168,12 @@ def run_learn(project_id, paths):


@cli.command('suggest')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.option('--limit', default=10, help='Maximum number of subjects')
@click.option('--threshold', default=0.0, help='Minimum score threshold')
@click.option('--backend-param', '-b', multiple=True,
help='Backend parameters to override')
@common_options
def run_suggest(project_id, limit, threshold, backend_param):
"""
Suggest subjects for a single document from standard input.
Expand All @@ -168,7 +188,6 @@ def run_suggest(project_id, limit, threshold, backend_param):


@cli.command('index')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('directory', type=click.Path(file_okay=False))
@click.option(
Expand All @@ -181,6 +200,7 @@ def run_suggest(project_id, limit, threshold, backend_param):
@click.option('--threshold', default=0.0, help='Minimum score threshold')
@click.option('--backend-param', '-b', multiple=True,
help='Backend parameters to override')
@common_options
def run_index(project_id, directory, suffix, force,
limit, threshold, backend_param):
"""
Expand Down Expand Up @@ -209,13 +229,13 @@ def run_index(project_id, directory, suffix, force,


@cli.command('eval')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('paths', type=click.Path(), nargs=-1)
@click.option('--limit', default=10, help='Maximum number of subjects')
@click.option('--threshold', default=0.0, help='Minimum score threshold')
@click.option('--backend-param', '-b', multiple=True,
help='Backend parameters to override')
@common_options
def run_eval(project_id, paths, limit, threshold, backend_param):
"""
Analyze documents and evaluate the result.
Expand Down Expand Up @@ -243,11 +263,11 @@ def run_eval(project_id, paths, limit, threshold, backend_param):


@cli.command('optimize')
@click_log.simple_verbosity_option(logger)
@click.argument('project_id')
@click.argument('paths', type=click.Path(), nargs=-1)
@click.option('--backend-param', '-b', multiple=True,
help='Backend parameters to override')
@common_options
def run_optimize(project_id, paths, backend_param):
"""
Analyze documents, testing multiple limits and thresholds.
Expand Down
12 changes: 8 additions & 4 deletions annif/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,11 @@ def dump(self):

def _create_projects(projects_file, datadir, init_projects):
if not os.path.exists(projects_file):
logger.warning("Project configuration file '%s' is missing. " +
'Please provide one.', projects_file)
logger.warning('You can set the path to the project configuration ' +
'file using the ANNIF_PROJECTS environment variable.')
logger.warning(
'Project configuration file "%s" is missing. Please provide one.' +
' You can set the path to the project configuration file using ' +
'the ANNIF_PROJECTS environment variable or the command-line ' +
'option "--projects".', projects_file)
return {}

config = configparser.ConfigParser()
Expand Down Expand Up @@ -255,6 +256,9 @@ def get_projects(min_access=Access.private):
AnnifProject. The min_access parameter may be used to set the minimum
access level required for the returned projects."""

if not hasattr(current_app, 'annif_projects'):
initialize_projects(current_app)

projects = [(project_id, project)
for project_id, project in current_app.annif_projects.items()
if project.access >= min_access]
Expand Down
10 changes: 10 additions & 0 deletions tests/projects_for_config_path_option.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Project configuration for Annif unit tests


[dummy_for_projects_option]
name=Dummy Option
language=en
backend=dummy
analyzer=snowball(english)
vocab=dummy
access=public
21 changes: 21 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# Generate a random project name to use in tests
TEMP_PROJECT = ''.join(
random.choice('abcdefghiklmnopqrstuvwxyz') for _ in range(8))
PROJECTS_FILE_OPTION = 'tests/projects_for_config_path_option.cfg'


def test_list_projects():
Expand All @@ -38,6 +39,26 @@ def test_list_projects_bad_arguments():
annif.cli.run_list_projects, ['moi', '--debug', 'y']).exit_code != 0


def test_list_projects_config_path_option():
result = runner.invoke(
annif.cli.cli, ["list-projects", "--projects", PROJECTS_FILE_OPTION])
assert not result.exception
assert result.exit_code == 0
assert 'dummy_for_projects_option' in result.output
assert 'dummy-fi' not in result.output
assert 'dummy-en' not in result.output


def test_list_projects_config_path_option_nonexistent():
nonexistent_file = "nonexistent.cfg"
result = runner.invoke(
annif.cli.cli, ["list-projects", "--projects", nonexistent_file])
assert not result.exception
assert result.exit_code == 0
assert 'Project configuration file "{}" is missing.'.format(
nonexistent_file) in result.output


def test_show_project():
result = runner.invoke(annif.cli.cli, ['show-project', 'dummy-en'])
assert not result.exception
Expand Down

0 comments on commit f9b1294

Please sign in to comment.