This is clearly an awkward specification for argparse
, and I suspect most other POSIX style parsers.
Scanning sys.argv
and adjusting the parser definition is one possible way.
Another is to use a 2 stage parser, with parse_known_args
:
import argparse
usage = 'prog [-h] [--simulation] [arg1 arg2 arg3 arg4]'
parser1 = argparse.ArgumentParser(usage=usage)
parser1.add_argument('--simulation', action='store_true')
# or omit the `store_true` if it just takes one argument
# other possible optionals
parser2 = argparse.ArgumentParser()
#parser2.add_argument("arg1", type = bool) # not a valid type parameter
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
# positionals are required, unless nargs=? or *
args, extras = parser1.parse_known_args()
if not args.simulation:
args = parser2.parse_args(extras, namespace=args)
elif extras:
parser1.error('cannot use --simulation with args')
print(args)
Possible runs include:
1526:~/mypy$ python stack41556997.py -h
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
optional arguments:
-h, --help show this help message and exit
--simulation
1526:~/mypy$ python stack41556997.py --simulation
Namespace(simulation=True)
1527:~/mypy$ python stack41556997.py 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', simulation=False)
1527:~/mypy$ python stack41556997.py 1 2 3 --sim
usage: prog [-h] [--simulation] [arg1 arg2 arg3 arg4]
stack41556997.py: error: cannot use --simulation with args
Note that the help does not include both sets. I included some information in the custom usage, but there are not help lines for the arg#
. Generating a good help
message is going to be awkward with your specification.
I skipped your arg1
. type=bool
is not a valid type
argument. See my explanation at Parsing boolean values with argparse
I changed --simulation
to store_true
since you said it didn't take any arguments. That's the normal way of accepting True/False.
Subparsers is often the best tool for accepting different patterns of arguments. In this case you could have one subparser called 'simulate' that doesn't require any arguments, and another call 'somethingelse' that requires the 4 positionals.
I was going to suggest a mutually_exclusive_group with --simulation
and --other
optionals. But a store_true
argument does not work in such a group.
=============
The subparser route:
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='cmd')
sp.add_parser('simulate')
parser2 = sp.add_parser('other')
parser2.add_argument("arg2" )
parser2.add_argument("arg3", type = int)
parser2.add_argument("arg4")
print(parser.parse_args())
testing:
1552:~/mypy$ python stack41556997.py -h
usage: stack41556997.py [-h] {simulate,other} ...
positional arguments:
{simulate,other}
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py simulate
Namespace(cmd='simulate')
1557:~/mypy$ python stack41556997.py other -h
usage: stack41556997.py other [-h] arg2 arg3 arg4
positional arguments:
arg2
arg3
arg4
optional arguments:
-h, --help show this help message and exit
1557:~/mypy$ python stack41556997.py other 1 2 3
Namespace(arg2='1', arg3=2, arg4='3', cmd='other')
Note that the arg3
type
converted the input to an integer. The others are left as strings. With this set up args.cmd
will be the name of the subparser, not quite the same as a boolean args.simulation
attribute.
==================
A flagged argument is not-required by default. Positional arguments are required unless the nargs
value is '?' or '*'. You can't provide a 'required' parameter to a positional.