From d29067c6be4f595a72153094fc1b13d7132bc69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?August=20Andr=C3=A9=20Kvernmo?= Date: Thu, 7 Dec 2023 13:19:37 +0100 Subject: [PATCH] Added app-clients get, status in workflows update-execution, statistics in models get (#107) * Merge * Updates * Updates * make positional arguments keyword arguments * statistics * merge * Update * Update changelogs * Update * Update test --------- Co-authored-by: Magnus Rud --- CHANGELOG.md | 8 ++++++ lascli/__version__.py | 2 +- lascli/parser/app_clients.py | 8 ++++++ lascli/parser/models.py | 43 ++++++++++++++++--------------- lascli/parser/predictions.py | 18 ++++++------- lascli/parser/workflows.py | 16 ++++++++---- lascli/util.py | 14 ++++++++++ requirements.txt | 2 +- tests/test_app_clients.py | 12 +++++++-- tests/test_models.py | 7 ++++- tests/test_workflow_executions.py | 8 ++++-- 11 files changed, 96 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6396f6..65fea6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Version 13.0.0 - 2023-12-07 + +- Added `app-clients get` +- Added optional parameter `--status` to `workflows update-execution` +- Added optional parameter `--next-transition-id` to `workflows update-execution` +- Removed mandatory parameter `next_transition_id` from `workflows update-execution` +- Added optional parameter `--statistics-last-n-days` to `models get` + ## Version 12.4.0 - 2023-12-05 - Updated default `--preprocess-image` in `create-default` workflow diff --git a/lascli/__version__.py b/lascli/__version__.py index b724705..8528a99 100644 --- a/lascli/__version__.py +++ b/lascli/__version__.py @@ -7,4 +7,4 @@ __maintainer_email__ = 'magnus@lucidtech.ai' __title__ = 'lucidtech-las-cli' __url__ = 'https://github.com/LucidtechAI/las-cli' -__version__ = '12.4.0' +__version__ = '13.0.0' diff --git a/lascli/parser/app_clients.py b/lascli/parser/app_clients.py index cf71e56..0cc30d0 100644 --- a/lascli/parser/app_clients.py +++ b/lascli/parser/app_clients.py @@ -22,6 +22,10 @@ def create_app_client( ) +def get_app_client(las_client: Client, app_client_id): + return las_client.get_app_client(app_client_id) + + def list_app_clients(las_client: Client, max_results=None, next_token=None): return las_client.list_app_clients(max_results=max_results, next_token=next_token) @@ -49,6 +53,10 @@ def create_app_clients_parser(subparsers): create_app_client_parser.add_argument('--role-ids', nargs='+', default=NotProvided) create_app_client_parser.set_defaults(cmd=create_app_client) + get_app_client_parser = subparsers.add_parser('get') + get_app_client_parser.add_argument('app_client_id') + get_app_client_parser.set_defaults(cmd=get_app_client) + list_app_clients_parser = subparsers.add_parser('list') list_app_clients_parser.add_argument('--max-results', '-m', type=int, default=None) list_app_clients_parser.add_argument('--next-token', '-n', default=None) diff --git a/lascli/parser/models.py b/lascli/parser/models.py index e08734d..ff3f883 100644 --- a/lascli/parser/models.py +++ b/lascli/parser/models.py @@ -3,7 +3,7 @@ from las import Client -from lascli.util import NotProvided, nullable, json_path, json_or_json_path +from lascli.util import NotProvided, nullable, json_path, json_or_json_path, int_range def create_model(las_client: Client, field_config, **optional_args): @@ -26,8 +26,8 @@ def delete_model(las_client: Client, model_id): return las_client.delete_model(model_id=model_id) -def get_model(las_client: Client, model_id): - return las_client.get_model(model_id=model_id) +def get_model(las_client: Client, model_id, statistics_last_n_days): + return las_client.get_model(model_id=model_id, statistics_last_n_days=statistics_last_n_days) def update_model(las_client: Client, model_id, **optional_args): @@ -101,16 +101,16 @@ def create_models_parser(subparsers): create_parser.add_argument('--preprocess-config', '-p', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the pre processing configuration for predictions made by this model { - 'autoRotate': True | False (optional) - 'maxPages': 1 - 3 (optional) - 'imageQuality': 'LOW' | 'HIGH' (optional) - 'pages': List with up to 3 page-indices to process (optional) - 'rotation': 0, 90, 180 or 270 (optional) + "autoRotate": True | False (optional) + "maxPages": 1 - 3 (optional) + "imageQuality": "LOW" | "HIGH" (optional) + "pages": List with up to 3 page-indices to process (optional) + "rotation": 0, 90, 180 or 270 (optional) } Examples: - {'pages': [0, 1, 5], 'autoRotate': True} - {'pages': [0, 1, -1], 'rotation': 90, 'imageQuality': 'HIGH'} - {'maxPages': 3, 'imageQuality': 'LOW'} + {"pages": [0, 1, 5], "autoRotate": True} + {"pages": [0, 1, -1], "rotation": 90, "imageQuality": "HIGH"} + {"maxPages": 3, "imageQuality": "LOW"} ''')) create_parser.add_argument('--postprocess-config', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the post processing configuration for predictions made by this model @@ -122,7 +122,7 @@ def create_models_parser(subparsers): } } Examples: - {"strategy": "BEST_FIRST"} + {"strategy": "BEST_FIRST", "outputFormat": "v2"} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3}} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3, "collapse": true}} ''')) @@ -141,6 +141,7 @@ def create_models_parser(subparsers): get_parser = subparsers.add_parser('get') get_parser.add_argument('model_id') + get_parser.add_argument('--statistics-last-n-days', type=int_range(1, 30)) get_parser.set_defaults(cmd=get_model) update_parser = subparsers.add_parser('update', formatter_class=RawTextHelpFormatter) @@ -167,16 +168,16 @@ def create_models_parser(subparsers): update_parser.add_argument('--preprocess-config', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the pre processing configuration for predictions made by this model { - 'autoRotate': True | False (optional) - 'maxPages': 1 - 3 (optional) - 'imageQuality': 'LOW' | 'HIGH' (optional) - 'pages': List with up to 3 page-indices to process (optional) - 'rotation': 0, 90, 180 or 270 (optional) + "autoRotate": True | False (optional) + "maxPages": 1 - 3 (optional) + "imageQuality": "LOW" | "HIGH" (optional) + "pages": List with up to 3 page-indices to process (optional) + "rotation": 0, 90, 180 or 270 (optional) } Examples: - {'pages': [0, 1, 5], 'autoRotate': True} - {'pages': [0, 1, -1], 'rotation': 90, 'imageQuality': 'HIGH'} - {'maxPages': 3, 'imageQuality': 'LOW'} + {"pages": [0, 1, 5], "autoRotate": True} + {"pages": [0, 1, -1], "rotation": 90, "imageQuality": "HIGH"} + {"maxPages": 3, "imageQuality": "LOW"} ''')) update_parser.add_argument('--postprocess-config', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the post processing configuration for predictions made by this model @@ -188,7 +189,7 @@ def create_models_parser(subparsers): } } Examples: - {"strategy": "BEST_FIRST"} + {"strategy": "BEST_FIRST", "outputFormat": "v2"} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3}} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3, "collapse": true}} ''')) diff --git a/lascli/parser/predictions.py b/lascli/parser/predictions.py index 8c6e1d5..fb3626f 100644 --- a/lascli/parser/predictions.py +++ b/lascli/parser/predictions.py @@ -26,16 +26,16 @@ def create_predictions_parser(subparsers): create_predicton_parser.add_argument('--preprocess-config', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the pre processing configuration for this prediction { - 'autoRotate': True | False (optional) - 'maxPages': 1 - 3 (optional) - 'imageQuality': 'LOW' | 'HIGH' (optional) - 'pages': List with up to 3 page-indices to process (optional) - 'rotation': 0, 90, 180 or 270 (optional) + "autoRotate": True | False (optional) + "maxPages": 1 - 3 (optional) + "imageQuality": "LOW" | "HIGH" (optional) + "pages": List with up to 3 page-indices to process (optional) + "rotation": 0, 90, 180 or 270 (optional) } Examples: - {'pages': [0, 1, 5], 'autoRotate': True} - {'pages': [0, 1, -1], 'rotation': 90, 'imageQuality': 'HIGH'} - {'maxPages': 3, 'imageQuality': 'LOW'} + {"pages": [0, 1, 5], "autoRotate": True} + {"pages": [0, 1, -1], "rotation": 90, "imageQuality": "HIGH"} + {"maxPages": 3, "imageQuality": "LOW"} ''')) create_predicton_parser.add_argument('--postprocess-config', type=json_or_json_path, help=textwrap.dedent(''' Path or inline JSON with the post processing configuration for this prediction @@ -47,7 +47,7 @@ def create_predictions_parser(subparsers): } } Examples: - {"strategy": "BEST_FIRST"} + {"strategy": "BEST_FIRST", "outputFormat": "v2"} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3}} {"strategy": "BEST_N_PAGES", "parameters": {"n": 3, "collapse": true}} ''')) diff --git a/lascli/parser/workflows.py b/lascli/parser/workflows.py index 294452b..b7f93d3 100644 --- a/lascli/parser/workflows.py +++ b/lascli/parser/workflows.py @@ -44,8 +44,8 @@ def get_workflow_execution(las_client: Client, workflow_id, execution_id): return las_client.get_workflow_execution(workflow_id, execution_id) -def update_workflow_execution(las_client: Client, workflow_id, execution_id, next_transition_id): - return las_client.update_workflow_execution(workflow_id, execution_id, next_transition_id) +def update_workflow_execution(las_client: Client, workflow_id, execution_id, next_transition_id, status): + return las_client.update_workflow_execution(workflow_id, execution_id, next_transition_id=next_transition_id, status=status) def delete_workflow_execution(las_client: Client, workflow_id, execution_id): @@ -218,9 +218,15 @@ def create_workflows_parser(subparsers): update_workflow_execution_parser = subparsers.add_parser('update-execution') update_workflow_execution_parser.add_argument('workflow_id') update_workflow_execution_parser.add_argument('execution_id') - update_workflow_execution_parser.add_argument( - 'next_transition_id', - help='use las:transition:commons-failed to end an execution', + update_workflow_execution_group = update_workflow_execution_parser.add_mutually_exclusive_group() + update_workflow_execution_group.add_argument( + '--next-transition-id', + help='Specify which transition to continue from. Use las:transition:commons-failed to end an execution', + ) + update_workflow_execution_group.add_argument( + '--status', + choices={'completed', 'succeeded'}, + help='Change status of workflow execution, can only update from succeeded to completed and vice versa', ) update_workflow_execution_parser.set_defaults(cmd=update_workflow_execution) diff --git a/lascli/util.py b/lascli/util.py index 7b9a303..0e47173 100644 --- a/lascli/util.py +++ b/lascli/util.py @@ -1,3 +1,4 @@ +import argparse import collections import contextlib import json @@ -64,3 +65,16 @@ def json_or_json_path(value): pass raise Exception('Could not interpret input as neither JSON nor a path containing JSON') + + +def int_range(min_value, max_value): + def checker(arg): + try: + value = int(arg) + except ValueError: + raise argparse.ArgumentTypeError('must be an integer') + if not (min_value <= value <= max_value): + raise argparse.ArgumentTypeError(f'must be in range [{min_value}..{max_value}]') + return value + + return checker diff --git a/requirements.txt b/requirements.txt index 728096a..52aa071 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ PyYAML>=6.0.0 argcomplete>=2.0.0 dateparser>=1.1.1 filetype>=1.0.13 -lucidtech-las~=10.2 +lucidtech-las~=11.0 diff --git a/tests/test_app_clients.py b/tests/test_app_clients.py index 7f9c837..61081dc 100644 --- a/tests/test_app_clients.py +++ b/tests/test_app_clients.py @@ -54,7 +54,7 @@ def test_app_clients_update(parser, client, name_and_description, role_ids): *name_and_description, *role_ids, ] - + if len(args) <= 3: # patch call requires at least one change with pytest.raises(Exception): util.main_parser(parser, client, args) @@ -62,6 +62,15 @@ def test_app_clients_update(parser, client, name_and_description, role_ids): util.main_parser(parser, client, args) +def test_app_clients_get(parser, client): + args = [ + 'app-clients', + 'get', + service.create_app_client_id(), + ] + util.main_parser(parser, client, args) + + def test_app_clients_list(parser, client, list_defaults): args = [ 'app-clients', @@ -71,7 +80,6 @@ def test_app_clients_list(parser, client, list_defaults): util.main_parser(parser, client, args) -@pytest.mark.skip def test_app_clients_delete(parser, client): args = [ 'app-clients', diff --git a/tests/test_models.py b/tests/test_models.py index c558273..49aaf3f 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -94,11 +94,16 @@ def test_models_list(parser, client, list_defaults, owner): util.main_parser(parser, client, args) -def test_models_get(parser, client): +@pytest.mark.parametrize('statistics_last_n_days', [ + ('--statistics-last-n-days', '14'), + (), +]) +def test_models_get(parser, client, statistics_last_n_days): args = [ 'models', 'get', service.create_model_id(), + *statistics_last_n_days, ] util.main_parser(parser, client, args) diff --git a/tests/test_workflow_executions.py b/tests/test_workflow_executions.py index c32a3a6..6520f41 100644 --- a/tests/test_workflow_executions.py +++ b/tests/test_workflow_executions.py @@ -66,12 +66,16 @@ def test_executions_get(parser, client): util.main_parser(parser, client, args) -def test_executions_update(parser, client): +@pytest.mark.parametrize('optional_args', [ + ('--next-transition-id', service.create_transition_id()), + ('--status', 'completed'), +]) +def test_executions_update(parser, client, optional_args): args = [ 'workflows', 'update-execution', service.create_workflow_id(), service.create_workflow_execution_id(), - service.create_transition_id(), + *optional_args, ] util.main_parser(parser, client, args)