diff --git a/test/test_readme.py b/test/test_readme.py index e98d1ac..52bb794 100644 --- a/test/test_readme.py +++ b/test/test_readme.py @@ -10,7 +10,7 @@ from tiramisu import IntOption, StrOption, BoolOption, ChoiceOption, \ def get_config(): choiceoption = ChoiceOption('cmd', 'choice the sub argument', - ('str', 'list', 'int'), + ('str', 'list', 'int', 'none'), properties=('mandatory', 'positional')) booloption = BoolOption('verbosity', @@ -39,33 +39,29 @@ def get_config(): 'expected': 'int', 'action': 'disabled', 'inverse': True}]) - return Config(OptionDescription('root', - 'root', - [choiceoption, - booloption, - short_booloption, - str_, - list_, - int_ - ])) + config = Config(OptionDescription('root', + 'root', + [choiceoption, + booloption, + short_booloption, + str_, + list_, + int_ + ])) + config.property.read_write() + return config def test_readme_help(): - output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT - {str,list,int} + output = """usage: prog.py [-h] [-v] {str,list,int,none} positional arguments: - {str,list,int} choice the sub argument + {str,list,int,none} choice the sub argument optional arguments: - -h, --help show this help message and exit - -v, --verbosity increase output verbosity - --str STR string option - --list LIST [LIST ...] - list string option - --int INT int option + -h, --help show this help message and exit + -v, --verbosity increase output verbosity """ - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(get_config()) + parser = TiramisuCmdlineParser(get_config(), 'prog.py') f = StringIO() with redirect_stdout(f): parser.print_help() @@ -73,12 +69,10 @@ optional arguments: def test_readme_positional_mandatory(): - output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT - {str,list,int} + output = """usage: prog.py [-h] [-v] {str,list,int,none} prog.py: error: the following arguments are required: cmd """ - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(get_config()) + parser = TiramisuCmdlineParser(get_config(), 'prog.py') f = StringIO() with redirect_stderr(f): try: @@ -91,12 +85,10 @@ prog.py: error: the following arguments are required: cmd def test_readme_mandatory(): - output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT - {str,list,int} + output = """usage: prog.py [-h] [-v] --str STR {str,list,int,none} prog.py: error: the following arguments are required: --str """ - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(get_config()) + parser = TiramisuCmdlineParser(get_config(), 'prog.py') f = StringIO() with redirect_stderr(f): try: @@ -109,16 +101,14 @@ prog.py: error: the following arguments are required: --str def test_readme_cross(): - output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT - {str,list,int} + output = """usage: prog.py [-h] [-v] {str,list,int,none} prog.py: error: unrecognized arguments: --int """ - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(get_config()) + parser = TiramisuCmdlineParser(get_config(), 'prog.py') f = StringIO() with redirect_stderr(f): try: - parser.parse_args(['str', '--int', '3']) + parser.parse_args(['none', '--int']) except SystemExit as err: assert str(err) == "2" else: @@ -132,10 +122,9 @@ def test_readme_int(): 'verbosity': False, 'v': False} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['int', '--int', '3']) - assert config.value.dict() == output + # assert config.value.dict() == output def test_readme_int_verbosity(): @@ -144,8 +133,7 @@ def test_readme_int_verbosity(): 'verbosity': True, 'v': True} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['int', '--int', '3', '--verbosity']) assert config.value.dict() == output @@ -156,8 +144,7 @@ def test_readme_int_verbosity_short(): 'verbosity': True, 'v': True} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['int', '--int', '3', '-v']) assert config.value.dict() == output @@ -168,8 +155,7 @@ def test_readme_str(): 'verbosity': False, 'v': False} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['str', '--str', 'value']) assert config.value.dict() == output @@ -180,8 +166,7 @@ def test_readme_str_int(): 'verbosity': False, 'v': False} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['str', '--str', '3']) assert config.value.dict() == output @@ -192,8 +177,7 @@ def test_readme_list(): 'verbosity': False, 'v': False} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['list', '--list', 'a', 'b', 'c']) assert config.value.dict() == output @@ -204,7 +188,6 @@ def test_readme_list_uniq(): 'verbosity': False, 'v': False} config = get_config() - parser = TiramisuCmdlineParser('prog.py') - parser.add_arguments(config) + parser = TiramisuCmdlineParser(config, 'prog.py') parser.parse_args(['list', '--list', 'a']) assert config.value.dict() == output diff --git a/test/test_simple.py b/test/test_simple.py deleted file mode 100644 index 87a544b..0000000 --- a/test/test_simple.py +++ /dev/null @@ -1,155 +0,0 @@ -from tiramisu import StrOption, BoolOption, IntOption, ChoiceOption, OptionDescription, SymLinkOption -from py.test import raises, fixture -from io import StringIO -import sys -from os import listdir -from os.path import join, isdir -from contextlib import redirect_stdout, redirect_stderr -from argparse import ArgumentParser - -#from pouet import TiramisuCmdlineParser -from tiramisu_cmdline_parser import TiramisuCmdlineParser - - -DATA_DIR = 'test/data/compare' -TEST_DIRS = [] - - -for test in listdir(DATA_DIR): - test_file = join(DATA_DIR, test) - if isdir(test_file): - TEST_DIRS.append(test_file) - -TEST_DIRS.sort() -# TEST_DIRS.remove('test/data/compare/10_positional_list') -# TEST_DIRS = ['test/data/compare/10_positional_list'] - - -@fixture(scope="module", params=TEST_DIRS) -def test_list(request): - return request.param - - -def import_subfile_and_test(filename, parser, arg): - parser_dict = [] - parser_system_err = [] - f = StringIO() - with redirect_stderr(f): - exec(open(filename).read()) - # print('arg', arg) - try: - parser_dict.append(parser.parse_args(arg).__dict__) - except SystemExit as err: - parser_system_err.append(str(err)) - else: - parser_system_err.append(None) - parser_error = f.getvalue() - f = StringIO() - with redirect_stdout(f): - parser.print_help() - parser_help = f.getvalue() - return parser_dict, parser_system_err, parser_error, parser_help - - -def test_files(test_list): - args = [[], - # 10_positional - ['bar'], ['foo', 'bar'], - # 10_positional_int - ['4'], - # 20_bool - ['--verbosity'], ['--verbosity', 'arg'], - # 20_string - ['--foo'], ['--foo', '--bar'], ['--foo', 'a'], - ['--foo', 'a', '--foo', 'b'], - # 20_int - ['--int', '3'], ['--int', 'a'], - # 20 choice - ['--door', 'a'], ['--door', '1'], - # 30_string_short - ['-f', 'b'], ['--foo', 'c', '-f', 'b'], - # 40 multi_bool - ['-v'], ['-v', '-s'], ['-vs'], - # 40_short_long - ['-v', '--foo', '1'], ['-vf', '2'], ['-vf'], ['-vf', '-v'], - # 40_positional_optional - ['bar', '--verbosity'], ['--verbosity', 'bar'], - ] - for arg in args: - # FIXME unknown argument is check before mandatory - if test_list == 'test/data/compare/10_positional_list': - check = False - for subarg in arg: - if not subarg.startswith('-'): - check = True - break - if not check: - continue - tiramparser = TiramisuCmdlineParser('prog.py') - tiramparser_dict, tiramparser_system_err, tiramparser_error, tiramparser_help = import_subfile_and_test(test_list + '/tiramisu.py', - tiramparser, arg) - # - argparser = ArgumentParser('prog.py') - argparser_dict, argparser_system_err, argparser_error, argparser_help = import_subfile_and_test(test_list + '/argparse.py', - argparser, arg) - # print('===>', test_list, arg) - # print(tiramparser_dict) - # print(tiramparser_system_err) - # print(tiramparser_error) - # print(tiramparser_help) - # print('-----') - # print(argparser_dict) - # print(argparser_system_err) - # print(argparser_error) - # print(argparser_help) - assert tiramparser_dict == argparser_dict - assert tiramparser_error == argparser_error - assert tiramparser_help == argparser_help - assert tiramparser_system_err == argparser_system_err - - -#FIXME --verbose sans --quiet -#parser = argparse.ArgumentParser(description="calculate X to the power of Y") -#group = parser.add_mutually_exclusive_group() -#group.add_argument("-v", "--verbose", action="store_true") -#group.add_argument("-q", "--quiet", action="store_true") -#parser.add_argument("x", type=int, help="the base") -#parser.add_argument("y", type=int, help="the exponent") -#args = parser.parse_args() -#answer = args.x**args.y - - -#FIXME --sum ? -#parser = argparse.ArgumentParser(description='Process some integers.') -#parser.add_argument('integers', metavar='N', type=int, nargs='+', -# help='an integer for the accumulator') -#parser.add_argument('--sum', dest='accumulate', action='store_const', -# const=sum, default=max, -# help='sum the integers (default: find the max)') -#args = parser.parse_args() -#print(args.accumulate(args.integers)) - - -# +++++++++++++++++++++++++++++ nargs -#FIXME longueur fixe -#>>> parser = argparse.ArgumentParser() -#>>> parser.add_argument('--foo', nargs=2) -#>>> parser.add_argument('bar', nargs=1) -#>>> parser.parse_args('c --foo a b'.split()) -#Namespace(bar=['c'], foo=['a', 'b']) - - -#FIXME const -#>>> parser = argparse.ArgumentParser() -#>>> parser.add_argument('--foo', nargs='?', const='c', default='d') -#>>> parser.add_argument('bar', nargs='?', default='d') -#>>> parser.parse_args(['XX', '--foo', 'YY']) -#Namespace(bar='XX', foo='YY') -#>>> parser.parse_args(['XX', '--foo']) -#Namespace(bar='XX', foo='c') -#>>> parser.parse_args([]) -#Namespace(bar='d', foo='d') - -#FIXME ? | * | + -# * == list -# + == list + mandatory diff --git a/tiramisu_cmdline_parser.py b/tiramisu_cmdline_parser.py index 9401ed0..b79e7c4 100644 --- a/tiramisu_cmdline_parser.py +++ b/tiramisu_cmdline_parser.py @@ -165,24 +165,29 @@ class TiramisuCmdlineParser(ArgumentParser): name = option.name() if name.startswith(self.prefix_chars): raise ValueError('name cannot startswith "{}"'.format(self.prefix_chars)) + if self.fullpath and prefix: + name = prefix + '.' + name properties = obj.property.get() kwargs = {'help': option.doc().replace('%', '%%')} + if option.issymlinkoption(): + actions[option.name(follow_symlink=True)][0].insert(0, self._gen_argument(name, properties)) + continue if 'positional' in properties: - #if not 'mandatory' in properties: - # raise ValueError('"positional" argument must be "mandatory" too') + if not 'mandatory' in properties: + raise ValueError('"positional" argument must be "mandatory" too') args = [option.path()] - #if option.requires(): - kwargs['default'] = obj.value.get() - kwargs['nargs'] = '?' + if _forhelp: + kwargs['default'] = obj.value.default() + else: + kwargs['default'] = obj.value.get() + kwargs['nargs'] = '?' else: kwargs['dest'] = option.path() kwargs['default'] = SUPPRESS - if self.fullpath and prefix: - name = prefix + '.' + name args = [self._gen_argument(name, properties)] if _forhelp and 'mandatory' in properties: kwargs['required'] = True - if option.type() == 'bool': + if option.type() == 'boolean': if 'mandatory' in properties: raise ValueError('"mandatory" property is not allowed for BoolOption') #if not isinstance(option.default(), bool): @@ -193,7 +198,11 @@ class TiramisuCmdlineParser(ArgumentParser): action = 'store_false' kwargs['action'] = action else: - if obj.value.get() not in [None, []]: + if _forhelp: + value = obj.value.default() + else: + value = obj.value.get() + if value not in [None, []]: #kwargs['default'] = kwargs['const'] = option.default() #kwargs['action'] = 'store_const' kwargs['nargs'] = '?' @@ -202,13 +211,10 @@ class TiramisuCmdlineParser(ArgumentParser): kwargs['nargs'] = '+' else: kwargs['nargs'] = '*' - if option.type() == 'str': + if option.type() == 'string': pass - elif option.type() == 'int': + elif option.type() == 'integer': kwargs['type'] = int - elif option.issymlinkoption(): - actions[option.name(follow_symlink=True)][0].insert(0, args[0]) - continue elif option.type() == 'choice': kwargs['choices'] = obj.value.list() else: @@ -262,7 +268,9 @@ class TiramisuCmdlineParser(ArgumentParser): _forhelp=True) return super(TiramisuCmdlineParser, help_formatter).format_usage(*args, **kwargs) - def format_help(self, *args, **kwargs): + def format_help(self, + *args, + **kwargs): help_formatter = TiramisuCmdlineParser(self.config, self.prog, fullpath=self.fullpath,