2013-03-28 2 views
3

Я определил пользовательский тип регулярного выражения для аргумента, который должен следовать точному формату. Я использовал код из другого сообщения (regex custom type), который был очень полезен. Моя проблема заключается в том, что я пишу модульные тесты, где ожидаю, что регулярное выражение не сработает, и попытаюсь утверждать, что argparse.ArgumentError поднят (assertRaises(argparse.ArgumentError, parser.parse_args(inargs.split()))). Проблема в том, что argparse, похоже, захватывает ArgumentError и бросает общую ошибку, не позволяя мне проверить причину сбоя. Я что-то упускаю?Python: после поднятия argparse.ArgumentError, argparse вызывает общую ошибку

Вот отслеживающий:

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 

Вот мой определенный пользовательский тип и код парсера:

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.") 

Вот тест блок:

# Fail for ending colon 
    inargs = "-s out=i[one[id1]:]" 
    self.assertRaises(argparse.ArgumentError, parser.parse_args(inargs.split())) 
+0

Argparse поднимает 'SystemExit', потому что это то, что инструмент командной строки должен делать; верните код выхода системы при ошибке. –

+0

Можете ли вы уточнить? Я бы не рассматривал argparse инструмент командной строки, поскольку он является модулем python. Как и в любом модуле, я бы ожидал, что смогу «поймать» ошибки argparse и обработать их самостоятельно. –

+0

Это библиотека для * создания * инструментов командной строки. Я добавил ответ. –

ответ

3

Argparse является синтаксический анализатор командной строки и ошибки всегда заканчиваются вызовом argparse.exit(), который, в свою очередь, вызывает sys.exit() с кодом ошибки. Это по дизайну.

Для проведения единичного теста вам необходимо будет обезвреживать (используя насмешливо) .error() или методы анализатора .exit(). .error() вызывается с сообщением об ошибке и печатает сообщение об использовании, затем вызывает .exit() с кодом выхода и сообщением об ошибке.

Их текущая реализация:

# =============== 
# 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)) 
+0

Очень полезно, спасибо! –

Смежные вопросы