summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2.py22
-rwxr-xr-xexamples/subcommands.py58
2 files changed, 78 insertions, 2 deletions
diff --git a/cmd2.py b/cmd2.py
index 378ac097..204e6450 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -292,7 +292,12 @@ def with_argparser_and_unknown_args(argparser):
argparser.description = func.__doc__
cmd_wrapper.__doc__ = argparser.format_help()
+
+ # Mark this function as having an argparse ArgumentParser (used by do_help)
+ cmd_wrapper.__dict__['has_parser'] = True
+
return cmd_wrapper
+
return arg_decorator
@@ -316,7 +321,12 @@ def with_argument_parser(argparser):
argparser.description = func.__doc__
cmd_wrapper.__doc__ = argparser.format_help()
+
+ # Mark this function as having an argparse ArgumentParser (used by do_help)
+ cmd_wrapper.__dict__['has_parser'] = True
+
return cmd_wrapper
+
return arg_decorator
@@ -1198,8 +1208,16 @@ class Cmd(cmd.Cmd):
# Getting help for a specific command
funcname = self._func_named(arglist[0])
if funcname:
- # No special behavior needed, delegate to cmd base class do_help()
- cmd.Cmd.do_help(self, funcname[3:])
+ # Check to see if this function was decorated with an argparse ArgumentParser
+ func = getattr(self, funcname)
+ if func.__dict__.get('has_parser', False):
+ # Function has an argparser, so get help based on all the arguments in case there are sub-commands
+ new_arglist = arglist[1:]
+ new_arglist.append('-h')
+ func(new_arglist)
+ else:
+ # No special behavior needed, delegate to cmd base class do_help()
+ cmd.Cmd.do_help(self, funcname[3:])
else:
# Show a menu of what commands help can be gotten for
self._help_menu()
diff --git a/examples/subcommands.py b/examples/subcommands.py
new file mode 100755
index 00000000..347cb61d
--- /dev/null
+++ b/examples/subcommands.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+# coding=utf-8
+"""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
+and provides separate contextual help.
+"""
+import argparse
+
+import cmd2
+from cmd2 import with_argument_parser
+
+
+class SubcommandsExample(cmd2.Cmd):
+ """ Example cmd2 application where we a base command which has a couple subcommands."""
+
+ def __init__(self):
+ cmd2.Cmd.__init__(self)
+
+ # sub-command functions for the base command
+ def foo(self, args):
+ """foo subcommand of base command"""
+ print(args.x * args.y)
+
+ def bar(self, args):
+ """bar sucommand of base command"""
+ print('((%s))' % args.z)
+
+ # create the top-level parser
+ base_parser = argparse.ArgumentParser(prog='base')
+ base_subparsers = base_parser.add_subparsers(title='subcommands', help='subcommand help')
+
+ # create the parser for the "foo" 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=foo)
+
+ # create the parser for the "bar" command
+ parser_bar = base_subparsers.add_parser('bar', help='bar help')
+ parser_bar.add_argument('z', help='string')
+ parser_bar.set_defaults(func=bar)
+
+ @with_argument_parser(base_parser)
+ def do_base(self, args):
+ """Base command help"""
+ try:
+ # Call whatever sub-command function was selected
+ args.func(self, args)
+ except AttributeError:
+ # No sub-command was provided, so as called
+ self.do_help('base')
+
+
+if __name__ == '__main__':
+ app = SubcommandsExample()
+ app.cmdloop()