From d313e9a41dc3d4c297859fee6714d5133c055eea Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 10 Jan 2019 09:55:45 +0100 Subject: [PATCH] works now with tiramisu-json-api --- examples/Hangman/{hangman.py => example.py} | 0 tiramisu_cmdline_parser.py | 101 ++++++++++++-------- 2 files changed, 63 insertions(+), 38 deletions(-) rename examples/Hangman/{hangman.py => example.py} (100%) diff --git a/examples/Hangman/hangman.py b/examples/Hangman/example.py similarity index 100% rename from examples/Hangman/hangman.py rename to examples/Hangman/example.py diff --git a/tiramisu_cmdline_parser.py b/tiramisu_cmdline_parser.py index d5245fe..e4f8787 100644 --- a/tiramisu_cmdline_parser.py +++ b/tiramisu_cmdline_parser.py @@ -14,23 +14,31 @@ # along with this program. If not, see . -from typing import Union, List +from typing import Union, List, Optional from argparse import ArgumentParser, Namespace, SUPPRESS -from tiramisu import Option, OptionDescription, Config, BoolOption, StrOption, IntOption, \ - ChoiceOption, SymLinkOption from tiramisu.error import PropertiesOptionError +try: + from tiramisu import Config +except ImportError: + Config = None +try: + from tiramisu_json_api import Config as ConfigJson + if Config is None: + Config = ConfigJson +except ImportError: + ConfigJson = Config class TiramisuNamespace(Namespace): def _populate(self): - self._config.property.read_only() + #self._config.property.read_only() for tiramisu_key, tiramisu_value in self._config.value.dict().items(): option = self._config.option(tiramisu_key) - if not isinstance(option.option.get(), SymLinkOption): + if not option.option.issymlinkoption(): if tiramisu_value == [] and option.option.ismulti() and option.owner.isdefault(): tiramisu_value = None super().__setattr__(tiramisu_key, tiramisu_value) - self._config.property.read_write() + #self._config.property.read_write() def __init__(self, config): self._config = config @@ -40,7 +48,7 @@ class TiramisuNamespace(Namespace): if key == '_config': super().__setattr__(key, value) return - self._config.property.read_write() + # self._config.property.read_write() option = self._config.option(key) if option.option.ismulti() and value is not None and not isinstance(value, list): value = [value] @@ -53,17 +61,21 @@ class TiramisuNamespace(Namespace): class TiramisuCmdlineParser(ArgumentParser): - def __init__(self, *args, **kwargs): + def __init__(self, + *args, + **kwargs): self.config = None super().__init__(*args, **kwargs) - def _match_arguments_partial(self, actions, arg_string_pattern): + def _match_arguments_partial(self, + actions, + arg_string_pattern): # used only when check first proposal for first value # we have to remove all actions with propertieserror # so only first settable option will be returned actions_pop = [] for idx, action in enumerate(actions): - if self.config.unrestraint.option(action.dest).property.get(only_raises=True): + if self.config.option(action.dest).property.get(only_raises=True): actions_pop.append(idx) else: break @@ -81,44 +93,59 @@ class TiramisuCmdlineParser(ArgumentParser): raise NotImplementedError('do not use add_subparsers') def _config_to_argparser(self, - _forhelp: bool): + _forhelp: bool, + config, + prefix: Optional[str]=None, + group=None) -> None: + if group is None: + group = super() actions = {} - for obj in self.config.unrestraint.option.list(): - if obj.option.properties(only_raises=True) or 'frozen' in obj.option.properties(): - continue + for obj in config.list(type='all'): option = obj.option - tiramisu_option = option.get() + if option.isoptiondescription(): + if _forhelp: + group = self.add_argument_group(option.doc()) + if prefix: + prefix_ = prefix + '.' + option.name() + else: + prefix_ = option.path() + self._config_to_argparser(_forhelp, obj, prefix_, group) + continue + if 'frozen' in option.properties(): + continue name = option.name() if name.startswith(self.prefix_chars): raise ValueError('name cannot startswith "{}"'.format(self.prefix_chars)) properties = obj.property.get() - kwargs = {'help': option.doc(), + kwargs = {'help': option.doc().replace('%', '%%'), 'default': SUPPRESS} if 'positional' in properties: #if not 'mandatory' in properties: # raise ValueError('"positional" argument must be "mandatory" too') args = [name] - if option.requires(): - kwargs['nargs'] = '?' + #if option.requires(): + kwargs['nargs'] = '?' else: + if prefix: + name = prefix + '.' + name if len(name) == 1 and 'longargument' not in properties: args = [self.prefix_chars + name] else: args = [self.prefix_chars * 2 + name] if _forhelp and 'mandatory' in properties: kwargs['required'] = True - if isinstance(tiramisu_option, BoolOption): + if option.type() == 'bool': if 'mandatory' in properties: raise ValueError('"mandatory" property is not allowed for BoolOption') #if not isinstance(option.default(), bool): # raise ValueError('default value is mandatory for BoolOption') - if option.default() is False: + if obj.value.get() is False: action = 'store_true' else: action = 'store_false' kwargs['action'] = action else: - if option.default() not in [None, []]: + if obj.value.get() not in [None, []]: #kwargs['default'] = kwargs['const'] = option.default() #kwargs['action'] = 'store_const' kwargs['nargs'] = '?' @@ -127,34 +154,29 @@ class TiramisuCmdlineParser(ArgumentParser): kwargs['nargs'] = '+' else: kwargs['nargs'] = '*' - if isinstance(tiramisu_option, StrOption): + if option.type() == 'str': pass - elif isinstance(tiramisu_option, IntOption): + elif option.type() == 'int': kwargs['type'] = int - elif isinstance(tiramisu_option, SymLinkOption): - tiramisu_option = tiramisu_option.impl_getopt() - actions[tiramisu_option.impl_getname()][0].insert(0, args[0]) + elif option.issymlinkoption(): + option = option.impl_getopt() + actions[option.impl_getname()][0].insert(0, args[0]) continue - elif isinstance(tiramisu_option, ChoiceOption): + elif option.type() == 'choice': kwargs['choices'] = obj.value.list() else: pass #raise NotImplementedError('not supported yet') actions[option.name()] = (args, kwargs) for args, kwargs in actions.values(): - super().add_argument(*args, **kwargs) + group.add_argument(*args, **kwargs) def add_arguments(self, - tiramisu: Union[Config, Option, List[Option], OptionDescription], + tiramisu: Union[Config, ConfigJson], _forhelp: bool=False) -> None: - if not isinstance(tiramisu, Config): - if not isinstance(tiramisu, OptionDescription): - if isinstance(tiramisu, Option): - tiramisu = [tiramisu] - tiramisu = OptionDescription('root', 'root', tiramisu) - tiramisu = Config(tiramisu) self.config = tiramisu - self._config_to_argparser(_forhelp) + self._config_to_argparser(_forhelp, + self.config.option) def parse_args(self, *args, **kwargs): kwargs['namespace'] = TiramisuNamespace(self.config) @@ -163,7 +185,7 @@ class TiramisuCmdlineParser(ArgumentParser): del namespaces.__dict__['_config'] except PropertiesOptionError as err: name = err._option_bag.option.impl_getname() - properties = self.config.unrestraint.option(name).property.get() + properties = self.config.option(name).property.get() if 'positional' not in properties: if len(name) == 1 and 'longargument' not in properties: name = self.prefix_chars + name @@ -175,7 +197,10 @@ class TiramisuCmdlineParser(ArgumentParser): self.error('unrecognized arguments: {}'.format(name)) return namespaces - def format_usage(self, *args, _forhelp=False, **kwargs): + def format_usage(self, + *args, + _forhelp=False, + **kwargs): if _forhelp: return super().format_usage(*args, **kwargs) help_formatter = TiramisuCmdlineParser(self.prog)