python ArgParse 自定义操作与使用 metavar 的键值选项导致 -h 输出中的重复

Posted

技术标签:

【中文标题】python ArgParse 自定义操作与使用 metavar 的键值选项导致 -h 输出中的重复【英文标题】:python ArgParse custom action with key value options using metavar causes duplicates in -h output 【发布时间】:2021-12-13 00:22:07 【问题描述】:

我正在使用参数解析器的自定义操作来允许特定参数的 key=value 选项。

test.py --arg2 input1=something input2=something_else

自定义操作工作正常,但是当我使用 metavar 列出所有自定义选项时,我得到了重复项。

这是我的自定义操作:

class KeyValue(argparse.Action):
def __call__(self, parser, namespace,
             values, option_string=None):
    setattr(namespace, self.dest, dict())

    for value in values:
        # split it into key and value
        key, value = value.split('=')
        # assign into dictionary
        getattr(namespace, self.dest)[key] = value

这是使用情况:

    sub_1.add_argument(
        "--arg2",
        action=KeyValue,
        nargs="*",
        default=NoArgumentProvided(),
        help='arg 2 help',
        metavar="key1=val1 key2=val2"
    )

帮助的样子,显示重复:

usage: arg_issue.py test [-h] [--arg1]
                     [--arg2 [key1=val1 key2=val2 [key1=val1 key2=val2 ...]]]

test description

optional arguments:
  -h, --help            show this help message and exit
  --arg1                arg1 help
  --arg2 [key1=val1 key2=val2 [key1=val1 key2=val2 ...]]
                        arg 2 help

任何想法为什么我会得到重复?显然是来自自定义 Action,但我不知道为什么?

完整代码:

import argparse


class NoArgumentProvided(object):
    pass


class KeyValue(argparse.Action):
    def __call__(self, parser, namespace,
                 values, option_string=None):
        setattr(namespace, self.dest, dict())

        for value in values:
            # split it into key and value
            key, value = value.split('=')
            # assign into dictionary
            getattr(namespace, self.dest)[key] = value


def main():
    parser = argparse.ArgumentParser(
        description='parser',
        formatter_class=argparse.RawTextHelpFormatter,
    )

    # top-level args.
    parser.add_argument('--verbose',
                        help='Verbose mode',
                        action='store_true',
                        required=False,
                        default=NoArgumentProvided())
    # Add the main sub parsers
    subparsers = parser.add_subparsers(dest='action')

    sub_1 = subparsers.add_parser(
        'test',
        help='test help',
        description='test description')

    sub_1.add_argument(
        "--arg1",
        action='store_true',
        required=False,
        default=NoArgumentProvided(),
        help='arg1 help'
    )

    sub_1.add_argument(
        "--arg2",
        action=KeyValue,
        nargs="*",
        default=NoArgumentProvided(),
        help='arg 2 help',
        metavar="key1=val1 key2=val2"
    )

    subparsers.required = True

    args = parser.parse_args()


if __name__=="__main__":
    main()

【问题讨论】:

【参考方案1】:

如果元变量是字符串元组

p.add_argument('--foo', nargs='*', metavar=('one','two'))

帮助将是

usage: ipython3 [-h] [--foo [one [two ...]]]

optional arguments:
  -h, --help            show this help message and exit
  --foo [one [two ...]]

nargs='*' 的用法是 2 个部分,[one [two ...]]。使用自定义操作类不会改变显示。

保持metavar 简单,并根据需要在help 中详细说明。 description也可以添加详情。

编辑

几年前的一个补丁简化了* 帮助。

https://bugs.python.org/issue38438 argparse“用法”过于复杂,带有 nargs="*"

使用 Python 3.10

In [218]: import argparse310 as argparse
In [219]: p=argparse.ArgumentParser()
In [220]: p.add_argument('--foo',nargs='*');
In [221]: p.print_help()
usage: ipython3 [-h] [--foo [FOO ...]]

optional arguments:
  -h, --help       show this help message and exit
  --foo [FOO ...]

元组版本仍然可用:

In [226]: p._actions[1].metavar=('one','two')
In [227]: p.print_help()
usage: ipython3 [-h] [--foo [one [two ...]]]

optional arguments:
  -h, --help            show this help message and exit
  --foo [one [two ...]]

【讨论】:

有趣;使用元组的元组作品(更好)。我不明白为什么当 metavar 是一个字符串时我会得到重复项,除非 argparse 中的某些东西试图猜测并将其分解。无论如何,谢谢! 如果 metavar 是字符串,则显示为 --foo [metavar [metavar ...]] 您是说使用字符串时不会复制它吗?这正是我看到的问题。我应该提到这是 2.7 ......当我看到帮助时,给出这个字符串 metavar metavar="key1=val1 key2=val2",它显示为两倍。检查完整的代码。 --arg2 [key1=val1 key2=val2 [key1=val1 key2=val2 ...]] 看到那里的副本了吗?我猜这是预期的?此外,与 nargs="*" 组合时,当 metavar 是一个元组时,我只能给出 2 个项目。 查看我的编辑以获得最近 Python 版本中使用的更简单的显示。 Python 2.7 没有收到这种补丁。 (我的默认 argparse 仍然是 3.8)。

以上是关于python ArgParse 自定义操作与使用 metavar 的键值选项导致 -h 输出中的重复的主要内容,如果未能解决你的问题,请参考以下文章

python内置库--argparse

如何在 argparse 中嵌套自定义参数解析器实例

Python命令行参数处理之argparse模块

python标准库之argparse

python之定义参数模块argparse的基本使用

导致 Python 的 argparse 执行默认操作