如何让argparse选择默认的subparser?

时间:2017-10-26 20:23:20

标签: python argparse

我在script.py中有以下代码:

import argparse

parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='command')
sp.default = 'a'

a_parser = sp.add_parser('a')
b_parser = sp.add_parser('b')

a_parser.add_argument('--thing', default='thing')
b_parser.add_argument('--nothing', default='nothing')

args = parser.parse_args()
print(args)

我可以用三种不同的方式来称呼:

$ python3 script.py
Namespace(command='a')
$ python3 script.py a
Namespace(command='a', thing='thing')
$ python3 script.py b
Namespace(command='b', nothing='nothing')

这只有一个问题:我想要的是,如果我在命令行上提供零参数,那么a_parser就是最终解析的那个并做的事情。显然不是,sp.default只是设置command='a',而不是我期望的,也就是说,"哦是的,用户没有提供任何参数在命令行上,但我知道这应该由a_parser处理。这是Namespace(command='a', thing='thing')!"

可以使用argparse执行此操作吗?我已经找了几个不同的选项,但它们似乎都没有提供我所追求的东西。我想我可以做一些jiggery,制作3个不同的ArgumentParsers,然后将参数传递给每个参数,尽管听起来有点严重。

有更好的选择吗?

1 个答案:

答案 0 :(得分:2)

首先是一个历史记录 - 子分析器不是可选的,它们仍然不在Python2中。它们在Py3中是可选的这一事实是几年前引入的一个bug。所需参数的测试发生了变化,子分析师(一种位置)从裂缝中掉了下来。如果做得好,你必须明确地将subparsers设置为不需要。

Subparsers的行为与其他非必需参数不同,nargs='?'或没有required参数的标记。

在任何情况下,您的sp.default都会定义将放在command目标中的值,但不会触发使用a_parsercommand='a'永远不会被'评估'。

使用parse_known_args可能会让您使用a_parser贬值剩余的字符串。

没有任何论据,我们可以这样做:

In [159]: args, extras = parser.parse_known_args([])
In [160]: args
Out[160]: Namespace(command='a')
In [161]: extras
Out[161]: []

然后有条件地运行a_parser(如果命令是'a'但没有'东西')

In [163]: a_parser.parse_args(extras,namespace=args)
Out[163]: Namespace(command='a', thing='thing')

但是如果我尝试包含--thing值:

In [164]: args, extras = parser.parse_known_args('--thing ouch'.split())
usage: ipython3 [-h] {a,b} ...
ipython3: error: argument command: invalid choice: 'ouch' (choose from 'a', 'b')

它试图将'ouch'解析为subparser名称。主解析器对--thing参数一无所知。

正如我今天在另一个argparse问题中解释的那样,顶层解析器会解析输入,直到找到适合“subparsers”命令的内容(或者在此示例中引发错误)。然后它将解析传递给subparser。它不会在之后恢复解析。

Add top level argparse arguments after subparser args

How to Set a Default Subparser using Argparse Module with Python 2.7

我对这个Py2请求的回答可能对你有用。我首先使用没有subparser的解析器运行parse_known_args,并有条件地运行第二个处理subparser的解析器。

In [165]: firstp = argparse.ArgumentParser()
In [166]: args, extras = firstp.parse_known_args('--thing ouch'.split())
In [167]: args
Out[167]: Namespace()

如果extras没有'a'或'b'来电a_parser(或者只是直接查看sys.argv[1:]):

In [168]: extras
Out[168]: ['--thing', 'ouch']
In [169]: a_parser.parse_args(extras)
Out[169]: Namespace(thing='ouch')

或修改extras以包含缺少的subparser命令:

In [170]: extras = ['a']+extras
In [171]: parser.parse_args(extras)
Out[171]: Namespace(command='a', thing='ouch')

在任何情况下,optional中的argparse子分析器都没有很好地发展。这是改变的副作用,而不是一个经过深思熟虑的功能。