Python argparse AssertionError

Я только начал использовать модуль argparse. Я написал следующий снимок, чтобы продемонстрировать проблему, с которой я сталкиваюсь.

from argparse import ArgumentParser

if __name__ == '__main__':
    parser = ArgumentParser('Test argparse. This string needs to be relatively long to trigger the issue.')
    parser.add_argument('-f', '--fin', help='a', required = True)
    parser.add_argument('-o', '--out ', help='b', required = True)
    parser.add_argument('-t', '--trans', help='c', required = True)

    args = parser.parse_args()
    print(repr(vars(args)))

AssertionError будет производиться, когда script запускается с аргументом -h

Traceback (most recent call last):
  File "arg.py", line 10, in <module>
    args = parser.parse_args()
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1707, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1739, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1945, in _parse_known_args
    start_index = consume_optional(start_index)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1885, in consume_optional
    take_action(action, args, option_string)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1813, in take_action
    action(self, namespace, argument_values, option_string)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 1017, in __call__
    parser.print_help()
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 2341, in print_help
    self._print_message(self.format_help(), file)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 2325, in format_help
    return formatter.format_help()
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 278, in format_help
    help = self._root_section.format_help()
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 208, in format_help
    func(*args)
  File "C:\Users\user\AppData\Local\Continuum\Anaconda\envs\py3k\lib\argparse.py", line 329, in _format_usage
    assert ' '.join(opt_parts) == opt_usage
AssertionError

Уменьшение длины строки описания, переданной в АргументПарсер, заставляет ее работать правильно. Удаление одного из аргументов также поможет.

Я делаю что-то неправильно здесь? Моя среда:

Python 3.3.5 | Anaconda 1.9.2 (64-бит) | (по умолчанию, 10 марта 2014 года, 11:25:04) [MSC v.1600 64 бит (AMD64)] на win32

Ответ 1

В коде есть дополнительное пространство после --out. Изменение:

parser.add_argument('-o', '--out ', help='b', required = True)

в

parser.add_argument('-o', '--out', help='b', required = True)

Основной причиной проблемы является проверка assert внутри Python код, который возникает только тогда, когда Python пытается разбить текст справки на несколько строк, потому что он слишком длинный. После разбиения текста на список, код Python соединяет его вместе и сравнивает его с оригиналом убедитесь, что это правильно. Однако код, который разрывает текст, падает смежные пространства, что приводит к ошибке.

Я добавил отпечатки к коду (argparse.py, Python 2.7):

# wrap the usage parts if it too long
text_width = self._width - self._current_indent
if len(prefix) + len(usage) > text_width:
    # break usage into wrappable parts
    part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
    opt_usage = format(optionals, groups)
    pos_usage = format(positionals, groups)
    opt_parts = _re.findall(part_regexp, opt_usage)
    pos_parts = _re.findall(part_regexp, pos_usage)
    print ' '.join(opt_parts)
    print opt_usage
    assert ' '.join(opt_parts) == opt_usage

И результаты:

[-h] -f FIN -o OUT -t TRANS
[-h] -f FIN -o OUT  -t TRANS
Traceback (most recent call last):
  File "blah.py", line 9, in <module>
    args = parser.parse_args()

Обратите внимание на дополнительное пространство после OUT.

Это объясняет все наблюдаемое поведение:

  • Должно быть достаточно длинным, чтобы вызвать поведение оболочки.
  • Удаление аргумента --trans перенесло --out в конец, отрицая поведение.
  • Удаление аргумента --out отрицает поведение.

Ответ 2

Проблема не в добавлении -h, которое вы добавили. Посмотрите на ошибку и аргумент -o:

assert ' '.join(opt_parts) == opt_usage

он присоединяется к пробелу в '--out '. Если вы его удалите, все должно работать нормально.

Ответ 3

Я пришел сюда с точно такой же проблемой/ошибкой, но без лишних пробелов после --out. Моя проблема заключалась в том, что для metavar была задана пустая строка (metavar=''). Изменение, которое решило проблему.

Ответ 4

Python 3.5.2

Некоторое время это сводило меня с ума, но я наконец нашел проблему. Это определенно проблема длины строки использования, если она превышает COLUMNS среды COLUMNS установленную для консоли/терминала, вы получите эту ошибку. Я пытаюсь из командной строки:

$ COLUMNS=80 python <myprog.py> -h

и я получаю это исключение:

...
  File "/usr/lib/python3.5/argparse.py", line 1735, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/usr/lib/python3.5/argparse.py", line 1767, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/usr/lib/python3.5/argparse.py", line 1973, in _parse_known_args
    start_index = consume_optional(start_index)
  File "/usr/lib/python3.5/argparse.py", line 1913, in consume_optional
    take_action(action, args, option_string)
  File "/usr/lib/python3.5/argparse.py", line 1841, in take_action
    action(self, namespace, argument_values, option_string)
  File "/usr/lib/python3.5/argparse.py", line 1025, in __call__
    parser.print_help()
  File "/usr/lib/python3.5/argparse.py", line 2367, in print_help
    self._print_message(self.format_help(), file)
  File "/usr/lib/python3.5/argparse.py", line 2351, in format_help
    return formatter.format_help()
  File "/usr/lib/python3.5/argparse.py", line 287, in format_help
    help = self._root_section.format_help()
  File "/usr/lib/python3.5/argparse.py", line 217, in format_help
    func(*args)
  File "/usr/lib/python3.5/argparse.py", line 338, in _format_usage
    assert ' '.join(opt_parts) == opt_usage
AssertionError

Но с:

$ COLUMNS=<XX> python <myprog.py> -h

где XX> из полученной строки использования, все в порядке, она печатает использование + справка и выходит. Поэтому вы либо сокращаете строку использования, либо увеличиваете значение COLUMNS.

РЕДАКТИРОВАТЬ:

Я обнаружил ошибку в моем случае: я использовал квадратные скобки [] в описании моей программы/аргументов.

Как правильно отметили другие, глядя на код python, где произошло исключение, вы можете увидеть, что в argparse есть условие для автоматического сворачивания использования/справки в столбцы $COLUMNS. Но чтобы разбить длинные строки, он использует следующее RE:

(Файл "/usr/lib/python3.5/argparse.py", строка 333 :)

'part_regexp = r'\(.*?\)+|\[.*?\]+|\S+''

Когда он присоединяется к строке, чтобы проверить, ввел ли пользователь квадратные скобки, assert завершается неудачей, будучи специальными символами, используемыми argparse для обозначения необязательных значений.

Короче говоря, я удалил квадратные квадратные скобки из своего текста, и все работает нормально, с использованием/справкой, правильно сложенным и отформатированным в соответствии со значением $COLUMNS.

Ответ 5

Для меня это было установка обоих обязательных = True и metavar = ''. Удаление одного и сохранение другого решило это.