summaryrefslogtreecommitdiff
path: root/cmd2/argparse_completer.py
diff options
context:
space:
mode:
Diffstat (limited to 'cmd2/argparse_completer.py')
-rw-r--r--cmd2/argparse_completer.py128
1 files changed, 14 insertions, 114 deletions
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index 74853fa8..c5a4c004 100644
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -61,115 +61,14 @@ How to supply completion choice lists or functions for sub-commands:
import argparse
import os
from argparse import SUPPRESS
-from typing import Any, Callable, Iterable, Dict, List, Optional, Tuple, Union
+from typing import Callable, Dict, List, Tuple, Union
from . import utils
from .ansi import ansi_safe_wcswidth
-from .argparse_custom import _RangeAction
+from .argparse_custom import ATTR_SUPPRESS_TAB_HINT, ATTR_DESCRIPTIVE_COMPLETION_HEADER, ATTR_NARGS_RANGE
+from .argparse_custom import ChoicesCallable, ATTR_CHOICES_CALLABLE
from .rl_utils import rl_force_redisplay
-# Argparse argument attribute that stores an ArgChoicesCallable
-ARG_CHOICES_CALLABLE = 'choices_callable'
-
-# Argparse argument attribute that suppresses tab-completion hints
-ARG_SUPPRESS_HINT = 'suppress_hint'
-
-# Argparse argument attribute that prints descriptive header when using CompletionItems
-ARG_DESCRIPTIVE_COMPLETION_HEADER = 'desc_header'
-
-
-class ArgChoicesCallable:
- """
- Enables using a callable as the choices provider for an argparse argument.
- While argparse has the built-in choices attribute, it is limited to an iterable.
- """
- def __init__(self, is_method: bool, is_completer: bool, to_call: Callable):
- """
- Initializer
- :param is_method: True if to_call is an instance method of a cmd2 app. False if it is a function.
- :param is_completer: True if to_call is a tab completion routine which expects
- the args: text, line, begidx, endidx
- :param to_call: the callable object that will be called to provide choices for the argument
- """
- self.is_method = is_method
- self.is_completer = is_completer
- self.to_call = to_call
-
-
-# Save original _ActionsContainer.add_argument's value because we will replace it with our wrapper
-orig_actions_container_add_argument = argparse._ActionsContainer.add_argument
-
-
-def add_argument_wrapper(self, *args,
- choices_function: Optional[Callable[[], Iterable[Any]]] = None,
- choices_method: Optional[Callable[[Any], Iterable[Any]]] = None,
- completer_function: Optional[Callable[[str, str, int, int], List[str]]] = None,
- completer_method: Optional[Callable[[Any, str, str, int, int], List[str]]] = None,
- suppress_hint: bool = False,
- description_header: Optional[str] = None,
- **kwargs) -> argparse.Action:
- """
- This is a wrapper around _ActionsContainer.add_argument() that supports more settings needed by AutoCompleter
-
- # Args from original function
- :param self: instance of the _ActionsContainer being added to
- :param args: arguments expected by argparse._ActionsContainer.add_argument
-
- # Added args used by AutoCompleter
- :param choices_function: function that provides choices for this argument
- :param choices_method: cmd2-app method that provides choices for this argument
- :param completer_function: tab-completion function that provides choices for this argument
- :param completer_method: cmd2-app tab-completion method that provides choices for this argument
- :param suppress_hint: when AutoCompleter has no choices to show during tab completion, it displays the current
- argument's help text as a hint. Set this to True to suppress the hint. Defaults to False.
- :param description_header: if the provided choices are CompletionItems, then this header will display
- during tab completion. Defaults to None.
-
- # Args from original function
- :param kwargs: keyword-arguments recognized by argparse._ActionsContainer.add_argument
-
- Note: You can only use 1 of the following in your argument:
- choices, choices_function, choices_method, completer_function, completer_method
-
- See the header of this file for more information
-
- :return: the created argument action
- """
- # Call the original add_argument function
- new_arg = orig_actions_container_add_argument(self, *args, **kwargs)
-
- # Verify consistent use of arguments
- choice_params = [new_arg.choices, choices_function, choices_method, completer_function, completer_method]
- num_set = len(choice_params) - choice_params.count(None)
-
- if num_set > 1:
- err_msg = ("Only one of the following may be used in an argparser argument at a time:\n"
- "choices, choices_function, choices_method, completer_function, completer_method")
- raise (ValueError(err_msg))
-
- # Set the custom attributes used by AutoCompleter
- if choices_function:
- setattr(new_arg, ARG_CHOICES_CALLABLE,
- ArgChoicesCallable(is_method=False, is_completer=False, to_call=choices_function))
- elif choices_method:
- setattr(new_arg, ARG_CHOICES_CALLABLE,
- ArgChoicesCallable(is_method=True, is_completer=False, to_call=choices_method))
- elif completer_function:
- setattr(new_arg, ARG_CHOICES_CALLABLE,
- ArgChoicesCallable(is_method=False, is_completer=True, to_call=completer_function))
- elif completer_method:
- setattr(new_arg, ARG_CHOICES_CALLABLE,
- ArgChoicesCallable(is_method=True, is_completer=True, to_call=completer_method))
-
- setattr(new_arg, ARG_SUPPRESS_HINT, suppress_hint)
- setattr(new_arg, ARG_DESCRIPTIVE_COMPLETION_HEADER, description_header)
-
- return new_arg
-
-
-# Overwrite _ActionsContainer.add_argument with our wrapper
-argparse._ActionsContainer.add_argument = add_argument_wrapper
-
class CompletionItem(str):
"""
@@ -301,8 +200,8 @@ class AutoCompleter(object):
self._arg_choices[action.dest] = action.choices
# otherwise check if a callable provides the choices for this argument
- elif hasattr(action, ARG_CHOICES_CALLABLE):
- arg_choice_callable = getattr(action, ARG_CHOICES_CALLABLE)
+ elif hasattr(action, ATTR_CHOICES_CALLABLE):
+ arg_choice_callable = getattr(action, ATTR_CHOICES_CALLABLE)
self._arg_choices[action.dest] = arg_choice_callable
# if the parameter is flag based, it will have option_strings
@@ -411,9 +310,10 @@ class AutoCompleter(object):
def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._ArgumentState) -> None:
"""Process the current argparse Action and initialize the ArgumentState object used
to track what arguments we have processed for this action"""
- if isinstance(action, _RangeAction):
- arg_state.min = action.nargs_min
- arg_state.max = action.nargs_max
+ nargs_range = getattr(action, ATTR_NARGS_RANGE, None)
+ if nargs_range is not None:
+ arg_state.min = nargs_range[0]
+ arg_state.max = nargs_range[1]
arg_state.variable = True
if arg_state.min is None or arg_state.max is None:
if action.nargs is None:
@@ -624,7 +524,7 @@ class AutoCompleter(object):
completions_with_desc.append(entry)
try:
- desc_header = getattr(action, ARG_DESCRIPTIVE_COMPLETION_HEADER)
+ desc_header = getattr(action, ATTR_DESCRIPTIVE_COMPLETION_HEADER)
except AttributeError:
desc_header = 'Description'
header = '\n{: <{token_width}}{}'.format(action.dest.upper(), desc_header, token_width=token_width + 2)
@@ -669,7 +569,7 @@ class AutoCompleter(object):
arg_choices = self._arg_choices[arg.dest]
# Check if the argument uses a specific tab completion function to provide its choices
- if isinstance(arg_choices, ArgChoicesCallable) and arg_choices.is_completer:
+ if isinstance(arg_choices, ChoicesCallable) and arg_choices.is_completer:
if arg_choices.is_method:
return arg_choices.to_call(self._cmd2_app, text, line, begidx, endidx)
else:
@@ -687,8 +587,8 @@ class AutoCompleter(object):
if arg.dest in self._arg_choices:
arg_choices = self._arg_choices[arg.dest]
- # Check if arg_choices is an ArgChoicesCallable that generates a choice list
- if isinstance(arg_choices, ArgChoicesCallable):
+ # Check if arg_choices is a ChoicesCallable that generates a choice list
+ if isinstance(arg_choices, ChoicesCallable):
if arg_choices.is_completer:
# Tab completion routines are handled in other functions
return []
@@ -717,7 +617,7 @@ class AutoCompleter(object):
return
# is parameter hinting disabled for this parameter?
- suppress_hint = getattr(action, ARG_SUPPRESS_HINT, False)
+ suppress_hint = getattr(action, ATTR_SUPPRESS_TAB_HINT, False)
if suppress_hint:
return