如何使用 'argparse' 指定两个必需的参数,包括一个子命令?

How do I specify two required arguments, including a subcommand, using 'argparse'?

有没有办法在 argparse 中指定两个必需的参数,一个对应于一个子命令,另一个是所有子命令都需要的。

我能做到的最接近的似乎是

import argparse

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='', dest='command',  metavar='COMMAND', title='required arguments',
                                   description='two arguments are required')
parser.add_argument('config', metavar='CONFIG', action='store', help='the config to use')

cmda_parser = subparsers.add_parser('cmdA',  help='a first command')
cmdb_parser = subparsers.add_parser('cmdB',  help='the second operation')
cmdc_parser = subparsers.add_parser('cmdC',  help='yet another thing')

print(parser.parse_args())

这给出了

usage: enigma.py [-h] COMMAND ... CONFIG

positional arguments:
  CONFIG      the config to use

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

required arguments:
  two arguments are required

  COMMAND
    cmdA      a first command
    cmdB      the second operation
    cmdC      yet another thing

和未显示的子命令的帮助 CONFIG;但我想要的是

usage: enigma.py [-h] COMMAND CONFIG

required arguments:
  two arguments are required

  COMMAND
    cmdA      a first command
    cmdB      the second operation
    cmdC      yet another thing

  CONFIG      the config to use

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

以及每个显示 CONFIG 的子命令的帮助,例如

usage: enigma.py cmdA CONFIG [-h] 

    required arguments:

      CONFIG      the config to use

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

有什么方法可以做到这一点吗?

如何指定两个个必需的参数,其中一个是子命令,第二个"propagated"作为每个子命令的必需参数?

对于您定义的解析器,COMMANDCONFIG 都是必需的。举个例子

python myprog cmdA

你应该得到一个遗漏的参数错误。在较新的版本上它将是明确的

0826:~/mypy$ python3.5 stack33463052.py cmdA 
usage: stack33463052.py [-h] COMMAND ... CONFIG
stack33463052.py: error: the following arguments are required: CONFIG

但是,是的,COMMAND 没有出现在子解析器的帮助中。那是因为子解析对此一无所知。它是为主解析器定义的。

如果我将 CONFIG 定义移动到 subparsers 创建之前,我得到:

0833:~/mypy$ python stack33463052.py tst cmdA -h
usage: stack33463052.py CONFIG cmdA [-h]

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

现在CONFIG出现在用法中。那是因为代码在定义子解析器时知道这个参数。但是 - 在寻求帮助时,我必须包含 CONFIG 的值。


(编辑) CONFIG 出现在 cmdA 用法中,因为它是在创建解析器时添加到它的 prog 属性中的:

 print(cmda_parser.prog)
 'stack33463052.py CONFIG cmdA'

但是如果稍后将参数添加到 parser,则 prog 不会被修改。


在下文中,cmdA 被用作 CONFIG 的参数,而不是 COMMAND,因此我得到了默认的主解析器帮助。

0833:~/mypy$ python stack33463052.py cmdA -h
usage: stack33463052.py [-h] CONFIG COMMAND ...

positional arguments:
  CONFIG      the config to use

optional arguments:
...

对于主解析器来说,CONFIGCOMMAND 都是必需的位置。 COMMAND 没有什么特别之处,只是它定义了 3 个 choices

为每个子解析器定义 CONFIG 可能是最佳选择。它需要更多的输入,但它会显示在正确的帮助中。如果从概念上讲它 link 比主解析器更接近于命令,那么它需要用它们来定义。所有命令都需要它这一事实并不那么重要。

一般来说,在使用子解析器时,最好对主要解析器值(如 vebosity 和日志记录)使用可选值,并在子解析器中定义其余部分。它使解析器之间的工作分配更加清晰。如果需要,我可以详细说明。

没有传播机制。但我当然可以编写一个函数,为每个子解析器添加一个公共参数。

def foo(subparsers, *args, **kwargs):
   sub = subparsers.add_parser(*args, **kwargs)
   sub.add_argument('config')
   return sub

这对 运行 在交互式 shell 中设置解析器并检查每个命令创建的对象很有指导意义 - parsersubparserscmda_parser,等等。 parser 知道的参数列表(Action 对象)在 parser._actions 中。

argparse 模块中的程序清晰简洁意味着 parsercmda_parser 是不同的 ArgumentParser 对象。一个不仅仅是另一个的模式或方法。 subparsers 对象(Action 子类)是 parsercmda_parser 之间唯一正式的 link。

也试试:

parser.print_help() # or parser.print_usage()
cmda_parser.print_help()

这有助于表明 2 个解析器的 help 是独立的。

解析器可以 "inherit" 来自另一个解析器的参数,使用 parents 属性。

import argparse

parser = argparse.ArgumentParser()

# Put common subparser arguments here. Each sub parser will have
# its own -h option, so disable it on the shared base.
subbase = argparse.ArgumentParser(add_help=False)
subbase.add_argument('config', metavar='CONFIG', action='store', help='the config to use')

subparsers = parser.add_subparsers(help='', dest='command',  metavar='COMMAND', title='required arguments',
                                   description='two arguments are required')

# Add subbase to the parent list for each subparser.
cmda_parser = subparsers.add_parser('cmdA', parents=[subbase],  help='a first command')
cmdb_parser = subparsers.add_parser('cmdB', parents=[subbase], help='the second operation')
cmdc_parser = subparsers.add_parser('cmdC', parents=[subbase], help='yet another thing')

print(parser.parse_args())