Let s assume I have a parser:
import argparse
def int_main():
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))
return 1
if __name__ == '__main__':
int_main()
Assuming the Python code above is saved into a file called prog.py
. If I give it wrong arguments in the command line:
python prog.py a b c
It gives this error message:
usage: prog.py [-h] [--sum] N [N ...]
prog.py: error: argument N: invalid int value: 'a'
In a context of mine, I don't want that error message to be generated, I want for example int_main()
simply to return False if any error raised indicating parsing errors.
How to do that?
I tried :
import argparse
def int_main():
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max,
help='sum the integers (default: find the max)')
try:
args = parser.parse_args()
# print(args.accumulate(args.integers))
except:
return False
return True
if __name__ == '__main__':
res = int_main()
print(res)
but didn't work.
Update
There is a bug it seems:
import argparse
parser = argparse.ArgumentParser(exit_on_error=False)
try:
parser.parse_args('invalid arguments'.split())
except argparse.ArgumentError:
print('ArgumentError caught.')
still exists on error even when set to False, how to fix this? I really want a solution to cover all possible exceptions and never outputs errors, this is because I am doing some unit testing and this can break things
update2
import argparse
def copy_(name1, name2):
return True
def int_main():
parser = argparse.ArgumentParser(prog='blabla',
exit_on_error=False,
argument_default=argparse.SUPPRESS,
add_help=False)
subparsers = parser.add_subparsers(dest="subparser_name", help="")
one_parser = subparsers.add_parser("copy_", help="")
one_parser.add_argument(
dest = "name1",
type = str,
metavar = "NAME1",
)
one_parser.add_argument(
dest = "name2",
type = str,
metavar = "NAME2",
)
one_parser.set_defaults(func=copy_)
try:
args = parser.parse_args()
print(args.func(args.name1, args.name2))
except (SystemExit, SystemError, argparse.ArgumentError):
return False
return True
if __name__ == '__main__':
int_main()
This one still outputs:
usage: blabla copy_ [-h] NAME1 NAME2
blabla copy_: error: the following arguments are required: NAME2
when submitting this command python arg.py copy_ a
. How can we see only False
and not the error message?
Modifying your int_main
to take an argv
parameter which is then passed to parser.parse_args(argv)
, and
redefining the error
method as
In [32]: def myerror(self, message):
...: print('message:', message)
...: print('no usage') # self.print_usage(_sys.stderr)
...: self.exit(2)
...: #args = {'prog': self.prog, 'message': message}
...: #self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
...:
In [33]: argparse.ArgumentParser.error = myerror
Your test case produces:
In [34]: int_main('copy_ a'.split())
message: the following arguments are required: NAME2
no usage
Out[34]: False
and other errors caught by ArgumentError
:
In [35]: int_main(None)
Out[35]: False
In [36]: int_main('copy_ a b'.split())
True
Out[36]: True
In [37]: int_main('foobar a b'.split())
Out[37]: False
This a crude error
replacement, but gives an idea of what might be done.
For unit testing I suspect redirecting stderr
would better than customizing the argparse
method. Be careful about blindly capturing errors. It could hide some serious or unexpected flaws.
Removing the exit_on_error=False
, produces the following 'error' displays:
In [40]: int_main('copy_ a b'.split())
True
Out[40]: True
In [41]: int_main(None)
message: argument subparser_name: invalid choice: 'C:\\Users\\14256\\AppData\\Roaming\\jupyter\\runtime\\kernel-1783dfcfeed2.json' (choose from 'copy_')
no usage
Out[41]: False
In [42]: int_main('foobar a b'.split())
message: argument subparser_name: invalid choice: 'foobar' (choose from 'copy_')
no usage
Out[42]: False
In [43]: int_main('copy_ a b c'.split())
message: unrecognized arguments: c
no usage
Out[43]: False