diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-10-05 13:32:04 -0400 |
---|---|---|
committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2018-10-05 13:32:04 -0400 |
commit | 734796b895bb85d67c651d9e8e8bf71e7d60b7e3 (patch) | |
tree | 5879270409a4992622da2933275ccaae30525ee6 | |
parent | 49cbec9969b4b53248d6097d8f395d92c74f7228 (diff) | |
download | cmd2-git-734796b895bb85d67c651d9e8e8bf71e7d60b7e3.tar.gz |
Using sub-command instead of subcommand where possible to be consistent with argparse
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rwxr-xr-x | cmd2/argparse_completer.py | 7 | ||||
-rw-r--r-- | cmd2/cmd2.py | 24 | ||||
-rw-r--r-- | cmd2/pyscript_bridge.py | 2 | ||||
-rwxr-xr-x | examples/subcommands.py | 42 | ||||
-rwxr-xr-x | examples/tab_autocomp_dynamic.py | 4 | ||||
-rwxr-xr-x | examples/tab_autocompletion.py | 8 | ||||
-rwxr-xr-x | examples/tab_completion.py | 2 | ||||
-rw-r--r-- | tests/test_argparse.py | 18 | ||||
-rw-r--r-- | tests/test_completion.py | 36 | ||||
-rw-r--r-- | tests/test_pyscript.py | 2 |
11 files changed, 77 insertions, 70 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e09d25b2..5d800fcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ have been deleted * The new application lifecycle hook system allows for registration of callbacks to be called at various points in the lifecycle and is more powerful and flexible than the previous system - * ``alias`` is now a command with subcommands to create, list, and delete aliases. Therefore its syntax + * ``alias`` is now a command with sub-commands to create, list, and delete aliases. Therefore its syntax has changed. All current alias commands in startup scripts or transcripts will break with this release. * `unalias` was deleted since ``alias delete`` replaced it diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index ad2c520b..c900a780 100755 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -917,6 +917,13 @@ class ACArgumentParser(argparse.ArgumentParser): self._custom_error_message = custom_message # End cmd2 customization + def add_subparsers(self, **kwargs): + """Custom override. Sets a default title if one was not given.""" + if 'title' not in kwargs: + kwargs['title'] = 'sub-commands' + + return super().add_subparsers(**kwargs) + def error(self, message: str) -> None: """Custom error override. Allows application to control the error being displayed by argparse""" if len(self._custom_error_message) > 0: diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 7aaacdb1..c95fbd51 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -2204,7 +2204,7 @@ class Cmd(cmd.Cmd): return stop - # ----- Alias subcommand functions ----- + # ----- Alias sub-command functions ----- def alias_create(self, args: argparse.Namespace): """Create or overwrite an alias""" @@ -2267,8 +2267,8 @@ class Cmd(cmd.Cmd): " macro") alias_parser = ACArgumentParser(description=alias_description, epilog=alias_epilog, prog='alias') - # Add subcommands to alias - alias_subparsers = alias_parser.add_subparsers(title='sub-commands') + # Add sub-commands to alias + alias_subparsers = alias_parser.add_subparsers() # alias -> create alias_create_help = "create or overwrite an alias" @@ -2326,13 +2326,13 @@ class Cmd(cmd.Cmd): """Manage aliases""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('alias') - # ----- Macro subcommand functions ----- + # ----- Macro sub-command functions ----- def macro_create(self, args: argparse.Namespace): """Create or overwrite a macro""" @@ -2445,8 +2445,8 @@ class Cmd(cmd.Cmd): " alias") macro_parser = ACArgumentParser(description=macro_description, epilog=macro_epilog, prog='macro') - # Add subcommands to macro - macro_subparsers = macro_parser.add_subparsers(title='sub-commands') + # Add sub-commands to macro + macro_subparsers = macro_parser.add_subparsers() # macro -> create macro_create_help = "create or overwrite a macro" @@ -2527,10 +2527,10 @@ class Cmd(cmd.Cmd): """Manage macros""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('macro') def complete_help_command(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: @@ -2551,7 +2551,7 @@ class Cmd(cmd.Cmd): if not tokens: return [] - # Must have at least 3 args for 'help command subcommand' + # Must have at least 3 args for 'help command sub-command' if len(tokens) < 3: return [] @@ -2580,7 +2580,7 @@ class Cmd(cmd.Cmd): setattr(help_parser.add_argument('command', help="command to retrieve help for", nargs="?"), ACTION_ARG_CHOICES, ('complete_help_command',)) - setattr(help_parser.add_argument('subcommand', help="subcommand to retrieve help for", + setattr(help_parser.add_argument('subcommand', help="sub-command to retrieve help for", nargs=argparse.REMAINDER), ACTION_ARG_CHOICES, ('complete_help_subcommand',)) help_parser.add_argument('-v', '--verbose', action='store_true', diff --git a/cmd2/pyscript_bridge.py b/cmd2/pyscript_bridge.py index a70a7ae6..2002ca6d 100644 --- a/cmd2/pyscript_bridge.py +++ b/cmd2/pyscript_bridge.py @@ -87,7 +87,7 @@ class ArgparseFunctor: return commands def __getattr__(self, item: str): - """Search for a subcommand matching this item and update internal state to track the traversal""" + """Search for a sub-command matching this item and update internal state to track the traversal""" # look for sub-command under the current command/sub-command layer for action in self.__current_subcommand_parser._actions: if not action.option_strings and isinstance(action, argparse._SubParsersAction): diff --git a/examples/subcommands.py b/examples/subcommands.py index 02b06412..83c29393 100755 --- a/examples/subcommands.py +++ b/examples/subcommands.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 # coding=utf-8 -"""A simple example demonstrating how to use Argparse to support subcommands. +"""A simple example demonstrating how to use Argparse to support sub-commands. -This example shows an easy way for a single command to have many subcommands, each of which takes different arguments +This example shows an easy way for a single command to have many sub-commands, each of which takes different arguments and provides separate contextual help. """ import argparse @@ -13,15 +13,15 @@ sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] # create the top-level parser for the base command base_parser = argparse.ArgumentParser(prog='base') -base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help') +base_subparsers = base_parser.add_subparsers(title='sub-commands', help='sub-command help') -# create the parser for the "foo" subcommand +# create the parser for the "foo" sub-command parser_foo = base_subparsers.add_parser('foo', help='foo help') parser_foo.add_argument('-x', type=int, default=1, help='integer') parser_foo.add_argument('y', type=float, help='float') parser_foo.add_argument('input_file', type=str, help='Input File') -# create the parser for the "bar" subcommand +# create the parser for the "bar" sub-command parser_bar = base_subparsers.add_parser('bar', help='bar help') bar_subparsers = parser_bar.add_subparsers(title='layer3', help='help for 3rd layer of commands') @@ -31,7 +31,7 @@ bar_subparsers.add_parser('apple', help='apple help') bar_subparsers.add_parser('artichoke', help='artichoke help') bar_subparsers.add_parser('cranberries', help='cranberries help') -# create the parser for the "sport" subcommand +# create the parser for the "sport" sub-command parser_sport = base_subparsers.add_parser('sport', help='sport help') sport_arg = parser_sport.add_argument('sport', help='Enter name of a sport') setattr(sport_arg, 'arg_choices', sport_item_strs) @@ -40,15 +40,15 @@ setattr(sport_arg, 'arg_choices', sport_item_strs) # create the top-level parser for the alternate command # The alternate command doesn't provide its own help flag base2_parser = argparse.ArgumentParser(prog='alternate', add_help=False) -base2_subparsers = base2_parser.add_subparsers(title='subcommands', help='subcommand help') +base2_subparsers = base2_parser.add_subparsers(title='sub-commands', help='sub-command help') -# create the parser for the "foo" subcommand +# create the parser for the "foo" sub-command parser_foo2 = base2_subparsers.add_parser('foo', help='foo help') parser_foo2.add_argument('-x', type=int, default=1, help='integer') parser_foo2.add_argument('y', type=float, help='float') parser_foo2.add_argument('input_file', type=str, help='Input File') -# create the parser for the "bar" subcommand +# create the parser for the "bar" sub-command parser_bar2 = base2_subparsers.add_parser('bar', help='bar help') bar2_subparsers = parser_bar2.add_subparsers(title='layer3', help='help for 3rd layer of commands') @@ -58,7 +58,7 @@ bar2_subparsers.add_parser('apple', help='apple help') bar2_subparsers.add_parser('artichoke', help='artichoke help') bar2_subparsers.add_parser('cranberries', help='cranberries help') -# create the parser for the "sport" subcommand +# create the parser for the "sport" sub-command parser_sport2 = base2_subparsers.add_parser('sport', help='sport help') sport2_arg = parser_sport2.add_argument('sport', help='Enter name of a sport') setattr(sport2_arg, 'arg_choices', sport_item_strs) @@ -66,26 +66,26 @@ setattr(sport2_arg, 'arg_choices', sport_item_strs) class SubcommandsExample(cmd2.Cmd): """ - Example cmd2 application where we a base command which has a couple subcommands - and the "sport" subcommand has tab completion enabled. + Example cmd2 application where we a base command which has a couple sub-commands + and the "sport" sub-command has tab completion enabled. """ def __init__(self): super().__init__() - # subcommand functions for the base command + # sub-command functions for the base command def base_foo(self, args): - """foo subcommand of base command""" + """foo sub-command of base command""" self.poutput(args.x * args.y) def base_bar(self, args): - """bar subcommand of base command""" + """bar sub-command of base command""" self.poutput('((%s))' % args.z) def base_sport(self, args): - """sport subcommand of base command""" + """sport sub-command of base command""" self.poutput('Sport is {}'.format(args.sport)) - # Set handler functions for the subcommands + # Set handler functions for the sub-commands parser_foo.set_defaults(func=base_foo) parser_bar.set_defaults(func=base_bar) parser_sport.set_defaults(func=base_sport) @@ -95,10 +95,10 @@ class SubcommandsExample(cmd2.Cmd): """Base command help""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('base') @cmd2.with_argparser(base2_parser) @@ -106,10 +106,10 @@ class SubcommandsExample(cmd2.Cmd): """Alternate command help""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('alternate') diff --git a/examples/tab_autocomp_dynamic.py b/examples/tab_autocomp_dynamic.py index 2c90b7a2..af77b204 100755 --- a/examples/tab_autocomp_dynamic.py +++ b/examples/tab_autocomp_dynamic.py @@ -25,7 +25,7 @@ def query_actors() -> List[str]: class TabCompleteExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" + """ Example cmd2 application where we a base command which has a couple sub-commands.""" CAT_AUTOCOMPLETE = 'AutoComplete Examples' @@ -225,7 +225,7 @@ class TabCompleteExample(cmd2.Cmd): @cmd2.with_category(CAT_AUTOCOMPLETE) @cmd2.with_argparser(video_parser) def do_video(self, args): - """Video management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" + """Video management command demonstrates multiple layers of sub-commands being handled by AutoCompleter""" func = getattr(args, 'func', None) if func is not None: # Call whatever subcommand function was selected diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py index 6a2e683e..ef283e9e 100755 --- a/examples/tab_autocompletion.py +++ b/examples/tab_autocompletion.py @@ -25,7 +25,7 @@ def query_actors() -> List[str]: class TabCompleteExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" + """ Example cmd2 application where we a base command which has a couple sub-commands.""" CAT_AUTOCOMPLETE = 'AutoComplete Examples' @@ -275,7 +275,7 @@ class TabCompleteExample(cmd2.Cmd): @cmd2.with_category(CAT_AUTOCOMPLETE) @cmd2.with_argparser(video_parser) def do_video(self, args): - """Video management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" + """Video management command demonstrates multiple layers of sub-commands being handled by AutoCompleter""" func = getattr(args, 'func', None) if func is not None: # Call whatever subcommand function was selected @@ -356,7 +356,7 @@ class TabCompleteExample(cmd2.Cmd): @cmd2.with_category(CAT_AUTOCOMPLETE) @cmd2.with_argparser(media_parser) def do_media(self, args): - """Media management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" + """Media management command demonstrates multiple layers of sub-commands being handled by AutoCompleter""" func = getattr(args, 'func', None) if func is not None: # Call whatever subcommand function was selected @@ -457,7 +457,7 @@ class TabCompleteExample(cmd2.Cmd): @cmd2.with_category(CAT_AUTOCOMPLETE) @cmd2.with_argparser(library_parser) def do_library(self, args): - """Media management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" + """Media management command demonstrates multiple layers of sub-commands being handled by AutoCompleter""" func = getattr(args, 'func', None) if func is not None: # Call whatever subcommand function was selected diff --git a/examples/tab_completion.py b/examples/tab_completion.py index 2ec7ff70..77d62988 100755 --- a/examples/tab_completion.py +++ b/examples/tab_completion.py @@ -12,7 +12,7 @@ sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] class TabCompleteExample(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" + """ Example cmd2 application where we a base command which has a couple sub-commands.""" def __init__(self): super().__init__() diff --git a/tests/test_argparse.py b/tests/test_argparse.py index fdd16bcc..f1078e73 100644 --- a/tests/test_argparse.py +++ b/tests/test_argparse.py @@ -179,31 +179,31 @@ def test_arglist_decorator_twice(argparse_app): class SubcommandApp(cmd2.Cmd): - """ Example cmd2 application where we a base command which has a couple subcommands.""" + """ Example cmd2 application where we a base command which has a couple sub-commands.""" def __init__(self): cmd2.Cmd.__init__(self) - # subcommand functions for the base command + # sub-command functions for the base command def base_foo(self, args): - """foo subcommand of base command""" + """foo sub-command of base command""" self.poutput(args.x * args.y) def base_bar(self, args): - """bar subcommand of base command""" + """bar sub-command of base command""" self.poutput('((%s))' % args.z) # create the top-level parser for the base command base_parser = argparse.ArgumentParser(prog='base') - base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help') + base_subparsers = base_parser.add_subparsers(title='sub-commands', help='sub-command help') - # create the parser for the "foo" subcommand + # create the parser for the "foo" sub-command parser_foo = base_subparsers.add_parser('foo', help='foo help') parser_foo.add_argument('-x', type=int, default=1, help='integer') parser_foo.add_argument('y', type=float, help='float') parser_foo.set_defaults(func=base_foo) - # create the parser for the "bar" subcommand + # create the parser for the "bar" sub-command parser_bar = base_subparsers.add_parser('bar', help='bar help') parser_bar.add_argument('z', help='string') parser_bar.set_defaults(func=base_bar) @@ -213,10 +213,10 @@ class SubcommandApp(cmd2.Cmd): """Base command help""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('base') @pytest.fixture diff --git a/tests/test_completion.py b/tests/test_completion.py index 1b7b65d2..d722e534 100644 --- a/tests/test_completion.py +++ b/tests/test_completion.py @@ -784,7 +784,7 @@ def test_cmd2_help_subcommand_completion_nomatch(sc_app): assert first_match is None def test_subcommand_tab_completion(sc_app): - # This makes sure the correct completer for the sport subcommand is called + # This makes sure the correct completer for the sport sub-command is called text = 'Foot' line = 'base sport {}'.format(text) endidx = len(line) @@ -797,8 +797,8 @@ def test_subcommand_tab_completion(sc_app): 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 + # This tests what happens when a sub-command has no completer + # In this case, the foo sub-command has no completer defined text = 'Foot' line = 'base foo {}'.format(text) endidx = len(line) @@ -825,42 +825,42 @@ def test_subcommand_tab_completion_space_in_text(sc_app): class SubcommandsWithUnknownExample(cmd2.Cmd): """ - Example cmd2 application where we a base command which has a couple subcommands - and the "sport" subcommand has tab completion enabled. + Example cmd2 application where we a base command which has a couple sub-commands + and the "sport" sub-command has tab completion enabled. """ def __init__(self): cmd2.Cmd.__init__(self) - # subcommand functions for the base command + # sub-command functions for the base command def base_foo(self, args): - """foo subcommand of base command""" + """foo sub-command of base command""" self.poutput(args.x * args.y) def base_bar(self, args): - """bar subcommand of base command""" + """bar sub-command of base command""" self.poutput('((%s))' % args.z) def base_sport(self, args): - """sport subcommand of base command""" + """sport sub-command of base command""" self.poutput('Sport is {}'.format(args.sport)) # create the top-level parser for the base command base_parser = argparse.ArgumentParser(prog='base') - base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help') + base_subparsers = base_parser.add_subparsers(title='sub-commands', help='sub-command help') - # create the parser for the "foo" subcommand + # create the parser for the "foo" sub-command parser_foo = base_subparsers.add_parser('foo', help='foo help') parser_foo.add_argument('-x', type=int, default=1, help='integer') parser_foo.add_argument('y', type=float, help='float') parser_foo.set_defaults(func=base_foo) - # create the parser for the "bar" subcommand + # create the parser for the "bar" sub-command parser_bar = base_subparsers.add_parser('bar', help='bar help') parser_bar.add_argument('z', help='string') parser_bar.set_defaults(func=base_bar) - # create the parser for the "sport" subcommand + # create the parser for the "sport" sub-command parser_sport = base_subparsers.add_parser('sport', help='sport help') sport_arg = parser_sport.add_argument('sport', help='Enter name of a sport') setattr(sport_arg, 'arg_choices', sport_item_strs) @@ -870,10 +870,10 @@ class SubcommandsWithUnknownExample(cmd2.Cmd): """Base command help""" func = getattr(args, 'func', None) if func is not None: - # Call whatever subcommand function was selected + # Call whatever sub-command function was selected func(self, args) else: - # No subcommand was provided, so call help + # No sub-command was provided, so call help self.do_help('base') @@ -977,7 +977,7 @@ def test_cmd2_help_subcommand_completion_nomatch_scu(scu_app): def test_subcommand_tab_completion_scu(scu_app): - # This makes sure the correct completer for the sport subcommand is called + # This makes sure the correct completer for the sport sub-command is called text = 'Foot' line = 'base sport {}'.format(text) endidx = len(line) @@ -990,8 +990,8 @@ def test_subcommand_tab_completion_scu(scu_app): def test_subcommand_tab_completion_with_no_completer_scu(scu_app): - # This tests what happens when a subcommand has no completer - # In this case, the foo subcommand has no completer defined + # This tests what happens when a sub-command has no completer + # In this case, the foo sub-command has no completer defined text = 'Foot' line = 'base foo {}'.format(text) endidx = len(line) diff --git a/tests/test_pyscript.py b/tests/test_pyscript.py index 36e48598..6b72e940 100644 --- a/tests/test_pyscript.py +++ b/tests/test_pyscript.py @@ -65,7 +65,7 @@ class PyscriptExample(Cmd): @with_argparser(media_parser) def do_media(self, args): - """Media management command demonstrates multiple layers of subcommands being handled by AutoCompleter""" + """Media management command demonstrates multiple layers of sub-commands being handled by AutoCompleter""" func = getattr(args, 'func', None) if func is not None: # Call whatever subcommand function was selected |