Reputation: 2067
I have created the following argument parser in my python code.
parser = argparse.ArgumentParser()
parser.add_argument('projectPath')
parser.add_argument('-project')
parser.add_argument('-release')
parser.add_argument('--test', default=False, action='store_true')
args = parser.parse_args()
and I'm executing my program the following way.
myProgram.py /path/to/file -project super --test
it works fine if I use the sysntax above with
args = parser.parse_args()
However if I take and use the sys.argv as input
args = parser.parse_args(sys.argv)
The parser is suddenly picky about the order of the arguments and I get the unrecognized argument error.
usage: fbu.py [-h] [-project PROJECT] [-release RELEASE] [--test] projectPath
fbu.py: error: unrecognized arguments: /path/to/file
As I can see from the error and also using the -h argument. The path argument must be last and the error makes sense in the last example. But why does it not care about the order in the first example ?
EDIT: I'm using python version 3.4.3
Upvotes: 4
Views: 5233
Reputation: 122032
As you can see from looking at the source code for parse_known_args
(which is called by parse_args
):
if args is None:
# args default to the system args
args = _sys.argv[1:]
When you don't provide the arguments explicitly, Python removes the first item from .argv
(which is the name of the script). If you pass the arguments manually, you must do this yourself:
parser.parse_args(sys.argv[1:])
This isn't explicitly covered in the documentation, but note that this section doesn't include a script name when calling parse_args
manually:
Beyond
sys.argv
Sometimes it may be useful to have an
ArgumentParser
parse arguments other than those ofsys.argv
. This can be accomplished by passing a list of strings toparse_args()
. This is useful for testing at the interactive prompt:>>> parser = argparse.ArgumentParser() >>> parser.add_argument( ... 'integers', metavar='int', type=int, choices=xrange(10), ... nargs='+', help='an integer in the range 0..9') >>> parser.add_argument( ... '--sum', dest='accumulate', action='store_const', const=sum, ... default=max, help='sum the integers (default: find the max)') >>> parser.parse_args(['1', '2', '3', '4']) Namespace(accumulate=<built-in function max>, integers=[1, 2, 3, 4]) >>> parser.parse_args('1 2 3 4 --sum'.split()) Namespace(accumulate=<built-in function sum>, integers=[1, 2, 3, 4])
The advantage of passing the arguments manually is that it makes it easier to test the parsing functionality, as you can pass in a list of appropriate arguments rather than trying to patch sys.argv
.
Upvotes: 4
Reputation: 522110
sys.argv
contains the script name as the first item, i.e. myProgram.py
. That argument takes the spot of projectPath
. Now there's one additional positional argument /path/to/file
, which can't be matched to any arguments, hence the error.
Calling parse_args
without arguments ArgumentParser
is clever enough to omit the script name from being parsed. But when explicitly passing an array of arguments, it can't do that and will parse everything.
Upvotes: 5