Reputation: 11008
I would like to get the following functionality while using the add_subparsers
method of the argparse
library and without using the keyword argument nargs
:
$ python my_program.py scream Hello
You just screamed Hello!!
$ python my_program.py count ten
You just counted to ten.
I know I could do this:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("cmd", help="Execute a command", action="store",
nargs='*')
args = parser.parse_args()
args_list = args.cmd
if len(args.cmd) == 2:
if args.cmd[0] == "scream":
if args.cmd[1] == "Hello":
print "You just screamed Hello!!"
else:
print "You just screamed some other command!!"
elif args.cmd[0] == "count":
if args.cmd[1]:
print "You just counted to %s." % args.cmd[1]
else:
pass
else:
print "These two commands are undefined"
else:
print "These commands are undefined"
But then when I do $ python my_program.py
I lose that default arparse text that shows a list of arguments etc. .
I know there is an add_subparsers
method of the argparse
library that can handle more than one positional argument but I have not found a way to get it properly working. Could anyone show me how?
Upvotes: 4
Views: 7372
Reputation: 1121524
When using the add_subparsers
you basically are creating a nested parser:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='sub-command help')
parser_scream = subparsers.add_parser('scream', help='scream help')
Now you have a new parser object, that you can add switches to. Or, you can add another level of nesting:
scream_subparsers = parser_scream.add_subparsers(help='scream sub-command help')
parser_scream_hello = scream_subparsers.add_parser('hello', help='scream hello help')
This can go as deep as you need to to control exact formatting. Each level provides help:
>>> parser.print_help()
usage: [-h] {scream} ...
positional arguments:
{scream} sub-command help
scream scream help
optional arguments:
-h, --help show this help message and exit
>>> parser_scream.print_help()
usage: scream [-h] {hello} ...
positional arguments:
{hello} scream sub-command help
hello scream hello help
optional arguments:
-h, --help show this help message and exit
>>> parser_scream_hello.print_help()
usage: scream hello [-h]
optional arguments:
-h, --help show this help message and exit
You can have each end-point call a function, by using set_defaults(func=yourfunction)
on the subparser in question, then using that default func
argument to call the selected function for the current arguments:
>>> def scream_hello(args):
... print "You screamed hello!"
...
>>> parser_scream_hello.set_defaults(func=scream_hello)
>>> parser.parse_args(['scream', 'hello'])
Namespace(func=<function scream_hello at 0x10bd73c80>)
>>> args = parser.parse_args(['scream', 'hello'])
>>> args.func(args)
You screamed hello!
Upvotes: 2
Reputation: 309861
import argparse
def scream(args):
print "you screamed "+' '.join(args.words)
def count(args):
print "you counted to {0}".format(args.count)
parser = argparse.ArgumentParser()
#tell the parser that there will be subparsers
subparsers = parser.add_subparsers(help="subparsers")
#Add parsers to the object that was returned by `add_subparsers`
parser_scream = subparsers.add_parser('scream')
#use that as you would any other argument parser
parser_scream.add_argument('words',nargs='*')
#set_defaults is nice to call a function which is specific to each subparser
parser_scream.set_defaults(func=scream)
#repeat for our next sub-command
parser_count = subparsers.add_parser('count')
parser_count.add_argument('count')
parser_count.set_defaults(func=count)
#parse the args
args = parser.parse_args()
args.func(args) #args.func is the function that was set for the particular subparser
now run it:
>python test.py scream Hello World! #you screamed Hello World!
>python test.py count 10 #you counted to 10
Upvotes: 8