From 013447bbe75dd397a710b21c5debd36689737925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Lebleu?= Date: Fri, 13 Nov 2015 11:53:31 +0100 Subject: [PATCH] [enh] Allow to define global abstract arguments in the cli --- moulinette/__init__.py | 13 ++++++++++--- moulinette/actionsmap.py | 27 ++++++++++++++++----------- moulinette/interfaces/__init__.py | 2 +- moulinette/interfaces/api.py | 2 +- moulinette/interfaces/cli.py | 19 +++++++++++++++++-- 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/moulinette/__init__.py b/moulinette/__init__.py index 9dd207b5..4b45a877 100755 --- a/moulinette/__init__.py +++ b/moulinette/__init__.py @@ -94,7 +94,8 @@ def api(namespaces, host='localhost', port=80, routes={}, 'use_cache': use_cache }) moulinette.run(host, port) -def cli(namespaces, args, print_json=False, print_plain=False, use_cache=True): +def cli(namespaces, args, print_json=False, print_plain=False, use_cache=True, + parser_kwargs={}): """Command line interface Execute an action with the moulinette from the CLI and print its @@ -107,12 +108,18 @@ def cli(namespaces, args, print_json=False, print_plain=False, use_cache=True): - print_plain -- True to print result as a script-usable string - use_cache -- False if it should parse the actions map file instead of using the cached one + - parser_kwargs -- A dict of arguments to pass to the parser + class at construction """ try: moulinette = init_interface('cli', - actionsmap={'namespaces': namespaces, - 'use_cache': use_cache}) + actionsmap={ + 'namespaces': namespaces, + 'use_cache': use_cache, + 'parser_kwargs': parser_kwargs, + }, + ) moulinette.run(args, print_json, print_plain) except MoulinetteError as e: import logging diff --git a/moulinette/actionsmap.py b/moulinette/actionsmap.py index 0bc843f8..0d696b36 100644 --- a/moulinette/actionsmap.py +++ b/moulinette/actionsmap.py @@ -342,17 +342,20 @@ class ActionsMap(object): all available namespaces. Keyword arguments: - - parser -- The BaseActionsMapParser derived class to use for - parsing the actions map + - parser_class -- The BaseActionsMapParser derived class to use + for parsing the actions map - namespaces -- The list of namespaces to use - use_cache -- False if it should parse the actions map file - instead of using the cached one. + instead of using the cached one + - parser_kwargs -- A dict of arguments to pass to the parser + class at construction """ - def __init__(self, parser, namespaces=[], use_cache=True): - if not issubclass(parser, BaseActionsMapParser): - raise ValueError("Invalid parser class '%s'" % parser.__name__) - self._parser_class = parser + def __init__(self, parser_class, namespaces=[], use_cache=True, + parser_kwargs={}): + if not issubclass(parser_class, BaseActionsMapParser): + raise ValueError("Invalid parser class '%s'" % parser_class.__name__) + self.parser_class = parser_class self.use_cache = use_cache if len(namespaces) == 0: @@ -380,8 +383,8 @@ class ActionsMap(object): m18n.load_namespace(n) # Generate parsers - self.extraparser = ExtraArgumentParser(parser.interface) - self._parser = self._construct_parser(actionsmaps) + self.extraparser = ExtraArgumentParser(parser_class.interface) + self._parser = self._construct_parser(actionsmaps, **parser_kwargs) @property def parser(self): @@ -515,13 +518,15 @@ class ActionsMap(object): ## Private methods - def _construct_parser(self, actionsmaps): + def _construct_parser(self, actionsmaps, **kwargs): """ Construct the parser with the actions map Keyword arguments: - actionsmaps -- A dict of multi-level dictionnary of categories/actions/arguments list for each namespaces + - **kwargs -- Additionnal arguments to pass at the parser + class instantiation Returns: An interface relevant's parser object @@ -551,7 +556,7 @@ class ActionsMap(object): parser.add_argument(*names, **argp) # Instantiate parser - top_parser = self._parser_class() + top_parser = self.parser_class(**kwargs) # Iterate over actions map namespaces for n, actionsmap in actionsmaps.items(): diff --git a/moulinette/interfaces/__init__.py b/moulinette/interfaces/__init__.py index 720b990a..422878c7 100644 --- a/moulinette/interfaces/__init__.py +++ b/moulinette/interfaces/__init__.py @@ -31,7 +31,7 @@ class BaseActionsMapParser(object): - parent -- A parent BaseActionsMapParser derived object """ - def __init__(self, parent=None): + def __init__(self, parent=None, **kwargs): if parent: self._o = parent else: diff --git a/moulinette/interfaces/api.py b/moulinette/interfaces/api.py index f2c1b9c8..bb7a9b53 100644 --- a/moulinette/interfaces/api.py +++ b/moulinette/interfaces/api.py @@ -476,7 +476,7 @@ class ActionsMapParser(BaseActionsMapParser): the arguments is represented by a ExtendedArgumentParser object. """ - def __init__(self, parent=None): + def __init__(self, parent=None, **kwargs): super(ActionsMapParser, self).__init__(parent) self._parsers = {} # dict({(method, path): _HTTPArgumentParser}) diff --git a/moulinette/interfaces/cli.py b/moulinette/interfaces/cli.py index 26f5476e..01650095 100644 --- a/moulinette/interfaces/cli.py +++ b/moulinette/interfaces/cli.py @@ -5,6 +5,7 @@ import sys import errno import getpass import locale +from argparse import SUPPRESS from moulinette.core import MoulinetteError from moulinette.interfaces import ( @@ -172,9 +173,12 @@ class ActionsMapParser(BaseActionsMapParser): Keyword arguments: - parser -- The ExtendedArgumentParser object to use - subparser_kwargs -- Arguments to pass to the sub-parser group + - top_parser -- An ArgumentParser object whose arguments should + be take into account but not parsed """ - def __init__(self, parent=None, parser=None, subparser_kwargs=None): + def __init__(self, parent=None, parser=None, subparser_kwargs=None, + top_parser=None, **kwargs): super(ActionsMapParser, self).__init__(parent) if subparser_kwargs is None: @@ -182,6 +186,14 @@ class ActionsMapParser(BaseActionsMapParser): self._parser = parser or ExtendedArgumentParser() self._subparsers = self._parser.add_subparsers(**subparser_kwargs) + self._global_parser = parent._global_parser if parent else None + + if top_parser: + # Append each top parser action to the global group + glob = self.add_global_parser() + for action in top_parser._actions: + action.dest = SUPPRESS + glob._add_action(action) ## Implement virtual properties @@ -198,7 +210,10 @@ class ActionsMapParser(BaseActionsMapParser): return [name] def add_global_parser(self, **kwargs): - return self._parser.add_mutually_exclusive_group() + if not self._global_parser: + self._global_parser = self._parser.add_argument_group( + "global arguments") + return self._global_parser def add_category_parser(self, name, category_help=None, **kwargs): """Add a parser for a category