当 nargs='*' 时从 argparse 生成更好的帮助

Generating better help from argparse when nargs='*'

与许多命令行工具一样,我的工具接受可选的文件名。 Argparse 似乎通过 nargs='*' 支持这一点,这按预期对我有用:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
        'files',
        help='file(s) to parse instead of stdin',
        nargs='*')

parser.parse_args()

然而,帮助输出很奇怪:

$ ./help.py -h
usage: help.py [-h] [files [files ...]]

如何避免嵌套的可选参数名和重复的参数名?除了 [files ...] 之外,重复不添加任何信息,这是 Unix 上指示可选参数列表的传统方式:

$ grep --help
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
        [-e pattern] [-f file] [--binary-files=value] [--color=when]
        [--context[=num]] [--directories=action] [--label] [--line-buffered]
        [--null] [pattern] [file ...]

$ ls --help
Usage:
  exa [options] [files...]

$ vim --help
Usage:
  nvim [options] [file ...]      Edit file(s)

感谢任何帮助。我正在尝试 argparse,因为使用它似乎是 Python 最佳实践,但此帮助输出对我来说是一个破坏者。

对于 Python 3.9 之前的所有版本:

您可以通过传递 usage="%(prog)s [options]" 字符串 when instantiating ArgumentParser 或更新现有实例的 usage 属性 来覆盖用法行。

如果你想让它生成一个用法字符串,你可以将它与 ArgumentParser.format_usage() 结合使用,但使用正则表达式或字符串替换仅替换 nargs 个选项。

例如:

import argparse
import re

parser = argparse.ArgumentParser()
parser.add_argument(
    'files',
    help='file(s) to parse instead of stdin',
    nargs='*',
)

usage = parser.format_usage()[7:]  # remove "usage: " prefix
parser.usage = re.sub(r'\[(.+?) \[ ...\]\]', r'[ ...]', usage)

parser.parse_args()

生产:

usage: test.py [-h] [files ...]

positional arguments:
  files       file(s) to parse instead of stdin

optional arguments:
  -h, --help  show this help message and exit

这已在 Python 3.9 中修复,参见 https://bugs.python.org/issue38438 and commit a0ed99bc 修复它。

如果 运行 on 3.9:

,您的代码会生成您期望的用法消息
Python 3.9.0 (default, Oct 12 2020, 02:44:01) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('files', help='file(s) to parse instead of stdin', nargs='*')
_StoreAction(option_strings=[], dest='files', nargs='*', const=None, default=None, type=None, choices=None, help='file(s) to parse instead of stdin', metavar=None)
>>> parser.print_help()
usage: [-h] [files ...]