Getting the remaining arguments in argparse
I want to get all the remaining unused arguments at once. How do I do it?
parser.add_argument('-i', action='store', dest='i', default='i.log')
parser.add_argument('-o', action='store', dest='o', default='o.log')
Use parse_known_args()
:
args, unknownargs = parser.parse_known_args()
Use argparse.REMAINDER
:
parser.add_argument('rest', nargs=argparse.REMAINDER)
Example:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='store', dest='i', default='i.log')
parser.add_argument('-o', action='store', dest='o', default='o.log')
parser.add_argument('rest', nargs=argparse.REMAINDER)
parser.parse_args(['hello', 'world'])
>>> Namespace(i='i.log', o='o.log', rest=['hello', 'world'])
I went and coded up the three suggestions given as answers in this thread. The test code appears at the bottom of this answer. Conclusion: The best all-around answer so far is nargs=REMAINDER
, but it might really depend on your use case.
Here are the differences I observed:
(1) nargs=REMAINDER
wins the user-friendliness test.
$ python test.py --help
Using nargs=* : usage: test.py [-h] [-i I] [otherthings [otherthings ...]]
Using nargs=REMAINDER : usage: test.py [-h] [-i I] ...
Using parse_known_args : usage: test.py [-h] [-i I]
(2) nargs=*
quietly filters out the first --
argument on the command line, which seems bad. On the other hand, all methods respect --
as a way to say "please don't parse any more of these strings as known args."
$ ./test.py hello -- -- cruel -- -- world
Using nargs=* : ['hello', '--', 'cruel', '--', '--', 'world']
Using nargs=REMAINDER : ['hello', '--', '--', 'cruel', '--', '--', 'world']
Using parse_known_args : ['hello', '--', '--', 'cruel', '--', '--', 'world']
$ ./test.py -i foo -- -i bar
Using nargs=* : ['-i', 'bar']
Using nargs=REMAINDER : ['--', '-i', 'bar']
Using parse_known_args : ['--', '-i', 'bar']
(3) Any method except parse_known_args
dies if it tries to parse a string beginning with -
and it turns out not to be valid.
$ python test.py -c hello
Using nargs=* : "unrecognized arguments: -c" and SystemExit
Using nargs=REMAINDER : "unrecognized arguments: -c" and SystemExit
Using parse_known_args : ['-c', 'hello']
(4) nargs=REMAINDER
completely stops parsing when it hits the first unknown argument. parse_known_args
will gobble up arguments that are "known", no matter where they appear on the line (and will die if they look malformed).
$ python test.py hello -c world
Using nargs=* : "unrecognized arguments: -c world" and SystemExit
Using nargs=REMAINDER : ['hello', '-c', 'world']
Using parse_known_args : ['hello', '-c', 'world']
$ python test.py hello -i world
Using nargs=* : ['hello']
Using nargs=REMAINDER : ['hello', '-i', 'world']
Using parse_known_args : ['hello']
$ python test.py hello -i
Using nargs=* : "error: argument -i: expected one argument" and SystemExit
Using nargs=REMAINDER : ['hello', '-i']
Using parse_known_args : "error: argument -i: expected one argument" and SystemExit
Here's my test code.
#!/usr/bin/env python
import argparse
import sys
def using_asterisk(argv):
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='i', default='i.log')
parser.add_argument('otherthings', nargs='*')
try:
options = parser.parse_args(argv)
return options.otherthings
except BaseException as e:
return e
def using_REMAINDER(argv):
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='i', default='i.log')
parser.add_argument('otherthings', nargs=argparse.REMAINDER)
try:
options = parser.parse_args(argv)
return options.otherthings
except BaseException as e:
return e
def using_parse_known_args(argv):
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='i', default='i.log')
try:
options, rest = parser.parse_known_args(argv)
return rest
except BaseException as e:
return e
if __name__ == '__main__':
print 'Using nargs=* : %r' % using_asterisk(sys.argv[1:])
print 'Using nargs=REMAINDER : %r' % using_REMAINDER(sys.argv[1:])
print 'Using parse_known_args : %r' % using_parse_known_args(sys.argv[1:])
Another option is to add a positional argument to your parser. Specify the option without leading dashes, and argparse
will look for them when no other option is recognized.
This has the added benefit of improving the help text for the command:
>>> parser.add_argument('otherthings', nargs='*')
>>> parser.parse_args(['foo', 'bar', 'baz'])
Namespace(i='i.log', o='o.log', otherthings=['foo', 'bar', 'baz'])
and
>>> print parser.format_help()
usage: ipython-script.py [-h] [-i I] [-o O] [otherthings [otherthings ...]]
positional arguments:
otherthings
optional arguments:
-h, --help show this help message and exit
-i I
-o O