summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2/argparse_completer.py (renamed from cmd2/AutoCompleter.py)229
-rw-r--r--cmd2/rl_utils.py4
-rwxr-xr-xexamples/tab_autocompletion.py24
-rw-r--r--tests/test_acargparse.py11
-rw-r--r--tests/test_autocompletion.py13
-rw-r--r--tests/test_completion.py23
6 files changed, 156 insertions, 148 deletions
diff --git a/cmd2/AutoCompleter.py b/cmd2/argparse_completer.py
index a8d25895..03cc6483 100755
--- a/cmd2/AutoCompleter.py
+++ b/cmd2/argparse_completer.py
@@ -1,14 +1,71 @@
# coding=utf-8
+"""
+AutoCompleter interprets the argparse.ArgumentParser internals to automatically
+generate the completion options for each argument.
+
+How to supply completion options for each argument:
+ argparse Choices
+ - pass a list of values to the choices parameter of an argparse argument.
+ ex: parser.add_argument('-o', '--options', dest='options', choices=['An Option', 'SomeOtherOption'])
+
+ arg_choices dictionary lookup
+ arg_choices is a dict() mapping from argument name to one of 3 possible values:
+ ex:
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-o', '--options', dest='options')
+ choices = {}
+ mycompleter = AutoCompleter(parser, completer, 1, choices)
+
+ - static list - provide a static list for each argument name
+ ex:
+ choices['options'] = ['An Option', 'SomeOtherOption']
+
+ - choices function - provide a function that returns a list for each argument name
+ ex:
+ def generate_choices():
+ return ['An Option', 'SomeOtherOption']
+ choices['options'] = generate_choices
+
+ - custom completer function - provide a completer function that will return the list
+ of completion arguments
+ ex 1:
+ def my_completer(text: str, line: str, begidx: int, endidx:int):
+ my_choices = [...]
+ return my_choices
+ choices['options'] = (my_completer)
+ ex 2:
+ def my_completer(text: str, line: str, begidx: int, endidx:int, extra_param: str, another: int):
+ my_choices = [...]
+ return my_choices
+ completer_params = {'extra_param': 'my extra', 'another': 5}
+ choices['options'] = (my_completer, completer_params)
+
+How to supply completion choice lists or functions for sub-commands:
+ subcmd_args_lookup is used to supply a unique pair of arg_choices and subcmd_args_lookup
+ for each sub-command in an argparser subparser group.
+ This requires your subparser group to be named with the dest parameter
+ ex:
+ parser = ArgumentParser()
+ subparsers = parser.add_subparsers(title='Actions', dest='action')
+
+ subcmd_args_lookup maps a named subparser group to a subcommand group dictionary
+ The subcommand group dictionary maps subcommand names to tuple(arg_choices, subcmd_args_lookup)
+
+ For more details of this more complex approach see tab_autocompletion.py in the examples
+"""
+
import argparse
-import re as _re
+from colorama import Fore
import sys
-from argparse import OPTIONAL, ZERO_OR_MORE, ONE_OR_MORE, REMAINDER, PARSER, ArgumentError, _
+from typing import List, Dict, Tuple, Callable, Union
+
+
+# imports copied from argparse to support our customized argparse functions
+from argparse import ZERO_OR_MORE, ONE_OR_MORE, ArgumentError, _
+import re as _re
+
+
from .rl_utils import rl_force_redisplay
-try:
- from typing import List, Dict, Tuple, Callable, Union
-except:
- pass
-from colorama import Fore
class _RangeAction(object):
@@ -128,57 +185,7 @@ class AutoCompleter(object):
subcmd_args_lookup: dict = None,
tab_for_arg_help: bool = True):
"""
- AutoCompleter interprets the argparse.ArgumentParser internals to automatically
- generate the completion options for each argument.
-
- How to supply completion options for each argument:
- argparse Choices
- - pass a list of values to the choices parameter of an argparse argument.
- ex: parser.add_argument('-o', '--options', dest='options', choices=['An Option', 'SomeOtherOption'])
-
- arg_choices dictionary lookup
- arg_choices is a dict() mapping from argument name to one of 3 possible values:
- ex:
- parser = argparse.ArgumentParser()
- parser.add_argument('-o', '--options', dest='options')
- choices = {}
- mycompleter = AutoCompleter(parser, completer, 1, choices)
-
- - static list - provide a static list for each argument name
- ex:
- choices['options'] = ['An Option', 'SomeOtherOption']
-
- - choices function - provide a function that returns a list for each argument name
- ex:
- def generate_choices():
- return ['An Option', 'SomeOtherOption']
- choices['options'] = generate_choices
-
- - custom completer function - provide a completer function that will return the list
- of completion arguments
- ex 1:
- def my_completer(text: str, line: str, begidx: int, endidx:int):
- my_choices = [...]
- return my_choices
- choices['options'] = (my_completer)
- ex 2:
- def my_completer(text: str, line: str, begidx: int, endidx:int, extra_param: str, another: int):
- my_choices = [...]
- return my_choices
- completer_params = {'extra_param': 'my extra', 'another': 5}
- choices['options'] = (my_completer, completer_params)
-
- How to supply completion choice lists or functions for sub-commands:
- subcmd_args_lookup is used to supply a unique pair of arg_choices and subcmd_args_lookup
- for each sub-command in an argparser subparser group.
- This requires your subparser group to be named with the dest parameter
- ex:
- parser = ArgumentParser()
- subparsers = parser.add_subparsers(title='Actions', dest='action')
-
- subcmd_args_lookup maps a named subparser group to a subcommand group dictionary
- The subcommand group dictionary maps subcommand names to tuple(arg_choices, subcmd_args_lookup)
-
+ Create an AutoCompleter
:param parser: ArgumentParser instance
:param token_start_index: index of the token to start parsing at
@@ -200,8 +207,9 @@ class AutoCompleter(object):
self._flags_without_args = [] # all flags that don't take arguments
self._flag_to_action = {} # maps flags to the argparse action object
self._positional_actions = [] # argument names for positional arguments (by position index)
- self._positional_completers = {} # maps action name to sub-command autocompleter:
- # action_name -> dict(sub_command -> completer)
+ # maps action name to sub-command autocompleter:
+ # action_name -> dict(sub_command -> completer)
+ self._positional_completers = {}
# Start digging through the argparse structures.
# _actions is the top level container of parameter definitions
@@ -225,10 +233,10 @@ class AutoCompleter(object):
sub_completers = {}
sub_commands = []
args_for_action = subcmd_args_lookup[action.dest]\
- if action.dest in subcmd_args_lookup.keys() else {}
+ if action.dest in subcmd_args_lookup else {}
for subcmd in action.choices:
(subcmd_args, subcmd_lookup) = args_for_action[subcmd] if \
- subcmd in args_for_action.keys() else \
+ subcmd in args_for_action else \
(arg_choices, subcmd_args_lookup) if forward_arg_choices else ({}, {})
subcmd_start = token_start_index + len(self._positional_actions)
sub_completers[subcmd] = AutoCompleter(action.choices[subcmd], subcmd_start,
@@ -258,7 +266,7 @@ class AutoCompleter(object):
"""Consuming token as a flag argument"""
# we're consuming flag arguments
# if this is not empty and is not another potential flag, count towards flag arguments
- if len(token) > 0 and not token[0] in self._parser.prefix_chars and flag_action is not None:
+ if token and token[0] not in self._parser.prefix_chars and flag_action is not None:
flag_arg.count += 1
# does this complete a option item for the flag
@@ -298,10 +306,10 @@ class AutoCompleter(object):
flag_action = None
# does the token fully match a known flag?
- if token in self._flag_to_action.keys():
+ if token in self._flag_to_action:
flag_action = self._flag_to_action[token]
elif hasattr(self._parser, 'allow_abbrev') and self._parser.allow_abbrev:
- candidates_flags = [flag for flag in self._flag_to_action.keys() if flag.startswith(token)]
+ candidates_flags = [flag for flag in self._flag_to_action if flag.startswith(token)]
if len(candidates_flags) == 1:
flag_action = self._flag_to_action[candidates_flags[0]]
@@ -338,9 +346,9 @@ class AutoCompleter(object):
if pos_index < len(self._positional_actions):
action = self._positional_actions[pos_index]
pos_name = action.dest
- if pos_name in self._positional_completers.keys():
+ if pos_name in self._positional_completers:
sub_completers = self._positional_completers[pos_name]
- if token in sub_completers.keys():
+ if token in sub_completers:
return sub_completers[token].complete_command(tokens, text, line,
begidx, endidx)
pos_action = action
@@ -372,7 +380,7 @@ class AutoCompleter(object):
# current_items = []
if flag_action is not None:
consumed = consumed_arg_values[flag_action.dest]\
- if flag_action.dest in consumed_arg_values.keys() else []
+ if flag_action.dest in consumed_arg_values else []
# current_items.extend(self._resolve_choices_for_arg(flag_action, consumed))
completion_results = self._complete_for_arg(flag_action, text, line, begidx, endidx, consumed)
if not completion_results:
@@ -382,7 +390,7 @@ class AutoCompleter(object):
else:
if pos_action is not None:
pos_name = pos_action.dest
- consumed = consumed_arg_values[pos_name] if pos_name in consumed_arg_values.keys() else []
+ consumed = consumed_arg_values[pos_name] if pos_name in consumed_arg_values else []
completion_results = self._complete_for_arg(pos_action, text, line, begidx, endidx, consumed)
if not completion_results:
self._print_action_help(pos_action)
@@ -420,8 +428,8 @@ class AutoCompleter(object):
line: str,
begidx: int,
endidx: int,
- used_values=list()) -> List[str]:
- if action.dest in self._arg_choices.keys():
+ used_values=()) -> List[str]:
+ if action.dest in self._arg_choices:
arg_choices = self._arg_choices[action.dest]
if isinstance(arg_choices, tuple) and len(arg_choices) > 0 and callable(arg_choices[0]):
@@ -447,8 +455,8 @@ class AutoCompleter(object):
return []
- def _resolve_choices_for_arg(self, action: argparse.Action, used_values=list()) -> List[str]:
- if action.dest in self._arg_choices.keys():
+ def _resolve_choices_for_arg(self, action: argparse.Action, used_values=()) -> List[str]:
+ if action.dest in self._arg_choices:
args = self._arg_choices[action.dest]
if callable(args):
args = args()
@@ -508,6 +516,14 @@ class AutoCompleter(object):
return [cur_match for cur_match in match_against if cur_match.startswith(text)]
+###############################################################################
+# Unless otherwise noted, everything below this point are copied from Python's
+# argparse implementation with minor tweaks to adjust output.
+# Changes are noted if it's buried in a block of copied code. Otherwise the
+# function will check for a special case and fall back to the parent function
+###############################################################################
+
+
class ACHelpFormatter(argparse.HelpFormatter):
"""Custom help formatter to configure ordering of help text"""
@@ -529,8 +545,9 @@ class ACHelpFormatter(argparse.HelpFormatter):
# split optionals from positionals
optionals = []
- required_options = []
positionals = []
+ # Begin cmd2 customization (separates required and optional, applies to all changes in this function)
+ required_options = []
for action in actions:
if action.option_strings:
if action.required:
@@ -539,6 +556,7 @@ class ACHelpFormatter(argparse.HelpFormatter):
optionals.append(action)
else:
positionals.append(action)
+ # End cmd2 customization
# build full usage string
format = self._format_actions_usage
@@ -549,6 +567,8 @@ class ACHelpFormatter(argparse.HelpFormatter):
text_width = self._width - self._current_indent
if len(prefix) + len(usage) > text_width:
+ # Begin cmd2 customization
+
# break usage into wrappable parts
part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
opt_usage = format(optionals, groups)
@@ -561,6 +581,8 @@ class ACHelpFormatter(argparse.HelpFormatter):
assert ' '.join(pos_parts) == pos_usage
assert ' '.join(req_parts) == req_usage
+ # End cmd2 customization
+
# helper for wrapping lines
def get_lines(parts, indent, prefix=None):
lines = []
@@ -585,6 +607,7 @@ class ACHelpFormatter(argparse.HelpFormatter):
# if prog is short, follow it with optionals or positionals
if len(prefix) + len(prog) <= 0.75 * text_width:
indent = ' ' * (len(prefix) + len(prog) + 1)
+ # Begin cmd2 customization
if opt_parts:
lines = get_lines([prog] + pos_parts, indent, prefix)
lines.extend(get_lines(req_parts, indent))
@@ -594,10 +617,12 @@ class ACHelpFormatter(argparse.HelpFormatter):
lines.extend(get_lines(req_parts, indent))
else:
lines = [prog]
+ # End cmd2 customization
# if prog is long, put it on its own line
else:
indent = ' ' * len(prefix)
+ # Begin cmd2 customization
parts = pos_parts + req_parts + opt_parts
lines = get_lines(parts, indent)
if len(lines) > 1:
@@ -605,6 +630,7 @@ class ACHelpFormatter(argparse.HelpFormatter):
lines.extend(get_lines(pos_parts, indent))
lines.extend(get_lines(req_parts, indent))
lines.extend(get_lines(opt_parts, indent))
+ # End cmd2 customization
lines = [prog] + lines
# join lines into usage
@@ -628,46 +654,24 @@ class ACHelpFormatter(argparse.HelpFormatter):
parts.extend(action.option_strings)
return ', '.join(parts)
+ # Begin cmd2 customization (less verbose)
# if the Optional takes a value, format is:
- # -s ARGS, --long ARGS
+ # -s, --long ARGS
else:
default = self._get_default_metavar_for_optional(action)
args_string = self._format_args(action, default)
- # for option_string in action.option_strings:
- # parts.append('%s %s' % (option_string, args_string))
-
return ', '.join(action.option_strings) + ' ' + args_string
-
- def _format_args(self, action, default_metavar):
- get_metavar = self._metavar_formatter(action, default_metavar)
- if isinstance(action, _RangeAction) and \
- action.nargs_min is not None and action.nargs_max is not None:
- result = '{}{{{}..{}}}'.format('%s' % get_metavar(1), action.nargs_min, action.nargs_max)
-
- elif action.nargs is None:
- result = '%s' % get_metavar(1)
- elif action.nargs == OPTIONAL:
- result = '[%s]' % get_metavar(1)
- elif action.nargs == ZERO_OR_MORE:
- result = '[%s [...]]' % get_metavar(1)
- elif action.nargs == ONE_OR_MORE:
- result = '%s [...]' % get_metavar(1)
- elif action.nargs == REMAINDER:
- result = '...'
- elif action.nargs == PARSER:
- result = '%s ...' % get_metavar(1)
- else:
- formats = ['%s' for _ in range(action.nargs)]
- result = ' '.join(formats) % get_metavar(action.nargs)
- return result
+ # End cmd2 customization
def _metavar_formatter(self, action, default_metavar):
if action.metavar is not None:
result = action.metavar
elif action.choices is not None:
choice_strs = [str(choice) for choice in action.choices]
+ # Begin cmd2 customization (added space after comma)
result = '{%s}' % ', '.join(choice_strs)
+ # End cmd2 customization
else:
result = default_metavar
@@ -678,6 +682,21 @@ class ACHelpFormatter(argparse.HelpFormatter):
return (result, ) * tuple_size
return format
+ def _format_args(self, action, default_metavar):
+ get_metavar = self._metavar_formatter(action, default_metavar)
+ # Begin cmd2 customization (less verbose)
+ if isinstance(action, _RangeAction) and \
+ action.nargs_min is not None and action.nargs_max is not None:
+ result = '{}{{{}..{}}}'.format('%s' % get_metavar(1), action.nargs_min, action.nargs_max)
+ elif action.nargs == ZERO_OR_MORE:
+ result = '[%s [...]]' % get_metavar(1)
+ elif action.nargs == ONE_OR_MORE:
+ result = '%s [...]' % get_metavar(1)
+ # End cmd2 customization
+ else:
+ result = super()._format_args(action, default_metavar)
+ return result
+
def _split_lines(self, text, width):
return text.splitlines()
@@ -694,15 +713,17 @@ class ACArgumentParser(argparse.ArgumentParser):
self._custom_error_message = ''
+ # Begin cmd2 customization
def set_custom_message(self, custom_message=''):
"""
Allows an error message override to the error() function, useful when forcing a
re-parse of arguments with newly required parameters
"""
self._custom_error_message = custom_message
+ # End cmd2 customization
def error(self, message):
- """Custom error override."""
+ """Custom error override. Allows application to control the error being displayed by argparse"""
if len(self._custom_error_message) > 0:
message = self._custom_error_message
self._custom_error_message = ''
@@ -733,6 +754,8 @@ class ACArgumentParser(argparse.ArgumentParser):
# description
formatter.add_text(self.description)
+ # Begin cmd2 customization (separate required and optional arguments)
+
# positionals, optionals and user-defined groups
for action_group in self._action_groups:
if action_group.title == 'optional arguments':
@@ -762,6 +785,8 @@ class ACArgumentParser(argparse.ArgumentParser):
formatter.add_arguments(action_group._group_actions)
formatter.end_section()
+ # End cmd2 customization
+
# epilog
formatter.add_text(self.epilog)
diff --git a/cmd2/rl_utils.py b/cmd2/rl_utils.py
index 1dc83d15..c00a5784 100644
--- a/cmd2/rl_utils.py
+++ b/cmd2/rl_utils.py
@@ -22,13 +22,15 @@ except ImportError:
pass
-# Check what implementation of readline we are using
class RlType(Enum):
+ """Readline library types we recognize"""
GNU = 1
PYREADLINE = 2
NONE = 3
+# Check what implementation of readline we are using
+
rl_type = RlType.NONE
# The order of this check matters since importing pyreadline will also show readline in the modules list
diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py
index 103706ac..448268d0 100755
--- a/examples/tab_autocompletion.py
+++ b/examples/tab_autocompletion.py
@@ -7,7 +7,7 @@ import itertools
from typing import List
import cmd2
-from cmd2 import with_argparser, with_category, AutoCompleter
+from cmd2 import with_argparser, with_category, argparse_completer
class TabCompleteExample(cmd2.Cmd):
@@ -91,7 +91,7 @@ class TabCompleteExample(cmd2.Cmd):
# - The help output for arguments with multiple flags or with append=True is more concise
# - ACArgumentParser adds the ability to specify ranges of argument counts in 'nargs'
- suggest_parser = AutoCompleter.ACArgumentParser()
+ suggest_parser = argparse_completer.ACArgumentParser()
suggest_parser.add_argument('-t', '--type', choices=['movie', 'show'], required=True)
suggest_parser.add_argument('-d', '--duration', nargs=(1, 2), action='append',
@@ -113,7 +113,7 @@ class TabCompleteExample(cmd2.Cmd):
def complete_suggest(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
""" Adds tab completion to media"""
- completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser, 1)
+ completer = argparse_completer.AutoCompleter(TabCompleteExample.suggest_parser, 1)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
@@ -125,7 +125,7 @@ class TabCompleteExample(cmd2.Cmd):
suggest_parser_hybrid = argparse.ArgumentParser()
# This registers the custom narg range handling
- AutoCompleter.register_custom_actions(suggest_parser_hybrid)
+ argparse_completer.register_custom_actions(suggest_parser_hybrid)
suggest_parser_hybrid.add_argument('-t', '--type', choices=['movie', 'show'], required=True)
suggest_parser_hybrid.add_argument('-d', '--duration', nargs=(1, 2), action='append',
@@ -141,7 +141,7 @@ class TabCompleteExample(cmd2.Cmd):
def complete_hybrid_suggest(self, text, line, begidx, endidx):
""" Adds tab completion to media"""
- completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_hybrid)
+ completer = argparse_completer.AutoCompleter(TabCompleteExample.suggest_parser_hybrid)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
@@ -168,7 +168,7 @@ class TabCompleteExample(cmd2.Cmd):
def complete_orig_suggest(self, text, line, begidx, endidx) -> List[str]:
""" Adds tab completion to media"""
- completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_orig)
+ completer = argparse_completer.AutoCompleter(TabCompleteExample.suggest_parser_orig)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
@@ -211,7 +211,7 @@ class TabCompleteExample(cmd2.Cmd):
print()
- media_parser = AutoCompleter.ACArgumentParser(prog='media')
+ media_parser = argparse_completer.ACArgumentParser(prog='media')
media_types_subparsers = media_parser.add_subparsers(title='Media Types', dest='type')
@@ -264,7 +264,7 @@ class TabCompleteExample(cmd2.Cmd):
choices = {'actor': self.query_actors, # function
'director': TabCompleteExample.static_list_directors # static list
}
- completer = AutoCompleter.AutoCompleter(TabCompleteExample.media_parser, arg_choices=choices)
+ completer = argparse_completer.AutoCompleter(TabCompleteExample.media_parser, arg_choices=choices)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
@@ -293,11 +293,11 @@ class TabCompleteExample(cmd2.Cmd):
def _query_movie_user_library(self):
return TabCompleteExample.USER_MOVIE_LIBRARY
- def _filter_library(self, text, line, begidx, endidx, full, exclude=[]):
+ def _filter_library(self, text, line, begidx, endidx, full, exclude=()):
candidates = list(set(full).difference(set(exclude)))
return [entry for entry in candidates if entry.startswith(text)]
- library_parser = AutoCompleter.ACArgumentParser(prog='library')
+ library_parser = argparse_completer.ACArgumentParser(prog='library')
library_subcommands = library_parser.add_subparsers(title='Media Types', dest='type')
@@ -410,8 +410,8 @@ class TabCompleteExample(cmd2.Cmd):
# under the type sub-parser group, there are 2 sub-parsers: 'movie', 'show'
library_subcommand_groups = {'type': library_type_params}
- completer = AutoCompleter.AutoCompleter(TabCompleteExample.library_parser,
- subcmd_args_lookup=library_subcommand_groups)
+ completer = argparse_completer.AutoCompleter(TabCompleteExample.library_parser,
+ subcmd_args_lookup=library_subcommand_groups)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
diff --git a/tests/test_acargparse.py b/tests/test_acargparse.py
index 6f40bd42..be3e8b97 100644
--- a/tests/test_acargparse.py
+++ b/tests/test_acargparse.py
@@ -1,14 +1,11 @@
"""
-Unit/functional testing for readline tab-completion functions in the cmd2.py module.
+Unit/functional testing for argparse customizations in cmd2
-These are primarily tests related to readline completer functions which handle tab-completion of cmd2/cmd commands,
-file system paths, and shell commands.
-
-Copyright 2017 Todd Leonhardt <todd.leonhardt@gmail.com>
+Copyright 2018 Eric Lin <anselor@gmail.com>
Released under MIT license, see LICENSE file
"""
import pytest
-from cmd2.AutoCompleter import ACArgumentParser
+from cmd2.argparse_completer import ACArgumentParser
def test_acarg_narg_empty_tuple():
@@ -54,5 +51,3 @@ def test_acarg_narg_tuple_zero_base():
def test_acarg_narg_tuple_zero_to_one():
parser = ACArgumentParser(prog='test')
parser.add_argument('tuple', nargs=(0, 1))
-
-
diff --git a/tests/test_autocompletion.py b/tests/test_autocompletion.py
index 5f28086a..e68bc104 100644
--- a/tests/test_autocompletion.py
+++ b/tests/test_autocompletion.py
@@ -1,10 +1,7 @@
"""
-Unit/functional testing for readline tab-completion functions in the cmd2.py module.
+Unit/functional testing for argparse completer in cmd2
-These are primarily tests related to readline completer functions which handle tab-completion of cmd2/cmd commands,
-file system paths, and shell commands.
-
-Copyright 2017 Todd Leonhardt <todd.leonhardt@gmail.com>
+Copyright 2018 Eric Lin <anselor@gmail.com>
Released under MIT license, see LICENSE file
"""
import pytest
@@ -257,9 +254,3 @@ def test_autcomp_custom_func_list_and_dict_arg(cmd2_app):
first_match = complete_tester(text, line, begidx, endidx, cmd2_app)
assert first_match is not None and \
cmd2_app.completion_matches == ['S01E02', 'S01E03', 'S02E01', 'S02E03']
-
-
-
-
-
-
diff --git a/tests/test_completion.py b/tests/test_completion.py
index 2902f55e..a01d1166 100644
--- a/tests/test_completion.py
+++ b/tests/test_completion.py
@@ -863,6 +863,7 @@ def test_subcommand_tab_completion(sc_app):
# It is at end of line, so extra space is present
assert first_match is not None and sc_app.completion_matches == ['Football ']
+
def test_subcommand_tab_completion_with_no_completer(sc_app):
# This tests what happens when a subcommand has no completer
# In this case, the foo subcommand has no completer defined
@@ -874,6 +875,7 @@ def test_subcommand_tab_completion_with_no_completer(sc_app):
first_match = complete_tester(text, line, begidx, endidx, sc_app)
assert first_match is None
+
def test_subcommand_tab_completion_space_in_text(sc_app):
text = 'B'
line = 'base sport "Space {}'.format(text)
@@ -886,10 +888,6 @@ def test_subcommand_tab_completion_space_in_text(sc_app):
sc_app.completion_matches == ['Ball" '] and \
sc_app.display_matches == ['Space Ball']
-
-
-
-
####################################################
@@ -960,6 +958,7 @@ class SubcommandsWithUnknownExample(cmd2.Cmd):
@pytest.fixture
def scu_app():
+ """Declare test fixture for with_argparser_and_unknown_args"""
app = SubcommandsWithUnknownExample()
return app
@@ -975,6 +974,7 @@ def test_cmd2_subcmd_with_unknown_completion_single_end(scu_app):
# It is at end of line, so extra space is present
assert first_match is not None and scu_app.completion_matches == ['foo ']
+
def test_cmd2_subcmd_with_unknown_completion_multiple(scu_app):
text = ''
line = 'base {}'.format(text)
@@ -984,6 +984,7 @@ def test_cmd2_subcmd_with_unknown_completion_multiple(scu_app):
first_match = complete_tester(text, line, begidx, endidx, scu_app)
assert first_match is not None and scu_app.completion_matches == ['bar', 'foo', 'sport']
+
def test_cmd2_subcmd_with_unknown_completion_nomatch(scu_app):
text = 'z'
line = 'base {}'.format(text)
@@ -1001,6 +1002,7 @@ def test_cmd2_help_subcommand_completion_single(scu_app):
begidx = endidx - len(text)
assert scu_app.complete_help(text, line, begidx, endidx) == ['base']
+
def test_cmd2_help_subcommand_completion_multiple(scu_app):
text = ''
line = 'help base {}'.format(text)
@@ -1018,6 +1020,7 @@ def test_cmd2_help_subcommand_completion_nomatch(scu_app):
begidx = endidx - len(text)
assert scu_app.complete_help(text, line, begidx, endidx) == []
+
def test_subcommand_tab_completion(scu_app):
# This makes sure the correct completer for the sport subcommand is called
text = 'Foot'
@@ -1030,6 +1033,7 @@ def test_subcommand_tab_completion(scu_app):
# It is at end of line, so extra space is present
assert first_match is not None and scu_app.completion_matches == ['Football ']
+
def test_subcommand_tab_completion_with_no_completer(scu_app):
# This tests what happens when a subcommand has no completer
# In this case, the foo subcommand has no completer defined
@@ -1041,6 +1045,7 @@ def test_subcommand_tab_completion_with_no_completer(scu_app):
first_match = complete_tester(text, line, begidx, endidx, scu_app)
assert first_match is None
+
def test_subcommand_tab_completion_space_in_text(scu_app):
text = 'B'
line = 'base sport "Space {}'.format(text)
@@ -1053,19 +1058,9 @@ def test_subcommand_tab_completion_space_in_text(scu_app):
scu_app.completion_matches == ['Ball" '] and \
scu_app.display_matches == ['Space Ball']
-
-
####################################################
-
-
-
-
-
-
-
-
class SecondLevel(cmd2.Cmd):
"""To be used as a second level command class. """