如何在argpare解析器中添加更多subparser?

时间:2017-11-04 16:52:08

标签: python python-3.x argparse subparsers

如果我的代码调用的函数返回已经定义了一些子分析符的ArgumentParser,我该如何添加更多的子分析符?

我想做点什么:

parser_with_subparsers = build_parser()
additional_subparsers = parser_with_subparsers.add_subparsers()
extra_subparser = additional_subparsers.add_parser("extra", help="extra help"))

但是当我在翻译中尝试时:

>>> parser_with_subparsers = build_parser()
>>> additional_subparsers = parser_with_subparsers.add_subparsers()
usage: [-h] {original_subparser} ...
: error: cannot have multiple subparser arguments

请注意,我无法访问build_parser()函数的内部。

我能想到的唯一解决方案是使用parents,但这会产生以奇怪的方式对子分析器进行分组的副作用:

>>> child_parser = argparse.ArgumentParser(parents=[build_parser()])
>>> additional_subparsers = child_parser.add_subparsers()
>>> extra_subparser = additional_subparsers.add_parser("extra", help="extra help")
>>> extra_subparser2 = additional_subparsers.add_parser("extra2", help="extra2 help")
>>> child_parser.print_help()
usage: [-h] {original_subparser} ... {extra,extra2} ...

positional arguments:
  {original_subparser}
    original_subparser  original_subparser help
  {extra,extra2}
    extra               extra help
    extra2              extra2 help

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

我想这样做的原因是我想添加额外的命令'到我继承的Argument Parser

1 个答案:

答案 0 :(得分:2)

您期望从添加的子分析符中获得什么样的行为?

sp = parser.add_subparsers(...)

add_subparsers创建_SubParsersAction类的位置参数,并在parser._subparsers属性中记下它。如果已经设置了该属性,则会引发该错误。 spAction个对象。

逻辑上,有一个以上的'subparsers'动作是没有意义的。当主解析器遇到subparser命令时,它会将解析委托给该subparser。除了一些清理错误检查,主解析器不会恢复解析。所以它无法处理第二个subparser命令。

add_subparsers创建的术语和add_parser所做的术语可能令人困惑。一个是位置参数/ Action,另一个是解析器(ArgumentParser的实例)。< / p>

应该可以将新的解析器添加到现有的subparsers动作中(我必须尝试找到一种干净的方法来执行此操作)。也可以添加嵌套子分析器,即为子分析器定义add_subparsers

parents方法绕过此multiple subparser arguments测试,可能是因为它没有第一次设置parser._subparsers属性(从父项复制Actions时)。这实际上创建了两个subparser arguments。这就是help显示的内容。但我的猜测是解析没有意义。它仍然期望'original_subparser'而不是'extra'或'extra2'。

parents机制不健全。它有直接的用途,但它很容易被打破。

In [2]: parser = argparse.ArgumentParser(prog='main')
In [3]: a1 = parser.add_argument('--foo')
In [4]: parser._subparsers    # initial value None

In [5]: sp = parser.add_subparsers(dest='cmd')
In [6]: parser._subparsers    # new non-None value
Out[6]: <argparse._ArgumentGroup at 0xaf780f0c>

sp对象,一个Action子类:

In [8]: sp
Out[8]: _SubParsersAction(option_strings=[], dest='cmd', nargs='A...', const=None, default=None, type=None, choices=OrderedDict(), help=None, metavar=None)
In [9]: sp1 = sp.add_parser('cmd1')

sp是一个Action(位置参数); sp1是一个解析器。

In [10]: parser.print_help()
usage: main [-h] [--foo FOO] {cmd1} ...

positional arguments:
  {cmd1}

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

_actions属性是一系列操作。请注意helpfoo

In [12]: parser._subparsers._actions
Out[12]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help',...),
 _StoreAction(option_strings=['--foo'], dest='foo',....),
 _SubParsersAction(option_strings=[], dest='cmd', ...]

因此,此列表中的最后一项是sp对象

In [13]: parser._subparsers._actions[-1]
Out[13]: _SubParsersAction(option_strings=[], dest='cmd', nargs='A...', const=None, default=None, type=None, choices=OrderedDict([('cmd1', ArgumentParser(prog='main cmd1', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True))]), help=None, metavar=None)

所以我们可以用

添加一个新的subparser
In [14]: parser._subparsers._actions[-1].add_parser('extra')
...
In [15]: parser.print_help()
usage: main [-h] [--foo FOO] {cmd1,extra} ...

positional arguments:
  {cmd1,extra}

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

因此,如果您只想将extraextra2添加到original_subparser,这应该可以。

所以只要我们不进一步尝试parser.add_argument(...)抓住最后一个_actions项应该有效。如果它不是最后一个,我们必须进行更复杂的搜索。

从我的代表变更来看,有人发现了_subparsers属性的早期探索:

How to obtain argparse subparsers from a parent parser (to inspect defaults)

相关问题