summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2018-10-05 13:39:37 -0400
committerGitHub <noreply@github.com>2018-10-05 13:39:37 -0400
commit9fee6105210b36201b5d2edc610f20bd67eac9f2 (patch)
tree5879270409a4992622da2933275ccaae30525ee6
parent49cbec9969b4b53248d6097d8f395d92c74f7228 (diff)
parent734796b895bb85d67c651d9e8e8bf71e7d60b7e3 (diff)
downloadcmd2-git-9fee6105210b36201b5d2edc610f20bd67eac9f2.tar.gz
Merge pull request #568 from python-cmd2/sub-command
Using sub-command instead of subcommand where possible to be consistent with argparse
-rw-r--r--CHANGELOG.md2
-rwxr-xr-xcmd2/argparse_completer.py7
-rw-r--r--cmd2/cmd2.py24
-rw-r--r--cmd2/pyscript_bridge.py2
-rwxr-xr-xexamples/subcommands.py42
-rwxr-xr-xexamples/tab_autocomp_dynamic.py4
-rwxr-xr-xexamples/tab_autocompletion.py8
-rwxr-xr-xexamples/tab_completion.py2
-rw-r--r--tests/test_argparse.py18
-rw-r--r--tests/test_completion.py36
-rw-r--r--tests/test_pyscript.py2
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