The optparse module already comes in the Python standard library. So why would you want to use argparse instead? Here’s a few of the many reasons:
The following sections discuss some of these points and a few of the other advantages of the argparse module.
The argparse module supports optional and positional arguments in a manner similar to the optparse module:
>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo', help='optional foo')
>>> parser.add_argument('bar', help='positional bar')
>>> values = parser.parse_args('--foo spam badger'.split())
>>> values.foo
'spam'
>>> values.bar
'badger'
Some of the important differences illustrated here:
The argparse module doesn’t try to dictate what your command line interface should look like. You want single dashes but long option names? Sure! You want to use '+' as a flag character? Sure! You want required options? Sure!
>>> parser = argparse.ArgumentParser(prog='PROG', prefix_chars='-+')
>>> parser.add_argument('-foo')
>>> parser.add_argument('+bar', required=True)
>>> parser.parse_args('-foo 1 +bar 2'.split())
Namespace(bar='2', foo='1')
>>> parser.parse_args('-foo X'.split())
usage: PROG [-h] [-foo FOO] +bar BAR
PROG: error: argument +bar is required
With optparse, if you don’t supply a usage string, you typically end up with "PROG [options]" displayed for usage. Since the ArgumentParser objects know both your optional and positional arguments, if you don’t supply your own usage string, a reasonable one will be derived for you:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-w', choices='123', help='w help')
>>> parser.add_argument('-x', nargs='+', help='x help')
>>> parser.add_argument('y', nargs='?', help='y help')
>>> parser.add_argument('z', nargs='*', help='z help')
>>> parser.parse_args('-x 2 3 -w 1 a b c d'.split())
Namespace(w='1', x=['2', '3'], y='a', z=['b', 'c', 'd'])
>>> parser.print_help()
usage: PROG [-h] [-w {1,2,3}] [-x X [X ...]] [y] [z [z ...]]
positional arguments:
y y help
z z help
optional arguments:
-h, --help show this help message and exit
-w {1,2,3} w help
-x X [X ...] x help
As you may have noticed in the previous section, the argparse module adds a number of useful new specifiers for the nargs keyword argument:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', nargs='?', const='X')
>>> parser.add_argument('-y', nargs='+')
>>> parser.add_argument('z', nargs='*')
>>> parser.parse_args('-y 0.5 -x'.split())
Namespace(x='X', y=['0.5'], z=[])
>>> parser.parse_args('-y 0.5 -xA 0 1 1 0'.split())
Namespace(x='A', y=['0.5'], z=['0', '1', '1', '0'])
In particular argparse supports:
By default, a single argument is accepted. For everything but '?' and the default, a list of values will be produced instead of single value.
With optparse, dispatching to subparsers required disallowing interspersed args and then manually matching arg names to parsers. With the argparse module, sub-parsers are supported through the add_subparsers() method. The add_subparsers() method creates and returns a positional argument that exposes an add_parser method from which new named parsers can be created:
>>> # create the base parser with a subparsers argument
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--bar')
>>> subparsers = parser.add_subparsers()
>>> # add a sub-command "abc"
>>> parser_abc = subparsers.add_parser('abc')
>>> parser_abc.add_argument('-a', action='store_true')
>>> parser_abc.add_argument('--b', type=int)
>>> parser_abc.add_argument('c', nargs=2)
>>> # add a sub-command "xyz"
>>> parser_xyz = subparsers.add_parser('xyz')
>>> parser_xyz.add_argument('--x', dest='xxx')
>>> parser_xyz.add_argument('-y', action='store_const', const=object)
>>> parser_xyz.add_argument('z', choices='123')
>>> # parse, using the subcommands
>>> parser.parse_args('abc --b 2 AA BB'.split())
Namespace(a=None, b=2, bar=None, c=['AA', 'BB'])
>>> parser.parse_args('--bar B xyz -y 3'.split())
Namespace(bar='B', xxx=None, y=<type 'object'>, z='3')
>>> parser.parse_args('xyz --b 42'.split())
usage: PROG xyz [-h] [--x XXX] [-y] {1,2,3}
PROG xyz: error: no such option: --b
Note that in addition to all the usual arguments that are valid to the ArgumentParser constructor, the add_parser method of a sub-parsers argument requires a name for the parser. This is used to determine which parser is invoked at argument parsing time, and to print a more informative usage message.
The argparse module allows any callable that takes a single string argument as the value for the type keyword argument:
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('x', type=float)
>>> parser.add_argument('y', type=complex)
>>> parser.add_argument('z', type=file)
>>> parser.parse_args('0.625 4j argparse.py'.split())
Namespace(x=0.625, y=4j, z=<open file 'argparse.py', mode 'r' at 0x...>)
For most users, you’ll never need to specify a type in string form again.
The argparse module allows a more easily extensible means of providing new types of parsing actions. The easiest way of generating such a new action is to extend argparse.Action and override the __init__() and __call__() methods as necessary:
>>> class FooAction(argparse.Action):
... def __init__(self, foo, **kwargs):
... super(FooAction, self).__init__(**kwargs)
... self.foo = foo
... def __call__(self, parser, namespace, value, option_string=None):
... setattr(namespace, self.dest, self.foo % value)
...
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-x', action=FooAction, foo='xfoox(%s)')
>>> parser.add_argument('y', action=FooAction, foo='fyoyo(%s)')
>>> parser.parse_args('42'.split())
Namespace(x=None, y='fyoyo(42)')
>>> parser.parse_args('42 -x 0'.split())
Namespace(x='xfoox(0)', y='fyoyo(42)')
The ArgumentParser constructs your action object when add_argument() is called, and passes on the arguments it received. Thus if you need more than the usual dest, nargs, etc., simply declare it in your __init__() method and provide a value for it in the corresponding call.
In optparse, the choices keyword argument accepts only a list of strings. The argparse module allows choices to provide any container object, and tests the arg string values against this container after they have been type-converted:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-x', nargs='+', choices='abc')
>>> parser.add_argument('-y', type=int, choices=xrange(3))
>>> parser.add_argument('z', type=float, choices=[0.5, 1.5])
>>> parser.parse_args('-x a c -y 2 0.5'.split())
Namespace(x=['a', 'c'], y=2, z=0.5)
>>> parser.parse_args('1.0'.split())
usage: PROG [-h] [-x {a,b,c} [{a,b,c} ...]] [-y {0,1,2}] {0.5,1.5}
PROG: error: argument z: invalid choice: 1.0 (choose from 0.5, 1.5)
Note that if choices is supplied for an argument that consumes multiple arg strings, each arg string will be checked against those choices.
The argparse module allows you to construct simple inheritance hierarchies of parsers when it’s convenient to have multiple parsers that share some of the same arguments:
>>> foo_parser = argparse.ArgumentParser(add_help=False)
>>> foo_parser.add_argument('--foo')
>>> bar_parser = argparse.ArgumentParser(add_help=False)
>>> bar_parser.add_argument('bar')
>>> foo_bar_baz_parser = argparse.ArgumentParser(
... parents=[foo_parser, bar_parser])
>>> foo_bar_baz_parser.add_argument('--baz')
>>> foo_bar_baz_parser.parse_args('--foo 1 XXX --baz 2'.split())
Namespace(bar='XXX', baz='2', foo='1')
If you end up with a lot of parsers (as may happen if you make extensive use of subparsers), the parents argument can help dramatically reduce the code duplication.
Both default values and help strings can be suppressed in argparse. Simply provide argparse.SUPPRESS to the appropriate keyword argument:
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--secret', help=argparse.SUPPRESS)
>>> parser.add_argument('-d', default=argparse.SUPPRESS)
Note that when help for an argument is suppressed, that option will not be displayed in usage or help messages:
>>> parser.print_help()
usage: PROG [-h] [-d D]
optional arguments:
-h, --help show this help message and exit
-d D
And when a default is suppressed, the object returned by parse_args() will only include an attribute for the argument if the argument was actually present in the arg strings:
>>> parser.parse_args('--secret value'.split())
Namespace(secret='value')
>>> parser.parse_args('-d value'.split())
Namespace(d='value', secret=None)
Originally, the argparse module had attempted to maintain compatibility with optparse. However, optparse was difficult to extend transparently, particularly with the changes required to support the new nargs= specifiers and better usage messges. When most everything in optparse had either been copy-pasted over or monkey-patched, it no longer seemed worthwhile to try to maintain the backwards compatibility.
A partial upgrade path from optparse to argparse: