问题
I defined a custom regex type for an argument that needs to follow an exact format. I used code from another post (regex custom type) that has been super useful. My problem is that I'm writing unit tests where I expect the regex to fail and trying to assert that the argparse.ArgumentError
is raised ( assertRaises(argparse.ArgumentError, parser.parse_args(inargs.split()))
). The problem is that argparse appears to be catching the ArgumentError and throwing a generic error, preventing me from verifying the cause of the failure. Am I missing something?
Here is the traceback:
Error
Traceback (most recent call last):
File "/Users/markebbert/PyCharmProjects/newproject/unittests.py", line 203, in test_set_operation_parameter
self.assertRaises(argparse.ArgumentError, parser.parse_args(inargs.split()))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1688, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1727, in parse_known_args
self.error(str(err))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 2347, in error
self.exit(2, _('%s: error: %s\n') % (self.prog, message))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 2335, in exit
_sys.exit(status)
SystemExit: 2
Here is my defined custom type and the parser code:
class RegexValidator(object):
"""
Performs regular expression match on value.
If match fails an ArgumentError is raised
"""
def __init__(self, pattern, statement=None):
self.pattern = re.compile(pattern)
self.statement = statement
if not self.statement:
self.statement = "must match pattern %s" % self.pattern
def __call__(self, string):
match = self.pattern.search(string)
if not match:
raise argparse.ArgumentError(None, self.statement)
return string
operatorRV = RegexValidator(
"^((\w+)=)?[iIuUcC]\[(\w+(\[\w+(,\w+)*\])?)(:\w+(\[\w+(,\w+)*\])?)*\]$",
"Set operations must conform to...")
parser = argparse.ArgumentParser(
description='Compare variants across individuals',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
group.add_argument('-s', '--set-operation', dest='operation', nargs='+',
type=operatorRV,
help="blah.")
Here is the unit test:
# Fail for ending colon
inargs = "-s out=i[one[id1]:]"
self.assertRaises(argparse.ArgumentError, parser.parse_args(inargs.split()))
回答1:
Argparse is a command line parser, and errors always end up calling argparse.exit()
, which in turn calls sys.exit()
with an error code. This is by design.
For a unit test, you'd have to monkeypatch (using mocking perhaps) the .error()
or the .exit()
methods of the parser. .error()
is called with an error message and prints the usage message, then calls .exit()
with an exit code and the error message.
Their current implementations:
# ===============
# Exiting methods
# ===============
def exit(self, status=0, message=None):
if message:
self._print_message(message, _sys.stderr)
_sys.exit(status)
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
If you override this in a subclass, it should not return -- it
should either exit or raise an exception.
"""
self.print_usage(_sys.stderr)
self.exit(2, _('%s: error: %s\n') % (self.prog, message))
来源:https://stackoverflow.com/questions/15691762/python-after-raising-argparse-argumenterror-argparse-raises-generic-error