From 25d52d7301064278d4159dbb967ffd2f7d9fd21c Mon Sep 17 00:00:00 2001 From: Eric Lin Date: Mon, 23 Apr 2018 15:19:54 -0400 Subject: [PATCH 1/3] Added support for using cmd2 application class methods as an argument completion provider. The default completion implementation in Cmd2 automatically passes self to AutoCompleter to be passed to the class method. --- cmd2/argparse_completer.py | 18 +++++++++++++++--- cmd2/cmd2.py | 2 +- examples/tab_autocompletion.py | 6 +++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index e87e9c04a..1b75411cf 100755 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -190,7 +190,8 @@ def __init__(self, token_start_index: int = 1, arg_choices: Dict[str, Union[List, Tuple, Callable]] = None, subcmd_args_lookup: dict = None, - tab_for_arg_help: bool = True): + tab_for_arg_help: bool = True, + cmd2_app=None): """ Create an AutoCompleter @@ -209,6 +210,7 @@ def __init__(self, self._arg_choices = arg_choices.copy() if arg_choices is not None else {} self._token_start_index = token_start_index self._tab_for_arg_help = tab_for_arg_help + self._cmd2_app = cmd2_app self._flags = [] # all flags in this command self._flags_without_args = [] # all flags that don't take arguments @@ -252,7 +254,8 @@ def __init__(self, subcmd_start = token_start_index + len(self._positional_actions) sub_completers[subcmd] = AutoCompleter(action.choices[subcmd], subcmd_start, arg_choices=subcmd_args, - subcmd_args_lookup=subcmd_lookup) + subcmd_args_lookup=subcmd_lookup, + cmd2_app=cmd2_app) sub_commands.append(subcmd) self._positional_completers[action.dest] = sub_completers self._arg_choices[action.dest] = sub_commands @@ -492,7 +495,16 @@ def _resolve_choices_for_arg(self, action: argparse.Action, used_values=()) -> L args = self._arg_choices[action.dest] if callable(args): - args = args() + try: + if self._cmd2_app is not None: + try: + args = args(self._cmd2_app) + except TypeError: + args = args() + else: + args = args() + except TypeError: + return [] try: iter(args) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 288a506b0..820e94419 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1838,7 +1838,7 @@ def complete(self, text, state): def _autocomplete_default(self, text: str, line: str, begidx: int, endidx: int, argparser: argparse.ArgumentParser) -> List[str]: """Default completion function for argparse commands.""" - completer = AutoCompleter(argparser) + completer = AutoCompleter(argparser, cmd2_app=self) tokens, _ = self.tokens_for_completion(line, begidx, endidx) results = completer.complete_command(tokens, text, line, begidx, endidx) diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py index 17c8391dd..a1a8daeee 100755 --- a/examples/tab_autocompletion.py +++ b/examples/tab_autocompletion.py @@ -95,6 +95,10 @@ def __init__(self): }, } + def instance_query_actors(self) -> List[str]: + """Simulating a function that queries and returns a completion values""" + return actors + # This demonstrates a number of customizations of the AutoCompleter version of ArgumentParser # - The help output will separately group required vs optional flags # - The help output for arguments with multiple flags or with append=True is more concise @@ -222,7 +226,7 @@ def _do_vid_media_shows(self, args) -> None: # tag the action objects with completion providers. This can be a collection or a callable setattr(director_action, argparse_completer.ACTION_ARG_CHOICES, static_list_directors) - setattr(actor_action, argparse_completer.ACTION_ARG_CHOICES, query_actors) + setattr(actor_action, argparse_completer.ACTION_ARG_CHOICES, instance_query_actors) vid_movies_delete_parser = vid_movies_commands_subparsers.add_parser('delete') From bd04bf2ca91d3d07747fd99d65343fbac0119c89 Mon Sep 17 00:00:00 2001 From: Eric Lin Date: Mon, 23 Apr 2018 15:21:26 -0400 Subject: [PATCH 2/3] Changed initial value to a boolean. --- cmd2/cmd2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 820e94419..8d8a5b076 100755 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2070,7 +2070,7 @@ def onecmd_plus_hooks(self, line): :param line: str - line of text read from input :return: bool - True if cmdloop() should exit, False otherwise """ - stop = 0 + stop = False try: statement = self._complete_statement(line) (stop, statement) = self.postparsing_precmd(statement) From de58200c9292cb23c69c7de416a31fd7ff206470 Mon Sep 17 00:00:00 2001 From: Eric Lin Date: Mon, 23 Apr 2018 15:25:32 -0400 Subject: [PATCH 3/3] Updated constructor arguments --- cmd2/argparse_completer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index 1b75411cf..03f2d965d 100755 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -200,6 +200,8 @@ def __init__(self, :param arg_choices: dictionary mapping from argparse argument 'dest' name to list of choices :param subcmd_args_lookup: mapping a sub-command group name to a tuple to fill the child\ AutoCompleter's arg_choices and subcmd_args_lookup parameters + :param tab_for_arg_help: Enable of disable argument help when there's no completion result + :param cmd2_app: reference to the Cmd2 application. Enables argparse argument completion with class methods """ if not subcmd_args_lookup: subcmd_args_lookup = {}