I'm using pythons(2.7.2) argparse (1.1) to parse command line and what I want is to create subparser and make it possible to enter subparser commands multiple times. Like this:
./script.py version 1 --file 1 2 3 version 3 --file 4 5 6
Is it possible to create such thing? Because now when I try to run script with such arguments in result namespase a get:
Namespace(file=['4', '5', '6'], n=[1])
n it is a version number. So I get first version number and second list of files instead both file lists and versions.
Python argparse optional argument The module is imported. An argument is added with add_argument . The action set to store_true will store the argument as True , if present. The help option gives argument help.
required is a parameter of the ArugmentParser object's function add_argument() . By default, the arguments of type -f or --foo are optional and can be omitted. If a user is required to make an argument, they can set the keyword argument required to True .
Using the nargs parameter in add_argument() , you can specify the number (or arbitrary number) of inputs the argument should expect. In this example named sum.py , the --value argument takes in 3 integers and will print the sum.
parse_args() returns two values: options, an object containing values for all of your options— e.g. if "--file" takes a single string argument, then options. file will be the filename supplied by the user, or None if the user did not supply that option.
To the main parser, the subparsers argument is a positional that takes choices. But it also allocates ALL of the remaining argument strings to the subparser.
I expect that your string is parsed as follows:
./script.py version 1 --file 1 2 3 version 3 --file 4 5 6
version
is accepted as a subparser name. 1
is accepted as value to positional argument n
. (of the subparser). --file
is accepted as a optional argument (by the subparser). The values from the second invocation overwrite the values from the first. I'm guessing --file
has nargs='*'
. If so, the first one writes ['1','2','3','version','3']
to the namespace, while the second overwrites it with ['4','5','6']
. If nargs=3
, I would expect the subparser to choke on the second version
, which it would see as an unknown positional.
So the basic point is - once the 'version' subparser gets the argument list, it does not let go until it has parsed everything it can. In this case it parses both --file
occurrences. Anything it can't handle comes back to the main parser as 'UNKNOWNS', which normally raises an error.
If you want values from repeated optionals, use an append action
parser.add_argument('--foo',action='append', nargs=3)
import argparse
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='version')
spp = sp.add_parser('version')
spp.add_argument('n',nargs='*',type=int)
spp.add_argument('--file',nargs=3,action='append')
str = 'version 1 --file 1 2 3 version 3 --file 4 5 6'
print(parser.parse_known_args(str.split()))
produces
(Namespace(file=[['1', '2', '3'], ['4', '5', '6']], n=[1], version='version'), ['version', '3'])
Still only one call to version
subparser, but all the data is present.
A different approach would be to nest subparsers
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='sub')
spp = sp.add_parser('version')
spp.add_argument('n',nargs=1,type=int)
spp.add_argument('--file',nargs=3)
sp = spp.add_subparsers(dest='sub1')
spp = sp.add_parser('version')
spp.add_argument('n1',nargs=1,type=int)
spp.add_argument('--file',dest='file1',nargs=3)
str = 'version 1 --file 1 2 3 version 3 --file 4 5 6'
print(parser.parse_args(str.split()))
Note that I have to change the 'dest' to avoid over writing values. This produces
Namespace(file=['1', '2', '3'], file1=['4', '5', '6'], n=[1], n1=[3], sub='version', sub1='version')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With