Python 帮助文本中的 argparse 参数顺序

Python argparse argument order in help text

我的 Python 程序使用 argparse 模块接受命令行参数并且它按预期工作,但是,帮助文本有点误导,我想为使用我的程序的其他人修复它。

目前,我有一个位置参数,它是一个目录和一个可选参数 -p,它使用 add_argumentnargs=+ 参数接受任意数量的包名称功能。 DIR 位置参数需要在可选参数列表之前指定,否则目录将被错误地添加到包名称列表中,并且会出错,提示没有指定位置参数。帮助输出当前如下所示:

package_info.py --help
usage: package_info.py [-h] [-v] [--no-cache] [-g FILE] [-p [PKG [PKG ...]]]
                       DIR

Get information on packages in ros workspace.

positional arguments:
  DIR                   The directory containing rospackages.

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Enables verbose mode
  --no-cache            Do not cache the dependency graph
  -g FILE, --graph-file FILE
                        The graph file to load from or save to.
  -p [PKG [PKG ...]], --packages [PKG [PKG ...]]
                        The packages to provide information on.

我希望将其格式化为在 -p 标志之前显示 DIR,以便用户更清楚必须首先指定此参数,如下所示:

package_info.py --help
usage: package_info.py DIR [-h] [-v] [--no-cache] [-g FILE] [-p [PKG [PKG ...]]]
            .
            .
            .

package_info.py --help
usage: package_info.py DIR
                       [-h] [-v] [--no-cache] [-g FILE] [-p [PKG [PKG ...]]]
            .
            .
            .

是否有一种简单的方法来格式化帮助消息,或者我是否需要编写自定义帮助消息格式化程序?

你说的是 usage 行。

用法格式化程序确实将 positionals 分开并将它们放在最后,如果足够长,可能在它们自己的行上。是的,确实与处理带有“+”标记的参数冲突。它不应该,但修复太复杂而不能简单地插入。

我不建议更改用法格式化程序 - 这套方法太复杂(而且脆弱),无法轻松修补。

在定义 ArgumentParser 时提供自定义 usage 参数是最简单的解决方法。我不记得它是如何与换行交互的。

查看 后,我能够查看 python3.5 的源代码,argparse 版本 1.1 这是我系统上的版本,并找到了几行我可以修改以使其工作。诚然,这不是一个优雅的解决方案,但很灵活(随着程序的发展,我不断 adding/removing/modifying 命令行参数)并且可以快速实施。

我创建了一个自定义帮助格式化程序 class,它继承自 argparse.HelpFormatter class。在我的自定义 class 中,我复制了 _format_usage 函数并更改了以下行:

# build full usage string
format = self._format_actions_usage
action_usage = format(optionals + positionals, groups)
usage = ' '.join([s for s in [prog, action_usage] if s])

# build full usage string
format = self._format_actions_usage
action_usage = format(positionals + optionals, groups)
usage = ' '.join([s for s in [prog, action_usage] if s])

如果不需要换行,这会提供我需要的格式。

我还更改了以下内容:

# if prog is short, follow it with optionals or positionals
if len(prefix) + len(prog) <= 0.75 * text_width:
    indent = ' ' * (len(prefix) + len(prog) + 1)
    if opt_parts:
        lines = get_lines([prog] + opt_parts, indent, prefix)
        lines.extend(get_lines(pos_parts, indent))
    elif pos_parts:
        lines = get_lines([prog] + pos_parts, indent, prefix)
    else:
        lines = [prog]

# if prog is short, follow it with optionals or positionals
if len(prefix) + len(prog) <= 0.75 * text_width:
    indent = ' ' * (len(prefix) + len(prog) + 1)
    if pos_parts:
        lines = get_lines([prog] + pos_parts, indent, prefix)
        lines.extend(get_lines(opt_parts, indent))
    elif opt_parts:
        lines = get_lines([prog] + opt_parts, indent, prefix)
    else:
        lines = [prog]

这为我提供了需要换行时所需的格式。