summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md10
-rw-r--r--cmd2/argparse_completer.py2
-rw-r--r--cmd2/argparse_custom.py1
-rw-r--r--cmd2/cmd2.py217
-rw-r--r--cmd2/table_creator.py27
-rw-r--r--docs/features/builtin_commands.rst26
-rw-r--r--docs/features/settings.rst8
-rw-r--r--tests/conftest.py40
-rw-r--r--tests/test_argparse_completer.py24
-rwxr-xr-xtests/test_cmd2.py47
-rw-r--r--tests/test_table_creator.py7
-rw-r--r--tests/transcripts/regex_set.txt31
-rw-r--r--tests_isolated/test_commandset/conftest.py22
-rw-r--r--tests_isolated/test_commandset/test_commandset.py12
14 files changed, 303 insertions, 171 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a782f55f..1e117b17 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,15 @@
## 2.2.0 (TBD, 2021)
+* Enhancements
+ * Using `SimpleTable` in the output for the following commands to improve appearance.
+ * help
+ * set (command and tab completion of Settables)
+ * alias tab completion
+ * macro tab completion
+ * Tab completion of `CompletionItems` now includes divider row comprised of `Cmd.ruler` character.
+ * Removed `--verbose` flag from set command since descriptions always show now.
* Deletions (potentially breaking changes)
* Deleted ``set_choices_provider()`` and ``set_completer()`` which were deprecated in 2.1.2
-
+
## 2.1.2 (July 5, 2021)
* Enhancements
* Added the following accessor methods for cmd2-specific attributes to the `argparse.Action` class
diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py
index a244941c..967e3f1c 100644
--- a/cmd2/argparse_completer.py
+++ b/cmd2/argparse_completer.py
@@ -578,7 +578,7 @@ class ArgparseCompleter:
cols.append(Column(destination.upper(), width=token_width))
cols.append(Column(desc_header, width=desc_width))
- hint_table = SimpleTable(cols, divider_char=None)
+ hint_table = SimpleTable(cols, divider_char=self._cmd2_app.ruler)
table_data = [[item, item.description] for item in completion_items]
self._cmd2_app.formatted_completions = hint_table.generate_table(table_data, row_spacing=0)
diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py
index 770b1e5c..d6e89989 100644
--- a/cmd2/argparse_custom.py
+++ b/cmd2/argparse_custom.py
@@ -130,6 +130,7 @@ tokens with descriptions instead of just a table of tokens::
The user sees this:
ITEM_ID Item Name
+ ============================
1 My item
2 Another item
3 Yet another item
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index df4d1dc2..35398088 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -130,6 +130,10 @@ from .rl_utils import (
rl_warning,
vt100_support,
)
+from .table_creator import (
+ Column,
+ SimpleTable,
+)
from .utils import (
Settable,
get_defining_class,
@@ -2017,7 +2021,7 @@ class Cmd(cmd.Cmd):
def complete( # type: ignore[override]
self, text: str, state: int, custom_settings: Optional[utils.CustomCompletionSettings] = None
) -> Optional[str]:
- """Override of cmd2's complete method which returns the next possible completion for 'text'
+ """Override of cmd's complete method which returns the next possible completion for 'text'
This completer function is called by readline as complete(text, state), for state in 0, 1, 2, …,
until it returns a non-string value. It should return the next possible completion starting with text.
@@ -2152,17 +2156,44 @@ class Cmd(cmd.Cmd):
if command not in self.hidden_commands and command not in self.disabled_commands
]
+ # Table displayed when tab completing aliases
+ _alias_completion_table = SimpleTable([Column('Value', width=80)], divider_char=None)
+
def _get_alias_completion_items(self) -> List[CompletionItem]:
- """Return list of current alias names and values as CompletionItems"""
- return [CompletionItem(cur_key, self.aliases[cur_key]) for cur_key in self.aliases]
+ """Return list of alias names and values as CompletionItems"""
+ results: List[CompletionItem] = []
+
+ for cur_key in self.aliases:
+ row_data = [self.aliases[cur_key]]
+ results.append(CompletionItem(cur_key, self._alias_completion_table.generate_data_row(row_data)))
+
+ return results
+
+ # Table displayed when tab completing macros
+ _macro_completion_table = SimpleTable([Column('Value', width=80)], divider_char=None)
def _get_macro_completion_items(self) -> List[CompletionItem]:
- """Return list of current macro names and values as CompletionItems"""
- return [CompletionItem(cur_key, self.macros[cur_key].value) for cur_key in self.macros]
+ """Return list of macro names and values as CompletionItems"""
+ results: List[CompletionItem] = []
+
+ for cur_key in self.macros:
+ row_data = [self.macros[cur_key].value]
+ results.append(CompletionItem(cur_key, self._macro_completion_table.generate_data_row(row_data)))
+
+ return results
+
+ # Table displayed when tab completing Settables
+ _settable_completion_table = SimpleTable([Column('Value', width=30), Column('Description', width=60)], divider_char=None)
def _get_settable_completion_items(self) -> List[CompletionItem]:
- """Return list of current settable names and descriptions as CompletionItems"""
- return [CompletionItem(cur_key, self.settables[cur_key].description) for cur_key in self.settables]
+ """Return list of Settable names, values, and descriptions as CompletionItems"""
+ results: List[CompletionItem] = []
+
+ for cur_key in self.settables:
+ row_data = [self.settables[cur_key].get_value(), self.settables[cur_key].description]
+ results.append(CompletionItem(cur_key, self._settable_completion_table.generate_data_row(row_data)))
+
+ return results
def _get_commands_aliases_and_macros_for_completion(self) -> List[str]:
"""Return a list of visible commands, aliases, and macros for tab completion"""
@@ -3163,7 +3194,7 @@ class Cmd(cmd.Cmd):
nargs=argparse.ZERO_OR_MORE,
help='alias(es) to delete',
choices_provider=_get_alias_completion_items,
- descriptive_header='Value',
+ descriptive_header=_alias_completion_table.generate_header(),
)
@as_subcommand_to('alias', 'delete', alias_delete_parser, help=alias_delete_help)
@@ -3197,7 +3228,7 @@ class Cmd(cmd.Cmd):
nargs=argparse.ZERO_OR_MORE,
help='alias(es) to list',
choices_provider=_get_alias_completion_items,
- descriptive_header='Value',
+ descriptive_header=_alias_completion_table.generate_header(),
)
@as_subcommand_to('alias', 'list', alias_list_parser, help=alias_list_help)
@@ -3389,7 +3420,7 @@ class Cmd(cmd.Cmd):
nargs=argparse.ZERO_OR_MORE,
help='macro(s) to delete',
choices_provider=_get_macro_completion_items,
- descriptive_header='Value',
+ descriptive_header=_macro_completion_table.generate_header(),
)
@as_subcommand_to('macro', 'delete', macro_delete_parser, help=macro_delete_help)
@@ -3423,7 +3454,7 @@ class Cmd(cmd.Cmd):
nargs=argparse.ZERO_OR_MORE,
help='macro(s) to list',
choices_provider=_get_macro_completion_items,
- descriptive_header='Value',
+ descriptive_header=_macro_completion_table.generate_header(),
)
@as_subcommand_to('macro', 'list', macro_list_parser, help=macro_list_help)
@@ -3545,6 +3576,80 @@ class Cmd(cmd.Cmd):
# Set apply_style to False so help_error's style is not overridden
self.perror(err_msg, apply_style=False)
+ def print_topics(self, header: str, cmds: Optional[List[str]], cmdlen: int, maxcol: int) -> None:
+ """
+ Print groups of commands and topics in columns and an optional header
+ Override of cmd's print_topics() to handle headers with newlines, ANSI style sequences, and wide characters
+
+ :param header: string to print above commands being printed
+ :param cmds: list of topics to print
+ :param cmdlen: unused, even by cmd's version
+ :param maxcol: max number of display columns to fit into
+ """
+ if cmds:
+ self.poutput(header)
+ if self.ruler:
+ divider = utils.align_left('', fill_char=self.ruler, width=ansi.widest_line(header))
+ self.poutput(divider)
+ self.columnize(cmds, maxcol - 1)
+ self.poutput()
+
+ def columnize(self, str_list: Optional[List[str]], display_width: int = 80) -> None:
+ """Display a list of single-line strings as a compact set of columns.
+ Override of cmd's print_topics() to handle strings with ANSI style sequences and wide characters
+
+ Each column is only as wide as necessary.
+ Columns are separated by two spaces (one was not legible enough).
+ """
+ if not str_list:
+ self.poutput("<empty>")
+ return
+
+ nonstrings = [i for i in range(len(str_list)) if not isinstance(str_list[i], str)]
+ if nonstrings:
+ raise TypeError(f"str_list[i] not a string for i in {nonstrings}")
+ size = len(str_list)
+ if size == 1:
+ self.poutput(str_list[0])
+ return
+ # Try every row count from 1 upwards
+ for nrows in range(1, len(str_list)):
+ ncols = (size + nrows - 1) // nrows
+ colwidths = []
+ totwidth = -2
+ for col in range(ncols):
+ colwidth = 0
+ for row in range(nrows):
+ i = row + nrows * col
+ if i >= size:
+ break
+ x = str_list[i]
+ colwidth = max(colwidth, ansi.style_aware_wcswidth(x))
+ colwidths.append(colwidth)
+ totwidth += colwidth + 2
+ if totwidth > display_width:
+ break
+ if totwidth <= display_width:
+ break
+ else:
+ nrows = len(str_list)
+ ncols = 1
+ colwidths = [0]
+ for row in range(nrows):
+ texts = []
+ for col in range(ncols):
+ i = row + nrows * col
+ if i >= size:
+ x = ""
+ else:
+ x = str_list[i]
+ texts.append(x)
+ while texts and not texts[-1]:
+ del texts[-1]
+ for col in range(len(texts)):
+ texts[col] = utils.align_left(texts[col], width=colwidths[col])
+ self.poutput(" ".join(texts))
+
def _help_menu(self, verbose: bool = False) -> None:
"""Show a list of commands which help can be displayed for"""
cmds_cats, cmds_doc, cmds_undoc, help_topics = self._build_command_info()
@@ -3602,25 +3707,26 @@ class Cmd(cmd.Cmd):
if not verbose:
self.print_topics(header, cmds, 15, 80)
else:
- self.poutput(f'{header}')
- widest = 0
- # measure the commands
- for command in cmds:
- width = ansi.style_aware_wcswidth(command)
- if width > widest:
- widest = width
- # add a 4-space pad
- widest += 4
- if widest < 20:
- widest = 20
-
- if self.ruler:
- ruler_line = utils.align_left('', width=80, fill_char=self.ruler)
- self.poutput(f'{ruler_line}')
+ # Find the widest command
+ widest = max([ansi.style_aware_wcswidth(command) for command in cmds])
+
+ # Define the table structure
+ name_column = Column('', width=max(widest, 20))
+ desc_column = Column('', width=80)
+
+ topic_table = SimpleTable([name_column, desc_column], divider_char=self.ruler)
+
+ # Build the topic table
+ table_str_buf = io.StringIO()
+ if header:
+ table_str_buf.write(header + "\n")
+
+ divider = topic_table.generate_divider()
+ if divider:
+ table_str_buf.write(divider + "\n")
# Try to get the documentation string for each command
topics = self.get_help_topics()
-
for command in cmds:
cmd_func = self.cmd_func(command)
doc: Optional[str]
@@ -3647,10 +3753,8 @@ class Cmd(cmd.Cmd):
doc = cmd_func.__doc__
# Attempt to locate the first documentation block
- if not doc:
- doc_block = ['']
- else:
- doc_block = []
+ cmd_desc = ''
+ if doc:
found_first = False
for doc_line in doc.splitlines():
stripped_line = doc_line.strip()
@@ -3660,15 +3764,18 @@ class Cmd(cmd.Cmd):
if found_first:
break
elif stripped_line:
- doc_block.append(stripped_line)
+ if found_first:
+ cmd_desc += "\n"
+ cmd_desc += stripped_line
found_first = True
elif found_first:
break
- for doc_line in doc_block:
- self.poutput(f'{command: <{widest}}{doc_line}')
- command = ''
- self.poutput()
+ # Add this command to the table
+ table_row = topic_table.generate_data_row([command, cmd_desc])
+ table_str_buf.write(table_row + '\n')
+
+ self.poutput(table_str_buf.getvalue())
shortcuts_parser = DEFAULT_ARGUMENT_PARSER(description="List available shortcuts")
@@ -3794,14 +3901,11 @@ class Cmd(cmd.Cmd):
)
set_parser_parent = DEFAULT_ARGUMENT_PARSER(description=set_description, add_help=False)
set_parser_parent.add_argument(
- '-v', '--verbose', action='store_true', help='include description of parameters when viewing'
- )
- set_parser_parent.add_argument(
'param',
nargs=argparse.OPTIONAL,
help='parameter to set or view',
choices_provider=_get_settable_completion_items,
- descriptive_header='Description',
+ descriptive_header=_settable_completion_table.generate_header(),
)
# Create the parser for the set command
@@ -3843,21 +3947,25 @@ class Cmd(cmd.Cmd):
# Show all settables
to_show = list(self.settables.keys())
- # Build the result strings
- max_len = 0
- results = dict()
- for param in to_show:
+ # Define the table structure
+ name_label = 'Name'
+ max_name_width = max([ansi.style_aware_wcswidth(param) for param in to_show])
+ max_name_width = max(max_name_width, ansi.style_aware_wcswidth(name_label))
+
+ cols: List[Column] = [
+ Column(name_label, width=max_name_width),
+ Column('Value', width=30),
+ Column('Description', width=60),
+ ]
+
+ table = SimpleTable(cols, divider_char=self.ruler)
+ self.poutput(table.generate_header())
+
+ # Build the table
+ for param in sorted(to_show, key=self.default_sort_key):
settable = self.settables[param]
- results[param] = f"{param}: {settable.get_value()!r}"
- max_len = max(max_len, ansi.style_aware_wcswidth(results[param]))
-
- # Display the results
- for param in sorted(results, key=self.default_sort_key):
- result_str = results[param]
- if args.verbose:
- self.poutput(f'{utils.align_left(result_str, width=max_len)} # {self.settables[param].description}')
- else:
- self.poutput(result_str)
+ row_data = [param, settable.get_value(), settable.description]
+ self.poutput(table.generate_data_row(row_data))
shell_parser = DEFAULT_ARGUMENT_PARSER(description="Execute a command as if at the OS prompt")
shell_parser.add_argument('command', help='the command to run', completer=shell_cmd_complete)
@@ -4057,7 +4165,6 @@ class Cmd(cmd.Cmd):
If pyscript is None, then this function runs an interactive Python shell.
Otherwise, it runs the pyscript file.
- :param args: Namespace of args on the command line
:param pyscript: optional path to a pyscript file to run. This is intended only to be used by do_run_pyscript()
after it sets up sys.argv for the script. (Defaults to None)
:return: True if running of commands should stop
diff --git a/cmd2/table_creator.py b/cmd2/table_creator.py
index 3df6ce37..5420ebec 100644
--- a/cmd2/table_creator.py
+++ b/cmd2/table_creator.py
@@ -545,7 +545,7 @@ class SimpleTable(TableCreator):
:param column_spacing: how many spaces to place between columns. Defaults to 2.
:param tab_width: all tabs will be replaced with this many spaces. If a row's fill_char is a tab,
then it will be converted to one space.
- :param divider_char: optional character used to build the header divider row. Set this to None if you don't
+ :param divider_char: optional character used to build the header divider row. Set this to blank or None if you don't
want a divider row. Defaults to dash. (Cannot be a line breaking character)
:raises: ValueError if column_spacing is less than 0
:raises: ValueError if tab_width is less than 1
@@ -556,6 +556,9 @@ class SimpleTable(TableCreator):
raise ValueError("Column spacing cannot be less than 0")
self.inter_cell = column_spacing * SPACE
+ if divider_char == '':
+ divider_char = None
+
if divider_char is not None:
if len(ansi.strip_style(divider_char)) != 1:
raise TypeError("Divider character must be exactly one character long")
@@ -604,20 +607,20 @@ class SimpleTable(TableCreator):
header = self.generate_row(inter_cell=self.inter_cell)
header_buf.write(header)
- # Create the divider if necessary
- if self.divider_char is not None:
- total_width = self.total_width()
- divider_char_width = ansi.style_aware_wcswidth(self.divider_char)
-
- # Make divider as wide as table and use padding if width of
- # divider_char does not divide evenly into table width.
- divider = self.divider_char * (total_width // divider_char_width)
- divider += SPACE * (total_width % divider_char_width)
+ # Add the divider if necessary
+ divider = self.generate_divider()
+ if divider:
+ header_buf.write('\n' + divider)
- header_buf.write('\n')
- header_buf.write(divider)
return header_buf.getvalue()
+ def generate_divider(self) -> str:
+ """Generate divider row"""
+ if self.divider_char is None:
+ return ''
+
+ return utils.align_left('', fill_char=self.divider_char, width=self.total_width())
+
def generate_data_row(self, row_data: Sequence[Any]) -> str:
"""
Generate a data row
diff --git a/docs/features/builtin_commands.rst b/docs/features/builtin_commands.rst
index 14f340c2..97b160b5 100644
--- a/docs/features/builtin_commands.rst
+++ b/docs/features/builtin_commands.rst
@@ -102,16 +102,22 @@ within a running application:
.. code-block:: text
- (Cmd) set --verbose
- allow_style: 'Terminal' # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never)
- always_show_hint: False # Display tab completion hint even when completion suggestions print
- debug: True # Show full traceback on exception
- echo: False # Echo command issued into output
- editor: 'vi' # Program used by 'edit'
- feedback_to_output: False # Include nonessentials in '|', '>' results
- max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
- quiet: False # Don't print nonessential feedback
- timing: False # Report execution times
+ (Cmd) set
+ Name Value Description
+ ==================================================================================================================
+ allow_style Terminal Allow ANSI text style sequences in output (valid values:
+ Terminal, Always, Never)
+ always_show_hint False Display tab completion hint even when completion suggestions
+ print
+ debug True Show full traceback on exception
+ echo False Echo command issued into output
+ editor vi Program used by 'edit'
+ feedback_to_output False Include nonessentials in '|', '>' results
+ max_completion_items 50 Maximum number of CompletionItems to display during tab
+ completion
+ quiet False Don't print nonessential feedback
+ timing False Report execution times
+
Any of these user-settable parameters can be set while running your app with
the ``set`` command like so:
diff --git a/docs/features/settings.rst b/docs/features/settings.rst
index c21b3258..0be46292 100644
--- a/docs/features/settings.rst
+++ b/docs/features/settings.rst
@@ -134,10 +134,10 @@ changes a setting, and will receive both the old value and the new value.
.. code-block:: text
- (Cmd) set --verbose | grep sunny
- sunny: False # Is it sunny outside?
- (Cmd) set --verbose | grep degrees
- degrees_c: 22 # Temperature in Celsius
+ (Cmd) set | grep sunny
+ sunny False Is it sunny outside?
+ (Cmd) set | grep degrees
+ degrees_c 22 Temperature in Celsius
(Cmd) sunbathe
Too dim.
(Cmd) set degrees_c 41
diff --git a/tests/conftest.py b/tests/conftest.py
index a5c47d97..0829da2f 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -104,29 +104,23 @@ SHORTCUTS_TXT = """Shortcuts for other commands:
@@: _relative_run_script
"""
-# Output from the show command with default settings
-SHOW_TXT = """allow_style: 'Terminal'
-always_show_hint: False
-debug: False
-echo: False
-editor: 'vim'
-feedback_to_output: False
-max_completion_items: 50
-quiet: False
-timing: False
-"""
-
-SHOW_LONG = """
-allow_style: 'Terminal' # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never)
-always_show_hint: False # Display tab completion hint even when completion suggestions print
-debug: False # Show full traceback on exception
-echo: False # Echo command issued into output
-editor: 'vim' # Program used by 'edit'
-feedback_to_output: False # Include nonessentials in '|', '>' results
-max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
-quiet: False # Don't print nonessential feedback
-timing: False # Report execution times
-"""
+# Output from the set command
+SET_TXT = (
+ "Name Value Description \n"
+ "==================================================================================================================\n"
+ "allow_style Terminal Allow ANSI text style sequences in output (valid values: \n"
+ " Terminal, Always, Never) \n"
+ "always_show_hint False Display tab completion hint even when completion suggestions\n"
+ " print \n"
+ "debug False Show full traceback on exception \n"
+ "echo False Echo command issued into output \n"
+ "editor vim Program used by 'edit' \n"
+ "feedback_to_output False Include nonessentials in '|', '>' results \n"
+ "max_completion_items 50 Maximum number of CompletionItems to display during tab \n"
+ " completion \n"
+ "quiet False Don't print nonessential feedback \n"
+ "timing False Report execution times \n"
+)
def normalize(block):
diff --git a/tests/test_argparse_completer.py b/tests/test_argparse_completer.py
index 6002a856..25a13157 100644
--- a/tests/test_argparse_completer.py
+++ b/tests/test_argparse_completer.py
@@ -725,10 +725,14 @@ def test_completion_items(ac_app, num_aliases, show_description):
assert bool(ac_app.formatted_completions) == show_description
if show_description:
- # If show_description is True, the table will show both the alias name and result
- first_result_line = normalize(ac_app.formatted_completions)[1]
- assert 'fake_alias0' in first_result_line
- assert 'help' in first_result_line
+ # If show_description is True, the table will show both the alias name and value
+ description_displayed = False
+ for line in ac_app.formatted_completions.splitlines():
+ if 'fake_alias0' in line and 'help' in line:
+ description_displayed = True
+ break
+
+ assert description_displayed
def test_completion_item_choices(ac_app):
@@ -742,10 +746,14 @@ def test_completion_item_choices(ac_app):
assert len(ac_app.completion_matches) == len(ac_app.completion_item_choices)
assert len(ac_app.display_matches) == len(ac_app.completion_item_choices)
- # Make sure a completion table was created
- first_result_line = normalize(ac_app.formatted_completions)[1]
- assert 'choice_1' in first_result_line
- assert 'A description' in first_result_line
+ # The table will show both the choice and description
+ description_displayed = False
+ for line in ac_app.formatted_completions.splitlines():
+ if 'choice_1' in line and 'A description' in line:
+ description_displayed = True
+ break
+
+ assert description_displayed
@pytest.mark.parametrize(
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index 928c323a..c541259e 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -31,9 +31,8 @@ from cmd2 import (
from .conftest import (
HELP_HISTORY,
+ SET_TXT,
SHORTCUTS_TXT,
- SHOW_LONG,
- SHOW_TXT,
complete_tester,
normalize,
odd_file_names,
@@ -107,7 +106,7 @@ def test_base_argparse_help(base_app):
def test_base_invalid_option(base_app):
out, err = run_cmd(base_app, 'set -z')
- assert err[0] == 'Usage: set [-h] [-v] [param] [value]'
+ assert err[0] == 'Usage: set [-h] [param] [value]'
assert 'Error: unrecognized arguments: -z' in err[1]
@@ -123,19 +122,11 @@ def test_command_starts_with_shortcut():
assert "Invalid command name 'help'" in str(excinfo.value)
-def test_base_show(base_app):
+def test_base_set(base_app):
# force editor to be 'vim' so test is repeatable across platforms
base_app.editor = 'vim'
out, err = run_cmd(base_app, 'set')
- expected = normalize(SHOW_TXT)
- assert out == expected
-
-
-def test_base_show_long(base_app):
- # force editor to be 'vim' so test is repeatable across platforms
- base_app.editor = 'vim'
- out, err = run_cmd(base_app, 'set -v')
- expected = normalize(SHOW_LONG)
+ expected = normalize(SET_TXT)
assert out == expected
@@ -150,7 +141,14 @@ now: True
assert out == expected
out, err = run_cmd(base_app, 'set quiet')
- assert out == ['quiet: True']
+ expected = normalize(
+ """
+Name Value Description
+===================================================================================================
+quiet True Don't print nonessential feedback
+"""
+ )
+ assert out == expected
def test_set_val_empty(base_app):
@@ -1752,7 +1750,8 @@ def test_get_alias_completion_items(base_app):
for cur_res in results:
assert cur_res in base_app.aliases
- assert cur_res.description == base_app.aliases[cur_res]
+ # Strip trailing spaces from table output
+ assert cur_res.description.rstrip() == base_app.aliases[cur_res]
def test_get_macro_completion_items(base_app):
@@ -1764,14 +1763,26 @@ def test_get_macro_completion_items(base_app):
for cur_res in results:
assert cur_res in base_app.macros
- assert cur_res.description == base_app.macros[cur_res].value
+ # Strip trailing spaces from table output
+ assert cur_res.description.rstrip() == base_app.macros[cur_res].value
def test_get_settable_completion_items(base_app):
results = base_app._get_settable_completion_items()
+ assert len(results) == len(base_app.settables)
+
for cur_res in results:
- assert cur_res in base_app.settables
- assert cur_res.description == base_app.settables[cur_res].description
+ cur_settable = base_app.settables.get(cur_res)
+ assert cur_settable is not None
+
+ # These CompletionItem descriptions are a two column table (Settable Value and Settable Description)
+ # First check if the description text starts with the value
+ str_value = str(cur_settable.get_value())
+ assert cur_res.description.startswith(str_value)
+
+ # The second column is likely to have wrapped long text. So we will just examine the
+ # first couple characters to look for the Settable's description.
+ assert cur_settable.description[0:10] in cur_res.description
def test_alias_no_subcommand(base_app):
diff --git a/tests/test_table_creator.py b/tests/test_table_creator.py
index 70b77bad..e1bc8883 100644
--- a/tests/test_table_creator.py
+++ b/tests/test_table_creator.py
@@ -364,9 +364,12 @@ def test_simple_table_creation():
# No divider
st = SimpleTable([column_1, column_2], divider_char=None)
- table = st.generate_table(row_data)
+ no_divider_1 = st.generate_table(row_data)
- assert table == (
+ st = SimpleTable([column_1, column_2], divider_char='')
+ no_divider_2 = st.generate_table(row_data)
+
+ assert no_divider_1 == no_divider_2 == (
'Col 1 Col 2 \n'
'Col 1 Row 1 Col 2 Row 1 \n'
'\n'
diff --git a/tests/transcripts/regex_set.txt b/tests/transcripts/regex_set.txt
index 623df8ed..68e61e30 100644
--- a/tests/transcripts/regex_set.txt
+++ b/tests/transcripts/regex_set.txt
@@ -3,14 +3,25 @@
# The regex for editor will match whatever program you use.
# Regexes on prompts just make the trailing space obvious
+(Cmd) set allow_style Terminal
+allow_style - was: '/.*/'
+now: 'Terminal'
+(Cmd) set editor vim
+editor - was: '/.*/'
+now: 'vim'
(Cmd) set
-allow_style: /'(Terminal|Always|Never)'/
-always_show_hint: False
-debug: False
-echo: False
-editor: /'.*'/
-feedback_to_output: False
-max_completion_items: 50
-maxrepeats: 3
-quiet: False
-timing: False
+Name Value Description/ +/
+==================================================================================================================
+allow_style Terminal Allow ANSI text style sequences in output (valid values:/ +/
+ Terminal, Always, Never)/ +/
+always_show_hint False Display tab completion hint even when completion suggestions
+ print/ +/
+debug False Show full traceback on exception/ +/
+echo False Echo command issued into output/ +/
+editor vim Program used by 'edit'/ +/
+feedback_to_output False Include nonessentials in '|', '>' results/ +/
+max_completion_items 50 Maximum number of CompletionItems to display during tab/ +/
+ completion/ +/
+maxrepeats 3 Max number of `--repeat`s allowed/ +/
+quiet False Don't print nonessential feedback/ +/
+timing False Report execution times/ +/
diff --git a/tests_isolated/test_commandset/conftest.py b/tests_isolated/test_commandset/conftest.py
index 32def64d..43e2af3e 100644
--- a/tests_isolated/test_commandset/conftest.py
+++ b/tests_isolated/test_commandset/conftest.py
@@ -107,28 +107,6 @@ SHORTCUTS_TXT = """Shortcuts for other commands:
@@: _relative_run_script
"""
-# Output from the show command with default settings
-SHOW_TXT = """allow_style: 'Terminal'
-debug: False
-echo: False
-editor: 'vim'
-feedback_to_output: False
-max_completion_items: 50
-quiet: False
-timing: False
-"""
-
-SHOW_LONG = """
-allow_style: 'Terminal' # Allow ANSI text style sequences in output (valid values: Terminal, Always, Never)
-debug: False # Show full traceback on exception
-echo: False # Echo command issued into output
-editor: 'vim' # Program used by 'edit'
-feedback_to_output: False # Include nonessentials in '|', '>' results
-max_completion_items: 50 # Maximum number of CompletionItems to display during tab completion
-quiet: False # Don't print nonessential feedback
-timing: False # Report execution times
-"""
-
def normalize(block):
"""Normalize a block of text to perform comparison.
diff --git a/tests_isolated/test_commandset/test_commandset.py b/tests_isolated/test_commandset/test_commandset.py
index 7e4e1821..89bac976 100644
--- a/tests_isolated/test_commandset/test_commandset.py
+++ b/tests_isolated/test_commandset/test_commandset.py
@@ -987,9 +987,10 @@ def test_commandset_settables():
# verify the settable shows up
out, err = run_cmd(app, 'set')
- assert 'arbitrary_value: 5' in out
+ any(['arbitrary_value' in line and '5' in line for line in out])
+
out, err = run_cmd(app, 'set arbitrary_value')
- assert out == ['arbitrary_value: 5']
+ any(['arbitrary_value' in line and '5' in line for line in out])
# change the value and verify the value changed
out, err = run_cmd(app, 'set arbitrary_value 10')
@@ -999,7 +1000,7 @@ now: 10
"""
assert out == normalize(expected)
out, err = run_cmd(app, 'set arbitrary_value')
- assert out == ['arbitrary_value: 10']
+ any(['arbitrary_value' in line and '10' in line for line in out])
# can't add to cmd2 now because commandset already has this settable
with pytest.raises(KeyError):
@@ -1058,9 +1059,10 @@ Parameter 'arbitrary_value' not supported (type 'set' for list of parameters).
assert 'some.arbitrary_value' in app.settables.keys()
out, err = run_cmd(app, 'set')
- assert 'some.arbitrary_value: 5' in out
+ any(['some.arbitrary_value' in line and '5' in line for line in out])
+
out, err = run_cmd(app, 'set some.arbitrary_value')
- assert out == ['some.arbitrary_value: 5']
+ any(['some.arbitrary_value' in line and '5' in line for line in out])
# verify registering a commandset with duplicate prefix and settable names fails
with pytest.raises(CommandSetRegistrationError):