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

时间:2015-11-01 14:09:38

标签: python python-2.7 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

有没有办法实现这个目标?

如何具体两个必需参数,其中一个是子命令,第二个“传播”​​到每个子命令作为必需参数?

2 个答案:

答案 0 :(得分:1)

Parsers可以使用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())

答案 1 :(得分:0)

使用您定义的解析器,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没有出现在subparser的帮助中。那是因为subparse对此一无所知。它是为主解析器定义的。

如果我将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出现在用法中。那是因为在定义subparser时代码知道这个参数。但是 - 在寻求帮助时我必须为CONFIG添加一个值。

(编辑) CONFIG用法中显示cmdA,因为在创建解析器时,它已添加到prog属性中:

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

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

在下文中,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可能是最佳选择。它需要更多输入,但它将显示在正确的帮助中。如果从概念上讲它与命令的关联比主解析器更紧密,那么它需要用它们来定义。所有命令都需要它的事实并不那么重要。

通常,在使用子分析程序时,最好使用主要解析器值(如vebosity和logging)的选项,并在子分配器中定义其余部分。它使解析器之间的工作分工更加清晰。如果需要,我可以详细说明。

没有传播机制。但我当然可以写一个函数,为每个subparser添加一个共同的参数。

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

在交互式shell中运行解析器设置并检查每个命令创建的对象 - parsersubparserscmda_parser等是有益的。参数列表parser知道的(操作对象)位于parser._actions中。

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

还可以尝试:

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

这有助于显示2个解析器的help是独立的。