From c09b3c08447bc2c2645b198f0ca142adf005a9e6 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 16 Mar 2020 15:34:51 +0100 Subject: [PATCH] support empty choice --- tests/test_choice.py | 207 +++++++++++++++++++++++++++++++++ tiramisu_cmdline_parser/api.py | 4 +- 2 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 tests/test_choice.py diff --git a/tests/test_choice.py b/tests/test_choice.py new file mode 100644 index 0000000..5c2e2ad --- /dev/null +++ b/tests/test_choice.py @@ -0,0 +1,207 @@ +from io import StringIO +from contextlib import redirect_stdout, redirect_stderr +import pytest + + +from tiramisu_cmdline_parser import TiramisuCmdlineParser +from tiramisu import ChoiceOption, OptionDescription, Config +try: + from tiramisu_api import Config as JsonConfig + params = ['tiramisu', 'tiramisu-json'] +except: + params = ['tiramisu'] + + + +def get_config(json): + positional = ChoiceOption('positional', + 'choice the sub argument', + ('str', 'list', 'int', 'none'), + properties=('positional', 'mandatory')) + positional_int = ChoiceOption('positional_int', + 'choice the sub argument', + (1, 2, 3), + properties=('positional', 'mandatory')) + str_ = ChoiceOption('str', + 'choice the sub argument', + ('str1', 'str2', 'str3')) + int_ = ChoiceOption('int', + 'choice the sub argument', + (1, 2, 3)) + int_multi = ChoiceOption('int_multi', + 'choice the sub argument', + (1, 2, 3), + multi=True) + od = OptionDescription('od', + 'od', + [positional, positional_int, str_, int_, int_multi]) + config = Config(od) + config.property.read_write() + if json == 'tiramisu': + return config + jconfig = JsonConfig(config.option.dict()) + return jconfig + + +@pytest.fixture(params=params) +def json(request): + return request.param + + +def test_choice_positional(json): + output1 = '''usage: prog.py "str" "1" [-h] [--str {str1,str2,str3}] [--int {1,2,3}] + [--int_multi [{1,2,3} [{1,2,3} ...]]] + {str,list,int,none} {1,2,3} +prog.py: error: argument positional: invalid choice: 'error' (choose from 'str', 'list', 'int', 'none') +''' + output2 = '''usage: prog.py "str" "1" [-h] [--str {str1,str2,str3}] [--int {1,2,3}] + [--int_multi [{1,2,3} [{1,2,3} ...]]] + {str,list,int,none} {1,2,3} +prog.py: error: argument positional_int: invalid choice: '4' (choose from '1', '2', '3') +''' + config = get_config(json) + parser = TiramisuCmdlineParser(config, 'prog.py') + parser.parse_args(['str', '1']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': None, + 'int_multi': []} + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['error', '1']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output1 + + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['str', '4']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output2 + + +def test_choice_str(json): + output = """usage: prog.py "str" "1" --str "str3" [-h] [--str {str1,str2,str3}] + [--int {1,2,3}] + [--int_multi [{1,2,3} [{1,2,3} ...]]] + {str,list,int,none} {1,2,3} +prog.py: error: argument --str: invalid choice: 'error' (choose from 'str1', 'str2', 'str3') +""" + config = get_config(json) + parser = TiramisuCmdlineParser(config, 'prog.py') + parser.parse_args(['str', '1', '--str', 'str1']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': 'str1', + 'int': None, + 'int_multi': []} + parser.parse_args(['str', '1', '--str', 'str2']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': 'str2', + 'int': None, + 'int_multi': []} + parser.parse_args(['str', '1', '--str', 'str3']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': 'str3', + 'int': None, + 'int_multi': []} + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['str', '1', '--str', 'error']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': 'str3', + 'int': None, + 'int_multi': []} + + +def test_choice_int(json): + output = """usage: prog.py "str" "1" --int "1" [-h] [--str {str1,str2,str3}] + [--int {1,2,3}] + [--int_multi [{1,2,3} [{1,2,3} ...]]] + {str,list,int,none} {1,2,3} +prog.py: error: argument --int: invalid choice: '4' (choose from '1', '2', '3') +""" + config = get_config(json) + parser = TiramisuCmdlineParser(config, 'prog.py') + parser.parse_args(['str', '1', '--int', '1']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': 1, + 'int_multi': []} + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['str', '1', '--int', '4']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': 1, + 'int_multi': []} + + +def test_choice_int_multi(json): + output = """usage: prog.py "str" "1" --int_multi "1" "2" [-h] [--str {str1,str2,str3}] + [--int {1,2,3}] + [--int_multi [{1,2,3} [{1,2,3} ...]]] + {str,list,int,none} {1,2,3} +prog.py: error: argument --int_multi: invalid choice: '4' (choose from '1', '2', '3') +""" + config = get_config(json) + parser = TiramisuCmdlineParser(config, 'prog.py') + parser.parse_args(['str', '1', '--int_multi', '1', '2']) + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': None, + 'int_multi': [1, 2]} + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['str', '1', '--int_multi', '4']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': None, + 'int_multi': [1, 2]} + f = StringIO() + with redirect_stderr(f): + try: + parser.parse_args(['str', '1', '--int_multi', '1', '4']) + except SystemExit as err: + assert str(err) == "2" + else: + raise Exception('must raises') + assert f.getvalue() == output + assert config.value.dict() == {'positional': 'str', + 'positional_int': 1, + 'str': None, + 'int': None, + 'int_multi': [1, 2]} diff --git a/tiramisu_cmdline_parser/api.py b/tiramisu_cmdline_parser/api.py index 51642c1..3a6dc38 100644 --- a/tiramisu_cmdline_parser/api.py +++ b/tiramisu_cmdline_parser/api.py @@ -26,7 +26,7 @@ except ImportError: RequirementError = PropertiesOptionError LeadershipError = ValueError try: - from tiramisu__api import Config as ConfigJson + from tiramisu_api import Config as ConfigJson if Config is None: Config = ConfigJson except ImportError: @@ -39,7 +39,7 @@ def get_choice_list(obj, properties, display): return str(choice) return choice choices = [convert(choice) for choice in obj.value.list()] - if choices[0] == '': + if choices and choices[0] == '': del choices[0] if display: choices = '{{{}}}'.format(','.join(choices))