Python3 Argparse metavar括号奇怪地解析了

时间:2015-01-30 11:32:15

标签: python-3.x formatting argparse brackets

我在python3中使用argparse,我得到一些奇怪的东西:

我使用的简短版代码是:

argparser = argparse.ArgumentParser(description='add/remove items')
argparser.add_argument('-a', action='append',     metavar="Item(s)", help='add one or more items to the list')
argparser.add_argument('-r', action='append',     metavar="Item(s)", help='remove one or more items from the list')
args = argparser.parse_args()

当我使用-h标志运行脚本时,我得到了这个输出:

usage: test.py [-h] [-a Items)] [-r Item(s]

add/remove items

optional arguments:
  -h, --help  show this help message and exit
  -a CPE(s)   add one or more items to the list
  -r CPE(s)   remove one or more items from the list

注意第一行中括号的奇怪解析。

是什么导致这种情况,我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

你的metavars中的()导致了错误的使用。使用格式化程序使用()标记需要互斥的组,然后删除多余的组。因此,它会尝试保留( -o | -t),但将(-o)更改为-o。不幸的是,代码不区分它添加的代码和通过metavar(或帮助代码行)添加的代码。

您的广告格式为:

usage: test.py [-h] [-a Item(s)] [-r Item(s)]

但它删除了我已用*:

替换的外部()
usage: test.py [-h] [-a Item*s)] [-r Item(s*]

http://bugs.python.org/issue11874侧重于不同的使用问题,当使用行很长并需要拆分时会出现问题。但该问题的最后两篇文章涉及这个问题。

如果您不喜欢自动usage格式的限制,可以为parser提供自己的自定义usage参数。

答案 1 :(得分:1)

因为您希望有多个项目的可能性。使用argparse的另一种方法如下:

import argparse
argparser = argparse.ArgumentParser(description='add/remove items')
argparser.add_argument('-a', metavar="item", nargs="*", help='add one or more items to the list')
argparser.add_argument('-r', metavar="item", nargs="*", help='remove one or more items from the list')
args = argparser.parse_args()

关键是使用nargs="*"(0个或更多个参数)。帮助变为:

usage: test.py [-h] [-a [item [item ...]]] [-r [item [item ...]]]

这样,您不必使用“Item(s)”,也可以遵循标准做法。

PS :我明白你想做什么。使用action="append",您实际上允许用户指定多个-a-r选项。在这种情况下,您绝对应该写"Item"(而不是“Item(s)”),因为每个选项都需要一个项目。这也解决了您的问题(您的帮助消息应该表明可以提供多个-a-r选项。)

答案 2 :(得分:0)

我在python 2.7中的解决方案是重写argparse.format_usage()和argparse.format_help()。您对元变量进行编码,然后在argparse对其进行格式化后对其进行解码:

FIXES = (('\[', '%lb'), ('\]', '%rb'), ('\(', '%lp'), ('\)', '%rp'))
def encode_parens(text):
    for orig, encoded in FIXES:
        text = re.sub(orig, encoded, text)
    return text
def decode_parens(text):
    for orig, encoded in FIXES:
        text = re.sub(encoded, orig[1:], text)
    return text

class MyArgParser(argparse.ArgumentParser):
    def __init__(self, *args, **kwargs):
        super(MyArgParser, self).__init__(*args, **kwargs)
    def format_usage(self, *args, **kwargs):
        u = super(MyArgParser, self).format_usage(*args, **kwargs)
        return decode_parens(u)
    def format_help(self, *args, **kwargs):
        h = super(MyArgParser, self).format_help(*args, **kwargs)
        return decode_parens(h)

if __name__ == '__main__':
    argparser = MyArgParser(description='add/remove items')
    argparser.add_argument('-a', action='append', metavar=encode_parens("Item(s)"), help='add one or more items to the list')
    argparser.add_argument('-r', action='append', metavar=encode_parens("Item(s)"), help='remove one or more items from the list')
    args = argparser.parse_args()

这产生了您想要的:

usage: arg.py [-h] [-a Item(s)] [-r Item(s)]

它还修复了方括号,argparse也不喜欢。