From 3cde7960112242732c27b5f21c8d4a08718c4135 Mon Sep 17 00:00:00 2001 From: Hrabal Date: Sat, 15 Dec 2018 17:22:29 +0100 Subject: [PATCH] refactor --- classcli/clibuilder.py | 75 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/classcli/clibuilder.py b/classcli/clibuilder.py index 401725a..8c67571 100644 --- a/classcli/clibuilder.py +++ b/classcli/clibuilder.py @@ -15,6 +15,41 @@ def __getattribute__(self, attr): fg = rs = EmptyStringer() +def _load_object(module_or_obj_collection): + # Input cleanup, get an iterable of classes out of the argument + if isinstance(module_or_obj_collection, dict): + iterator = ((cname, obj) for cname, obj in module_or_obj_collection.items() if inspect.isclass(obj)) + elif isinstance(module_or_obj_collection, list): + iterator = ((obj.__name__, obj) for obj in module_or_obj_collection if inspect.isclass(obj)) + elif inspect.ismodule(module_or_obj_collection): + iterator = inspect.getmembers(module_or_obj_collection, inspect.isclass) + else: + raise TypeError('Unsupported type for CLI init: list/dist with classes in it or module supported.') + return iterator + + +def _make_bool_arg(arg): + return ('-%s' % arg.name, ), {'action': 'store_false' if arg.default is False else 'store_true'} + + +def _make_arg(arg, used_aliases: set): + arg_kwargs = { + 'type': arg.annotation if arg.annotation is not arg.empty else str + } + if arg.default is not arg.empty: + arg_kwargs['default'] = arg.default + names = ['--%s' % arg.name, ] + try: + letter = next(l for l in arg.name if l not in used_aliases) + names.insert(0, '-%s' % letter) + used_aliases.add(letter) + except StopIteration: + raise argparse.ArgumentError(None, 'Impossible to find an alias for argument %s.' % arg) + else: + names = (arg.name, ) + return names, arg_kwargs + + class ClassParser(argparse.ArgumentParser): def error(self, message): sys.stderr.write('%serror: %s%s\n' % (fg.red, message, rs.fg)) @@ -34,23 +69,11 @@ def __init__(self, module_or_obj_collection): self.subparsers = self.parser.add_subparsers() # For every controller class defined in the input module we add a subparser - for _, cls in self._load_object(module_or_obj_collection): + for _, cls in _load_object(module_or_obj_collection): # Only classes with callable_cls will be added as subparser (so to exclude utility classes) if getattr(cls, 'callable_cls', False): self._make_subparser(cls) - def _load_object(self, module_or_obj_collection): - # Input cleanup, get an iterable of classes out of the argument - if isinstance(module_or_obj_collection, dict): - iterator = ((cname, obj) for cname, obj in module_or_obj_collection.items() if inspect.isclass(obj)) - elif isinstance(module_or_obj_collection, list): - iterator = ((obj.__name__, obj) for obj in module_or_obj_collection if inspect.isclass(obj)) - elif inspect.ismodule(module_or_obj_collection): - iterator = inspect.getmembers(module_or_obj_collection, inspect.isclass) - else: - raise TypeError('Unsupported type for CLI init: list/dist with classes in it or module supported.') - return iterator - def _make_subparser(self, cls): # Help for this command from the class docstring and the _base method docstring help_str = '\n'.join(doc for doc in (inspect.getdoc(cls), inspect.getdoc(cls._base)) if doc) @@ -78,31 +101,11 @@ def _read_arguments(self, method_args_parser, fnc): for arg in inspect.signature(fnc).parameters.values(): arg_kwargs = {} if arg.annotation is bool: - names, arg_kwargs = self._make_bool_arg(arg) + names, arg_kwargs = _make_bool_arg(arg) else: - names, arg_kwargs = self._make_arg(arg, used_aliases) + names, arg_kwargs = _make_arg(arg, used_aliases) method_args_parser.add_argument(*names, **arg_kwargs) - def _make_bool_arg(self, arg): - return ('-%s' % arg.name, ), {'action': 'store_false' if arg.default is False else 'store_true'} - - def _make_arg(self, arg, used_aliases: set): - arg_kwargs = { - 'type': arg.annotation if arg.annotation is not arg.empty else str - } - if arg.default is not arg.empty: - arg_kwargs['default'] = arg.default - names = ['--%s' % arg.name, ] - try: - letter = next(l for l in arg.name if l not in used_aliases) - names.insert(0, '-%s' % letter) - used_aliases.add(letter) - except StopIteration: - raise argparse.ArgumentError(None, 'Impossible to find an alias for argument %s.' % arg) - else: - names = (arg.name, ) - return names, arg_kwargs - def run_cli(self, args=None): if args: args = map(str, args) @@ -112,6 +115,6 @@ def run_cli(self, args=None): raise argparse.ArgumentError(None, 'At least one argument needed.') return args.func(**{k: v for k, v in vars(args).items() if k != 'func'}) except argparse.ArgumentError as ex: - print('ERROR! Wrong command invocation: %s%s' % (fg.red, ex.message, rs.fg)) + print('%sERROR! Wrong command invocation: %s%s' % (fg.red, ex.message, rs.fg)) print('Please read the help:') self.parser.print_help()