argparse 子命令和组:在自己的组上的子命令中设置帮助对话框,而不隐藏在***帮助对话框中

Posted

技术标签:

【中文标题】argparse 子命令和组:在自己的组上的子命令中设置帮助对话框,而不隐藏在***帮助对话框中【英文标题】:argparse sub-commands and groups: Setting help-dialog in sub-command on its own group without being hidden in top-level help-dialog 【发布时间】:2021-12-06 13:30:51 【问题描述】:

我正在尝试实现一个程序,它同时使用子命令(例如:程序子命令 [options])和组(这使得一个花哨的帮助对话框)。

我已经实现了这个目标,但有一个小例外:为了在自己的组中获得帮助对话框,我必须在创建子命令解析器时添加标志 add_help=False,这会在运行顶部时删除帮助消息-级别帮助对话框(例如:program -h)。

这是我开发的代码:

# imports
import argparse

# create the top-level parser
parser = argparse.ArgumentParser(prog="example", add_help=False, epilog="A very cool program")

# add top-level groups
toplevel = parser.add_argument_group("Global arguments")
toplevel.add_argument("-g", "--global", action="store_true", help="A global argument.")

help = parser.add_argument_group("Help dialog")
help.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# create subparser
subparsers = parser.add_subparsers(title="Available subcommands", dest="subcommand")

# create the parser for the "a" subcommand
parser_a = subparsers.add_parser("a", add_help=False)

# add groups for subcommand "a"
required_a = parser_a.add_argument_group("Required arguments")
required_a.add_argument("--bar", type=int, help="Flag bar help", required=True)

help_a = parser_a.add_argument_group("Help dialog")
help_a.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# create the parser for the "b" command
parser_b = subparsers.add_parser("b", add_help=False)

# add groups for subcommand "b"
required_b = parser_b.add_argument_group("Required arguments")
required_b.add_argument("--baz", help="Flag baz help", required=True)

optional_b = parser_b.add_argument_group("Optional arguments")
optional_b.add_argument("--tas", help="Flag tas help")

help_b = parser_b.add_argument_group("Help dialog")
help_b.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# parse arguments
args = parser.parse_args()

# provide args to main
print(args)

顶层帮助如下:

$ example -h
usage: example [-g] [-h] a,b ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available sub-commands:
  a,b

A very cool program

如您所见,子命令上没有显示帮助消息。 为了让它们出现,我必须在创建 parser_aparser_b 时去掉 add_help=False,但正如预期的那样,当我定义自己的帮助标志时会引发问题。

基本上我希望两全其美,我的主要对话将是:

$ example -h
usage: example [-g] [-h] a,b ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available sub-commands:
  a,b
    a           Help for sub-command a.
    b           Help for sub-command b.

A very cool program

子命令是:

$ example a -h
usage: example a --bar BAR [-h]

Required arguments:
  --bar BAR   Flag bar help

Help dialog:
  -h, --help  Show this help message and exit.

在浏览了 argparse 源代码后,选项conflict_handler 是一个可能的解决方案吗?是否可以告诉它忽略原始帮助对话框,该对话框显示在我不想要的位置参数下,而是显示在我自己的组中但不完全禁用它?

TL;DR: 寻找我的 Python 脚本所需的修改,以便 argparse 输出前两个代码块。

注意:标题之所以写“help-dialog”是因为堆栈溢出不允许我在标题上写世界“帮助”,不管写在哪里在句子中。

【问题讨论】:

使用正常的子解析器设置,example -h 将显示主解析器的组和子命令(subparsers 实际上是主解析器的位置参数)。 example a -h,将解析传递给parser_a,然后它又响应-h,显示它自己的组。主解析器对子解析器的参数一无所知,对子解析器也是如此。 我想你的“帮助对话框”替代品的行为方式相同,但我不能肯定地说。目前尚不清楚您缺少什么或期望什么。 我已经编辑了帖子以使自己更清楚,因为 cmets 中的字符限制非常低。我期望的是在主帮助对话框的子命令部分下方有一条帮助消息,并且在子命令帮助对话框中,将帮助命令放在它自己的组中。由于某种原因,这很难解释,但如果你看到最后两个代码块,那正是我想要实现的。 【参考方案1】:

您的代码生成:

1138:~/mypy$ python3 stack69633930.py -h
usage: example [-g] [-h] a,b ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available subcommands:
  a,b

A very cool program
1140:~/mypy$ python3 stack69633930.py a -h
usage: example a --bar BAR [-h]

Required arguments:
  --bar BAR   Flag bar help

Help dialog:
  -h, --help  Show this help message and exit.

借助常规帮助

1140:~/mypy$ python3 stack69633930-1.py -h
usage: example [-h] [-g] a,b ...

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

Global arguments:
  -g, --global  A global argument.

Available subcommands:
  a,b

A very cool program
1142:~/mypy$ python3 stack69633930-1.py a -h
usage: example a [-h] --bar BAR

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

Required arguments:
  --bar BAR   Flag bar help

我看到的唯一区别是“帮助对话框”组而不是“可选参数”,以及 [-h] 在用法中的位置。

要获得子命令的“帮助”:

1155:~/mypy$ python3 stack69633930-1.py -h
usage: example [-h] [-g] a,b ...

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

Global arguments:
  -g, --global  A global argument.

Available subcommands:
  a,b
    a           help for subcommand a
    b           help for subcommand b

A very cool program

添加

parser_a = subparsers.add_parser("a", help='help for subcommand a')

这也适用于您的帮助组。

===

add_parser 方法以一种特殊的方式处理“帮助”关键字。 “add_help”传递给ArgumentParser 创建函数。它们具有非常不同的功能。

def add_parser(self, name, **kwargs):
    # set prog from the existing prefix
    if kwargs.get('prog') is None:
        kwargs['prog'] = '%s %s' % (self._prog_prefix, name)

    aliases = kwargs.pop('aliases', ())

    # create a pseudo-action to hold the choice help
    if 'help' in kwargs:
        help = kwargs.pop('help')
        choice_action = self._ChoicesPseudoAction(name, aliases, help)
        self._choices_actions.append(choice_action)

    # create the parser and add it to the map
    parser = self._parser_class(**kwargs)
    self._name_parser_map[name] = parser

    # make parser available under aliases also
    for alias in aliases:
        self._name_parser_map[alias] = parser

    return parser

【讨论】:

不同之处在于您忘记添加help="something",而不是仅仅从parser_a = subparsers.add_parser("a", add_help=False) 中删除add_help=False。如果添加help="something" 对话框并删除add_help=False,您将看到使用全局-h 时,您将在“可用子命令:”部分中获得相同的帮助消息,在本例中为“某物”。也许我的要求并没有我想的那么具体。 add_help=False 是子解析器本身的参数。 help='something' is used by the subparsers` 操作。 是的,但它也显示在***帮助对话框中,如果提供,则在“可用子命令”下,这就是我的全部观点:让它显示在***帮助对话框的“可用子命令”和在子命令帮助对话框中时在其自己的组中。 我在您的子命令 hlep 对话框中看不到那个“东西”。 “a help for subcommand a”行与subpareser_a显示的帮助无关 我使用在线编译器来举例说明我的意思,转到https://trinket.io/python3/d21a721232,当你运行脚本时,你会看到子命令右侧有一个帮助对话框,在“可用的子命令:”部分。现在尝试通过注释掉第 24、25、37 和 38 行,将子命令中的帮助对话框添加到它自己的组中。如果再次运行脚本,它会给你一个错误。这很难用语言来解释,所以也许这让我想要实现的目标更加清晰。

以上是关于argparse 子命令和组:在自己的组上的子命令中设置帮助对话框,而不隐藏在***帮助对话框中的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 python argparse 解析多个嵌套的子命令?

子命令中选项的 argparse 冲突解决程序将关键字参数转换为位置参数

带有子命令的命令和子命令请求的 argparse 解决方案

在子解析器 args 之后添加*** argparse 参数

带有嵌套命名空间的 argparse 子命令

如何根据使用 dplyr 的组上的聚合函数计算新列(在汇总统计信息上添加汇总统计信息)?