Reputation: 75
I'm writing a REPL that has meta commands. The meta commands can take options and arguments, and I'm trying to use argparse to handle them. As such, I don't want to exit the program entirely if a user doesn't use the command correctly. At most, I'd like to print a usage message and continue the REPL. Here is the basic idea of what I'm trying:
import argparse
p = argparse.ArgumentParser(exit_on_error=False)
p.add_argument('foo')
try:
p.parse_args([]) # I want to catch the case of a user not supplying a required positional arg
except argparse.ArgumentError:
print("error detected")
However, running the above snippet gives me this (and exits right after):
usage: test.py [-h] foo
test.py: error: the following arguments are required: foo
The Python 3.9 documentation says this:
Normally, when you pass an invalid argument list to the
parse_args()
method of anArgumentParser
, it will exit with error info.If the user would like to catch errors manually, the feature can be enabled by setting
exit_on_error
toFalse
:
It could be that I'm misunderstanding what an "invalid argument list" means (and the example given in the docs certain works), but I would think that an empty argument list would apply in this case.
I realize there are other ways to handle this (and I've successfully tested one or two of them), but I just want to make sure that I'm not missing something with the exit_on_error
parameter. That said, does anyone have any idea why this is not working?
Upvotes: 5
Views: 2336
Reputation: 231375
That parameter deals with only one category of error, that raised with handling a particular argument. The test for required arguments is handled differently, and isn't diverted by this parameter. I suspect this has been raised on the Python bug/issues, but I haven't paid a lot of attention to it. Changing the parser.error
or parser.exit
methods works for both categories of error.
Upvotes: 7
Reputation: 17411
It's a known issue. Unlikely to be fixed soon based on discussions.
... the real issue here is the library was used too much by the users ..... We either keep the old "wrong" behavior, or break users existing code.
For me this was causing my tests to fail. I worked around by patching the ArgumentParser.exit()
method.
@pytest.mark.parametrize("args", [
'',
'--junk-kw',
'--junk-kw-with-val 123',
'junk-positional',
])
def test_invalid_args(self, args):
"""tests all validations done by argparse"""
with pytest.raises(argparse.ArgumentError), mock.patch(
'my.module.argparse.ArgumentParser.exit',
side_effect=argparse.ArgumentError(None, '')
):
my_module.MyClass().parse_args(*args.split())
Upvotes: 3