From 3cf43e1dd72d9831c8fcfdc1a3ff2b12c8d0aa6a Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 20 Feb 2019 21:11:19 -0500 Subject: [PATCH 1/5] Fixed bug where items tab completed in set were not current --- cmd2/cmd2.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index c690aef95..216ecf747 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -1604,13 +1604,17 @@ def get_visible_commands(self) -> List[str]: return commands def get_alias_names(self) -> List[str]: - """Return a list of alias names.""" + """Return list of current alias names""" return list(self.aliases) def get_macro_names(self) -> List[str]: - """Return a list of macro names.""" + """Return list of current macro names""" return list(self.macros) + def get_settable_names(self) -> List[str]: + """Return list of current settable names""" + return list(self.settable) + def get_commands_aliases_and_macros_for_completion(self) -> List[str]: """Return a list of visible commands, aliases, and macros for tab completion""" visible_commands = set(self.get_visible_commands()) @@ -2837,7 +2841,7 @@ def show(self, args: argparse.Namespace, parameter: str='') -> None: set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well') set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter') setattr(set_parser.add_argument('param', nargs='?', help='parameter to set or view'), - ACTION_ARG_CHOICES, settable) + ACTION_ARG_CHOICES, get_settable_names) set_parser.add_argument('value', nargs='?', help='the new value for settable') @with_argparser(set_parser) From 10f6b1d2eb05f636ce4b2874235b95e0cb83ee4a Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 20 Feb 2019 21:13:02 -0500 Subject: [PATCH 2/5] Added bug fix to change log --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc91dfbf3..6d3b4c328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.9 (TBD, 2019) +* Bug Fixes + * Fixed bug where the ``set`` command was not tab completing from the current ``settable`` dictionary. + ## 0.9.8 (February 06, 2019) * Bug Fixes * Fixed issue with echoing strings in StdSim. Because they were being sent to a binary buffer, line buffering From 5d49abe3623c0b3cc7b83c544eda64b35280a05e Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 20 Feb 2019 22:24:06 -0500 Subject: [PATCH 3/5] Added unit test --- tests/test_cmd2.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 630a8fa00..09c4fa6ce 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -1849,6 +1849,9 @@ def test_get_macro_names(base_app): assert len(base_app.macros) == 2 assert sorted(base_app.get_macro_names()) == ['bar', 'foo'] +def test_get_settable_names(base_app): + assert sorted(base_app.get_settable_names()) == sorted(base_app.settable.keys()) + def test_alias_no_subcommand(base_app, capsys): out = run_cmd(base_app, 'alias') assert "Usage: alias [-h]" in out[0] From 6e4d4801827559b3dc150b1dd29de482cfba2626 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 20 Feb 2019 22:39:36 -0500 Subject: [PATCH 4/5] No longer sorting settable during initialization since the show method already sorts it results --- cmd2/cmd2.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 216ecf747..65435d6b8 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -31,7 +31,6 @@ # setting is True import argparse import cmd -import collections import glob import inspect import os @@ -351,7 +350,6 @@ class Cmd(cmd.Cmd): timing = False # Prints elapsed time for each command # To make an attribute settable with the "do_set" command, add it to this ... - # This starts out as a dictionary but gets converted to an OrderedDict sorted alphabetically by key settable = {'colors': 'Allow colorized output (valid values: Terminal, Always, Never)', 'continuation_prompt': 'On 2nd+ line of input', 'debug': 'Show full error stack on error', @@ -562,13 +560,10 @@ def visible_prompt(self) -> str: return utils.strip_ansi(self.prompt) def _finalize_app_parameters(self) -> None: - """Finalize the shortcuts and settable parameters.""" + """Finalize the shortcuts""" # noinspection PyUnresolvedReferences self.shortcuts = sorted(self.shortcuts.items(), reverse=True) - # Make sure settable parameters are sorted alphabetically by key - self.settable = collections.OrderedDict(sorted(self.settable.items(), key=lambda t: t[0])) - def decolorized_write(self, fileobj: IO, msg: str) -> None: """Write a string to a fileobject, stripping ANSI escape sequences if necessary From 6cb882e3420fef1497955c9b4c7f0d8674e1557d Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Wed, 20 Feb 2019 22:56:25 -0500 Subject: [PATCH 5/5] Changed examples to reflect that settable doesn't need to be updated before calling init() --- README.md | 6 ++++-- examples/cmd_as_argument.py | 6 ++++-- examples/colors.py | 6 ++++-- examples/decorator_example.py | 6 +++--- examples/environment.py | 2 +- examples/example.py | 6 ++++-- examples/pirate.py | 7 +++++-- examples/plumbum_colors.py | 6 ++++-- tests/test_transcript.py | 5 +++-- 9 files changed, 32 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 97b7e72b6..0480f51b6 100755 --- a/README.md +++ b/README.md @@ -242,12 +242,14 @@ class CmdLineApp(cmd2.Cmd): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'max repetitions for speak command' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=False) + + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'max repetitions for speak command' speak_parser = argparse.ArgumentParser() speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') diff --git a/examples/cmd_as_argument.py b/examples/cmd_as_argument.py index 070a34a0e..dcec81c8b 100755 --- a/examples/cmd_as_argument.py +++ b/examples/cmd_as_argument.py @@ -33,13 +33,15 @@ def __init__(self): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'max repetitions for speak command' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=False) + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'max repetitions for speak command' + speak_parser = argparse.ArgumentParser() speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') diff --git a/examples/colors.py b/examples/colors.py index 2641ae44d..62df54e62 100755 --- a/examples/colors.py +++ b/examples/colors.py @@ -66,13 +66,15 @@ def __init__(self): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'max repetitions for speak command' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=True) + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'max repetitions for speak command' + speak_parser = argparse.ArgumentParser() speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') diff --git a/examples/decorator_example.py b/examples/decorator_example.py index bd9228db6..5d127619b 100755 --- a/examples/decorator_example.py +++ b/examples/decorator_example.py @@ -23,12 +23,12 @@ def __init__(self, ip_addr=None, port=None, transcript_files=None): self.shortcuts.update({'&': 'speak'}) self.maxrepeats = 3 - # Add stuff to settable and/or shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' - # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=False, transcript_files=transcript_files) + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' + # Disable cmd's usage of command-line arguments as commands to be run at invocation # self.allow_cli_args = False diff --git a/examples/environment.py b/examples/environment.py index c45ce71cb..e899cce87 100755 --- a/examples/environment.py +++ b/examples/environment.py @@ -14,9 +14,9 @@ class EnvironmentApp(cmd2.Cmd): sunny = False def __init__(self): + super().__init__() self.settable.update({'degrees_c': 'Temperature in Celsius'}) self.settable.update({'sunny': 'Is it sunny outside?'}) - super().__init__() def do_sunbathe(self, arg): if self.degrees_c < 20: diff --git a/examples/example.py b/examples/example.py index 264abd849..04727ec69 100755 --- a/examples/example.py +++ b/examples/example.py @@ -30,13 +30,15 @@ def __init__(self): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'max repetitions for speak command' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=False) + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'max repetitions for speak command' + speak_parser = argparse.ArgumentParser() speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') diff --git a/examples/pirate.py b/examples/pirate.py index 2da3fcaa7..323304049 100755 --- a/examples/pirate.py +++ b/examples/pirate.py @@ -32,12 +32,15 @@ def __init__(self): self.terminators = self.terminators + ['...'] self.songcolor = Fore.BLUE - # Add stuff to settable and/or shortcuts before calling base class initializer - self.settable['songcolor'] = 'Color to ``sing`` in (black/red/green/yellow/blue/magenta/cyan/white)' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'~': 'sing'}) """Initialize the base class as well as this one""" super().__init__() + + # Make songcolor settable at runtime + self.settable['songcolor'] = 'Color to ``sing`` in (black/red/green/yellow/blue/magenta/cyan/white)' + # prompts and defaults self.gold = 0 self.initial_gold = self.gold diff --git a/examples/plumbum_colors.py b/examples/plumbum_colors.py index 0cea3c10f..3e5031d73 100755 --- a/examples/plumbum_colors.py +++ b/examples/plumbum_colors.py @@ -69,13 +69,15 @@ def __init__(self): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and shortcuts before calling base class initializer - self.settable['maxrepeats'] = 'max repetitions for speak command' + # Add stuff to shortcuts before calling base class initializer self.shortcuts.update({'&': 'speak'}) # Set use_ipython to True to enable the "ipy" command which embeds and interactive IPython shell super().__init__(use_ipython=True) + # Make maxrepeats settable at runtime + self.settable['maxrepeats'] = 'max repetitions for speak command' + speak_parser = argparse.ArgumentParser() speak_parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') speak_parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') diff --git a/tests/test_transcript.py b/tests/test_transcript.py index d7438e861..6bfe187ea 100644 --- a/tests/test_transcript.py +++ b/tests/test_transcript.py @@ -32,10 +32,11 @@ def __init__(self, *args, **kwargs): self.multiline_commands = ['orate'] self.maxrepeats = 3 - # Add stuff to settable and/or shortcuts before calling base class initializer + super().__init__(*args, **kwargs) + + # Make maxrepeats settable at runtime self.settable['maxrepeats'] = 'Max number of `--repeat`s allowed' - super().__init__(*args, **kwargs) self.intro = 'This is an intro banner ...' speak_parser = argparse.ArgumentParser()