分组 argparse 子命令参数

6

我有一个脚本,其中包含多个命令,每个命令都有自己的一组必需和/或可选参数,通过使用add_subparser来实现。

=->test.py -h
usage: test.py [-h] <command> ...

positional arguments:
  <command>   Available Commands
    cmd1      Command 1
    cmd2      Command 2
    cmd3      Command 3
    cmd4      Command 4

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


=->test.py cmd1 -h
usage: test.py cmd1 [-h] --flag1 FLAG1

optional arguments:
  -h, --help     show this help message and exit
  --flag1 FLAG1  Test flag


=->test.py cmd2 -h
usage: test.py cmd2 [-h] [--flag2 FLAG2]

optional arguments:
  -h, --help     show this help message and exit
  --flag2 FLAG2  Test flag

我希望能够将这些命令分成几组,以便用户看到类似于以下内容:

=->test.py -h
usage: test.py [-h] <command> ...

First Group:
  cmd1      Command 1
  cmd2      Command 2

Second Group:
  cmd3      Command 3
  cmd4      Command 4

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

但是,add_argument_group和add_subparsers似乎不能同时使用。

有什么方法可以实现这个目的吗?

2个回答

10

你是正确的,参数组和子解析器不能一起使用。这是因为子解析器(或者说它们的名称)不是参数。

sp = parser.add_subparsers(...) 命令创建了一个参数,或者严格来说是 argparse.Action 的子类实例。这是一个位置参数。 add_parser 命令创建了一个 parser 对象(即调用 argparse.ArgumentParser),并将其连同其名称(和别名)添加到由此操作拥有的字典中。名称填充到 Action 的 choices 属性中。

这个 subparsers 操作可以属于参数组,但由于只能有一个这样的操作,它不能帮助您对帮助文本进行分组。

您可以通过使用描述并省略子解析器的帮助来在某种程度上控制帮助。

import argparse

description = """
First Group:
  cmd1      Command 1
  cmd2      Command 2

Second Group:
  cmd3      Command 3
  cmd4      Command 4"""

parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
sp = parser.add_subparsers(title='commands',description=description)
sp.add_parser('cmd1')
sp.add_parser('cmd2')
sp.add_parser('cmd3')
sp.add_parser('cmd4')

parser.print_help()

产生

1343:~/mypy$ python stack32017020.py 
usage: stack32017020.py [-h] {cmd1,cmd2,cmd3,cmd4} ...

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

commands:

  First Group:
    cmd1      Command 1
    cmd2      Command 2

  Second Group:
    cmd3      Command 3
    cmd4      Command 4

  {cmd1,cmd2,cmd3,cmd4}

http://bugs.python.org/issue9341 - 允许将argparse子命令分组

谈论如何实现所需功能。我提出的补丁不是微不足道的,但欢迎您测试它。


我正在使用Python 3.6,这个程序“几乎”可以运行。在你的示例输出下面仍有原始帮助输出的其余部分。你有什么想法可以抑制它吗? - Nathan Stocks
我知道这是一个旧评论,但对于任何发现这个问题的人,将help=argparse.SUPPRESS添加到parser.add_subparsers()中可以隐藏描述下面的命令(Python 3.9,尚未检查其他版本) - ohthatgeoff

0
我遇到了这个问题,并通过在父解析器中创建一个组和一个函数来解决它,在该函数中,为给定子解析器的每个子解析器创建一个虚拟组,并将虚拟组对象替换为所需的组对象,同时保留其地址,因此该组确实属于每个子解析器!
以下是带有一些上下文的示例:
import argparse
import ctypes


parent_parser = argparse.ArgumentParser(description="Redacted")

subparsers = parent_parser.add_subparsers()

subparser_email = subparsers.add_parser("email", parents=[parent_parser], add_help=False)
subparser_gen = subparsers.add_parser("gen", parents=[parent_parser], add_help=False)

group_emails = subparser_email.add_argument_group("Main inputs")
group_gen = subparser_gen.add_argument_group("Emails generation")
group_matchers = parent_parser.add_argument_group("Matchers") # The group we want on each subparser

[...] # add the arguments to your groups here

def add_group_to_subparsers(group: argparse._ArgumentGroup, subparsers: argparse._SubParsersAction, name: str):
    for name, subparser in subparsers._name_parser_map.items():
        dummy_group = subparser.add_argument_group(name)
        ctypes.memmove(id(dummy_group), id(group), object.__sizeof__(dummy_group))

add_group_to_subparsers(group_matchers, subparsers, "Matchers")

parent_parser.parse_args()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接