Python argparse AssertionError

16

我刚开始使用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)))

当使用-h参数运行脚本时,将会产生AssertionError
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

缩短传递给ArgumentParser的描述字符串长度可以使其正常工作。删除一个参数也会有所帮助。 在这里我做错了什么?我的环境是:

Python 3.3.5 |Anaconda 1.9.2 (64-bit)| (default, Mar 10 2014, 11:25:04) [MSC v.1600 64 bit (AMD64)] on win32


2
请注意,ArgumentParser.__init__ 实际上并不接受位置参数。鉴于定义关键字参数的顺序,您正在传递一个非常长的字符串来初始化 prog 属性,该属性旨在存储程序名称,就像它出现在帮助消息中一样。您试图使用该字符串初始化哪个属性? - chepner
2
问题的一部分是您没有正确指定描述字符串。您需要使用关键字参数:parser = ArgumentParser(description='测试argparse。这个字符串需要相对较长才能触发问题。') - khagler
@chepner 我打算设置 description - ohcamel
然后您应该使用 ArgumentParser(description="这里是长字符串") - chepner
5个回答

15

代码中--out后面有一个额外的空格。请更改:

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

to:

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

问题的根本原因是Python代码中的一个assert检查,它只在Python尝试将帮助文本分成多行时才会发生,因为文本太长。将文本拆分成列表后,Python代码将其重新组合并将其与原始文本进行比较以确保正确性。然而,将文本拆分的代码会删除相邻的空格,导致比较失败。
我已经在代码(argparse.py, Python 2.7)中添加了打印语句:
# wrap the usage parts if it's 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参数会否定该行为。

1
我刚刚查看了argparse.py代码。问题与换行有关。因此,一行很长导致了换行,你就遇到了这个问题。一行很短不需要换行,你就没有遇到这个问题。稍后我会添加一些文本来帮助澄清。 - esorton
抱歉,我误删了上面的评论。我最初写道:“有趣的是,描述文本的长度会影响出现次数”。但正如@chepner在主题评论中指出的那样,我实际上并没有设置“description”,而是设置了“prog”属性。 - ohcamel
@hpaulj 感谢您将信息添加到错误报告中。 - esorton
当我遇到这个问题并最终在上面链接的错误报告的评论中找到解决方案时,我在解析此页面的解决方案时遇到了麻烦。为了帮助其他人,直到修补程序被制作出来,这是我的TL;DR修复方法:TL;DR:你构建的ArgumentParser的所有参数(例如:用法、描述等)组合必须适合一行,并且在显示时不换行。在我的情况下,我有大量的参数导致我的“usage”换行。因此,我的解决方法是覆盖“usage”使其更短;然而,这也使它变得不太有用。 - Forrest Bice

9
我也遇到了同样的问题/错误,但没有在 --out 后面添加任何额外的空格。我的问题是 metavar 设置为空字符串 (metavar='')。更改后问题得以解决。

谢谢。我的问题是在一个元变量中有一组方括号。 - joadha
1
metavar=' ' 的定义为特定参数添加了额外的空格,导致解析时出现错误。 - akash
我也遇到了metavar的问题,将其删除后问题得以解决。但是,我仍然非常想摆脱metavar!你有什么想法吗? - skwidbreth

4

对我来说,问题出在同时设置了required=True和metavar=''。移除其中一个并保留另一个解决了问题。


谢谢。它有效。如果有人能够解释为什么这个有效,那将会很有趣。 - aysljc

4
问题不在于您添加的额外-h。看一下错误和-o参数:
assert ' '.join(opt_parts) == opt_usage

它正在将空格加入到'--out'中。如果去掉它,一切都应该正常工作。


3

Python 3.5.2

这个问题曾经让我很困惑,但最终我找到了问题所在。 它肯定是一个使用行长度的问题,如果它超过了控制台/终端设置的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 列的功能。 但是,为了分割长行,它使用以下正则表达式:

(文件“/usr/lib/python3.5/argparse.py”,第333行:)

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

当重新检查时,如果用户输入了方括号,则assert失败,因为它们是argparse用于标记可选值的特殊字符。
简而言之,我从文本中删除了不必要的方括号,现在一切正常,使用/帮助按照$COLUMNS值正确折叠和格式化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接