Reputation: 55
I have an argparsing program:
import argparse
def main():
p = argparse.ArgumentParser()
help_str = {'rule': 'Blah blah blah and stuff.'}
p.add_argument('-r', '--rule', action="store", type=str, dest='rule', help=help_str['rule'])
p.set_defaults(rule='string')
args = p.parse_args()
Therefore, my command line input:
username@compname:~$python progname.py -r/--rule 'something'
I am trying to figure out how I could just input:
username@compname:~$python progname.py -r/--rule
and have my own error message come up:
print '\n Error: no input value for rule:'
print ' resetting rule to default value.'
args.rule = 'string'
after this, the rule value should print out as 'string'
I am only slightly fluent in Python, sorry. I have tried using try/except blocks and even sys.argv[2] (though I may have done something wrong.) This is the error that keeps popping up with all of my solutions (not very familiar with errors outside Type and Value):
progname.py: error: argument -r/--rule: expected one argument
Any help appreciated.
Upvotes: 3
Views: 2813
Reputation: 231475
p = argparse.ArgumentParser()
p.add_argument('-r', '--rule', nargs='?', default='string')
args = p.parse_args()
print args
with nargs='?'
produces Namespace(rule='string')
if called without argument. With -r
, args is Namespace(rule=None)
. And Namespace(rule='something')
with -r something
.
Lets add a few lines of code
if args.rule is None:
print '\n Error: no input value for rule:'
print ' resetting rule to default value.'
args.rule = 'string'
print args
Now the output with '-r' (or --rule
) is:
Namespace(rule=None)
Error: no input value for rule:
resetting rule to default value.
Namespace(rule='string')
the other cases are the same.
If I drop the default
; p.add_argument('-r', '--rule', nargs='?')
, the no argument case also produces this custom 'error message', since the default (in argparse) is None
.
It's possible to add custom error checking with a custom type
or action
, but I think testing for None
after using argparse
is simpler, and easier to understand.
I'd suggest changing this error message
to a warning
. An Error usually terminates the program; a warning prints the message and continues.
Here's a solution when nargs=2
(or something else that's fixed). It's not a trivial change, since it involves redefining the error
method (documented near the end of the argparse
docs), and then capturing the error that it produces. The error
method cannot access the Namespace (args), nor can it continue parse_args
. So it cannot handle any other arguments if there is problem with the rule
argument.
class MyParser(argparse.ArgumentParser):
def error(self, message):
if 'rule' in message:
message = 'wrong number of input values for rule'
raise argparse.ArgumentError(None,message)
# cannot access namespace or continue parsing
else:
super(MyParser, self).error(message)
p = MyParser()
p.add_argument('-r', '--rule', nargs=2)
try:
args = p.parse_args()
except argparse.ArgumentError as e:
print e
args = argparse.Namespace(rule='default')
# create a namespace with this default value
print args
Keep in mind that nargs
has 2 purposes:
- raise an error if a wrong number of argument strings is given
- allocate multiple argument strings among multiple Actions (the thing created by add_argument
).
The 2nd is especially evident if you have, for example, several positionals, taking 1,2 and * arguments respectively. It is a key novel feature of argparse, at least relative to earlier Python parsers. While it possible to tweak it, it is hard to completely redefine it.
If the arguments allow it, you could use nargs='*'
instead of the '?', and issue the warning if the number of strings is not '2' (or whatever).
Upvotes: 1