support integer choiceoption

This commit is contained in:
Emmanuel Garette 2019-08-03 09:06:27 +02:00
parent 74215a6f80
commit e6a9a37607
2 changed files with 52 additions and 15 deletions

View File

@ -237,7 +237,7 @@ def test_leadership_modif_follower_choice_unknown(json):
[--leader.follower_boolean INDEX] [--leader.follower_boolean INDEX]
[--leader.no-follower_boolean INDEX] [--leader.no-follower_boolean INDEX]
[--leader.follower_choice INDEX [{opt1,opt2}]] [--leader.follower_choice INDEX [{opt1,opt2}]]
prog.py: error: invalid choice: 'opt_unknown' (choose from 'opt1', 'opt2') prog.py: error: argument --leader.follower_choice: invalid choice: 'opt_unknown' (choose from 'opt1', 'opt2')
""" """
config = get_config(json) config = get_config(json)
parser = TiramisuCmdlineParser(config, 'prog.py') parser = TiramisuCmdlineParser(config, 'prog.py')

View File

@ -33,6 +33,17 @@ except ModuleNotFoundError:
ConfigJson = Config ConfigJson = Config
def get_choice_list(obj, properties, display):
choices = obj.value.list()
if choices[0] == '':
del choices[0]
if display:
choices = '{{{}}}'.format(','.join(choices))
if 'mandatory' not in properties:
choices = f'[{choices}]'
return choices
class TiramisuNamespace(Namespace): class TiramisuNamespace(Namespace):
def __init__(self, def __init__(self,
config: Config, config: Config,
@ -41,6 +52,7 @@ class TiramisuNamespace(Namespace):
super().__setattr__('_root', root) super().__setattr__('_root', root)
super().__setattr__('list_force_no', {}) super().__setattr__('list_force_no', {})
super().__setattr__('list_force_del', {}) super().__setattr__('list_force_del', {})
super().__setattr__('arguments', {})
self._populate() self._populate()
super().__init__() super().__init__()
@ -74,6 +86,22 @@ class TiramisuNamespace(Namespace):
else: else:
_setattr = self._setattr _setattr = self._setattr
true_value = value true_value = value
if option.option.type() == 'choice':
# HACK if integer in choice
values = option.value.list()
if isinstance(value, list):
int_value = []
for val in value:
if isinstance(val, str) and val.isdigit():
int_val = int(val)
if int_val in values:
val = int_val
int_value.append(val)
value = int_value
elif value not in values and isinstance(value, str) and value.isdigit():
int_value = int(value)
if int_value in values:
value = int_value
try: try:
if key in self.list_force_del: if key in self.list_force_del:
option.value.pop(value) option.value.pop(value)
@ -81,7 +109,16 @@ class TiramisuNamespace(Namespace):
_setattr(option, true_key, key, value) _setattr(option, true_key, key, value)
except ValueError as err: except ValueError as err:
if option.option.type() == 'choice': if option.option.type() == 'choice':
raise ValueError("invalid choice: '{}' (choose from {})".format(true_value, ', '.join([f"'{val}'" for val in option.value.list()]))) choices = get_choice_list(option, option.property.get(), False)
values = option.value.list()
if isinstance(true_value, list):
for val in value:
if val not in values:
display_value = val
break
else:
display_value = true_value
raise ValueError("argument {}: invalid choice: '{}' (choose from {})".format(self.arguments[key], display_value, ', '.join([f"'{val}'" for val in choices])))
else: else:
raise err raise err
@ -173,8 +210,11 @@ class _BuildKwargs:
else: else:
ga_name = name ga_name = name
self.kwargs['dest'] = self.gen_argument_name(option.path(), False) self.kwargs['dest'] = self.gen_argument_name(option.path(), False)
self.args = [self.cmdlineparser._gen_argument(ga_name, is_short_name)] argument = self.cmdlineparser._gen_argument(ga_name, is_short_name)
self.cmdlineparser.namespace.arguments[option.path()] = argument
self.args = [argument]
else: else:
self.cmdlineparser.namespace.arguments[option.path()] = option.path()
self.args = [option.path()] self.args = [option.path()]
def __setitem__(self, def __setitem__(self,
@ -191,7 +231,9 @@ class _BuildKwargs:
name = self.gen_argument_name(option.name(), is_short_name) name = self.gen_argument_name(option.name(), is_short_name)
else: else:
name = option.name() name = option.name()
self.args.insert(0, self.cmdlineparser._gen_argument(name, is_short_name)) argument = self.cmdlineparser._gen_argument(name, is_short_name)
self.cmdlineparser.namespace.arguments[option.path()] = argument
self.args.insert(0, argument)
def gen_argument_name(self, name, is_short_name): def gen_argument_name(self, name, is_short_name):
if self.force_no: if self.force_no:
@ -467,14 +509,9 @@ class TiramisuCmdlineParser(ArgumentParser):
kwargs['nargs'] = 2 kwargs['nargs'] = 2
if _forhelp and 'mandatory' not in properties: if _forhelp and 'mandatory' not in properties:
metavar = f'[{metavar}]' metavar = f'[{metavar}]'
if option.type() == 'choice': if option.type() == 'choice' and _forhelp:
choice_list = obj.value.list() # do not manage choice with argparse there is problem with integer problem
if choice_list[0] == '': kwargs['metavar'] = ('INDEX', get_choice_list(obj, properties, True))
del choice_list[0]
choices = '{{{}}}'.format(','.join(choice_list))
if 'mandatory' not in properties:
choices = f'[{choices}]'
kwargs['metavar'] = ('INDEX', choices)
else: else:
kwargs['metavar'] = ('INDEX', metavar) kwargs['metavar'] = ('INDEX', metavar)
if force_del: if force_del:
@ -488,11 +525,11 @@ class TiramisuCmdlineParser(ArgumentParser):
if _forhelp and option.type() == 'boolean': if _forhelp and option.type() == 'boolean':
kwargs['metavar'] = 'INDEX' kwargs['metavar'] = 'INDEX'
kwargs['nargs'] = 1 kwargs['nargs'] = 1
elif option.type() == 'choice' and not option.isfollower(): elif option.type() == 'choice' and not option.isfollower() and _forhelp:
kwargs['choices'] = obj.value.list() # do not manage choice with argparse there is problem with integer problem
kwargs['choices'] = get_choice_list(obj, properties, False)
else: else:
pass pass
#raise NotImplementedError('not supported yet')
actions.setdefault(option.name(), []).append(kwargs) actions.setdefault(option.name(), []).append(kwargs)
for option_is_not_default in options_is_not_default.values(): for option_is_not_default in options_is_not_default.values():
self._option_is_not_default(**option_is_not_default) self._option_is_not_default(**option_is_not_default)