Reputation: 401
I have a program that works like this:
prog.py filename -r
Uses default default values given by me
prog.py filename -r 0 500 20
Uses 0, 500 and 20
I've managed to achieve this using:
class RdistAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
if not values:
setattr(namespace,self.dest,[0, 1000, 50])
else:
setattr(namespace,self.dest,values)
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--rdist", action=RdistAction, nargs='*', type=int)
args = parser.parse_args()
But I want to be stubborn, as my original goal was to have nargs set to 3. But when I use nargs=3 in the above code, I get an error message stating that 3 arguments were expected.
I've googled around, and from the results my gut tells me that I have to add def __init__
and modify something in that function. Is it possible to get the same results I get in the above code when nargs='*'
, but with nargs=3
instead?
Upvotes: 11
Views: 10385
Reputation: 231375
As I pointed out in your previous question, simply omitting the -r
puts the default
in the args Namespace. You don't have to do anything special.
nargs='?'
has a third option, const
.
Your custom action acts a bit like this, in that it assigns a custom value to the Namespace when -r
was used without any strings.
Parsing goes roughly as:
Action.__call__
values
passed depends on the nargs
parameterYour custom RdistAction
has no control over the number of values
, except via its nargs
attribute. nargs=3
means exactly 3, nargs='*'
means 'as many as you can give me' (i.e. 0 or to the end or to the next flag).
In optparse
an Action is give all the remaining argv
strings, and can consume as many as it wants. But in argparse
, the allocation is done at a higher level, and the Action uses what it's given.
I have explored in Python bug/issue expanding nargs
to include regex
like ranges, e.g. [0,3]
. But that requires changes to the core of the parser.
You still haven't explained why you need this bare -r
option.
Upvotes: 0
Reputation: 5983
If I change your add_argument
line to have nargs='3'
, I think I get the error you're taking about:
Traceback (most recent call last):
File "python", line 12, in <module>
ValueError: length of metavar tuple does not match nargs
If I set nargs=3
(without the quotes), then it works for me:
import argparse
class RdistAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
if not values:
setattr(namespace,self.dest,[0, 1000, 50])
else:
setattr(namespace,self.dest,values)
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--rdist", action=RdistAction, nargs=3, type=int)
print parser.parse_args('-r 0 500 20'.split())
gives
Namespace(rdist=[0, 500, 20])
Is that what you're looking for?
The trick here is that if nargs isn't one of the special characters ('?', '*', '+', etc), then it needs to be an integer, not a string.
Note that the documentation does point this out.
Upvotes: 24