Get selected subcommand with argparse
When I use subcommands with python argparse, I can get the selected arguments.
parser = argparse.ArgumentParser()
parser.add_argument('-g', '--global')
subparsers = parser.add_subparsers()
foo_parser = subparsers.add_parser('foo')
foo_parser.add_argument('-c', '--count')
bar_parser = subparsers.add_parser('bar')
args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
# args => Namespace(global='xyz', count='42')
So args
doesn't contain 'foo'
. Simply writing sys.argv[1]
doesn't work beca开发者_如何转开发use of the possible global args. How can I get the subcommand itself?
The very bottom of the Python docs on argparse sub-commands explains how to do this:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-g', '--global')
>>> subparsers = parser.add_subparsers(dest="subparser_name") # this line changed
>>> foo_parser = subparsers.add_parser('foo')
>>> foo_parser.add_argument('-c', '--count')
>>> bar_parser = subparsers.add_parser('bar')
>>> args = parser.parse_args(['-g', 'xyz', 'foo', '--count', '42'])
>>> args
Namespace(count='42', global='xyz', subparser_name='foo')
You can also use the set_defaults()
method referenced just above the example I found.
ArgumentParser.add_subparsers
has dest
formal argument described as:
dest
- name of the attribute under which sub-command name will be stored; by defaultNone
and no value is stored
In the example below of a simple task function layout using subparsers, the selected subparser is in parser.parse_args().subparser
.
import argparse
def task_a(alpha):
print('task a', alpha)
def task_b(beta, gamma):
print('task b', beta, gamma)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser')
parser_a = subparsers.add_parser('task_a')
parser_a.add_argument(
'-a', '--alpha', dest='alpha', help='Alpha description')
parser_b = subparsers.add_parser('task_b')
parser_b.add_argument(
'-b', '--beta', dest='beta', help='Beta description')
parser_b.add_argument(
'-g', '--gamma', dest='gamma', default=42, help='Gamma description')
kwargs = vars(parser.parse_args())
globals()[kwargs.pop('subparser')](**kwargs)
Just wanted to post this answer as this came in very handy in some of my recent work. This method makes use of decorators (although not used with conventional @ syntax) and comes in especially handy if the recommended set_defaults
is already being used with subparsers.
import argparse
from functools import wraps
import sys
def foo(subparser):
subparser.error('err')
def bar(subparser):
subparser.error('err')
def map_subparser_to_func(func, subparser):
@wraps(func)
def wrapper(*args, **kwargs):
return func(subparser, *args, **kwargs)
return wrapper
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
foo_parser = subparsers.add_parser('foo')
foo_parser.set_defaults(func = map_subparser_to_func(foo, foo_parser))
bar_parser = subparsers.add_parser('bar')
bar_parser.set_defaults(func = map_subparser_to_func(bar, bar_parser))
args = parser.parse_args(sys.argv[1:])
args.func()
The map_subparser_to_func
function can be modified to set the subparser to some class attribute or global variable inside of the wrapper
function instead of passing it directly and can also be reworked to a conventional decorator for the functions, although that would require adding another layer.
This way there is a direct reference to the object.
精彩评论