简体   繁体   English

你如何让 argparse 选择一个默认的子解析器?

[英]How do you get argparse to choose a default subparser?

I have the following code in script.py :我在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)

I can call this three different ways:我可以称之为三种不同的方式:

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

There's only one problem with this: what I want is that if I provide zero arguments on the command line is for a_parser to be the one that ends out parsing and doing stuff.这只有一个问题:我想要的是,如果我在命令行上提供零个参数,则a_parser将成为结束解析和执行操作的那个。 Clearly it's not, the sp.default is just setting command='a' , not what I expect, which is to say, "Oh yeah, the user didn't provide any arguments on the command line, but I know that this should be processed by a_parser . Here's Namespace(command='a', thing='thing') !"显然不是, sp.default只是设置command='a' ,不是我所期望的,也就是说,“哦,是的,用户没有在命令行上提供任何参数,但我知道这应该由a_parser处理。这里是Namespace(command='a', thing='thing') !”

Is there a way that I can do this with argparse?有没有一种方法,我可以argparse做到这一点? I've looked for a few different options, but none of them really seem to provide what I'm after.我已经寻找了一些不同的选择,但它们似乎都没有真正提供我所追求的。 I guess I could do some jiggery with making 3 distinct ArgumentParsers and then passing on the arguments to each of them, though that sounds a bit gross.我想我可以通过制作 3 个不同的 ArgumentParsers 然后将参数传递给每个人来做一些麻烦事,尽管这听起来有点恶心。

Any better options?还有更好的选择吗?

First a historical note - subparsers were not optional, and they still aren't in Python2.首先是一个历史记录 - 子解析器不是可选的,它们仍然不在 Python2 中。 The fact that they are optional in Py3 is something of a bug that was introduced several years ago.它们在 Py3 中是可选的这一事实是几年前引入的一个错误。 There was a change in the test for required arguments, and subparsers (a kind of positional) fell through the cracks.所需参数的测试发生了变化,并且子解析器(一种位置)陷入了困境。 If done right you should have had to explicitly set subparsers as not-required.如果做得对,您应该必须明确地将子解析器设置为不需要。

Subparsers don't behave like other non-required arguments, ones with nargs='?'子解析器的行为不像其他非必需参数,即带有nargs='?' or flagged without the required parameter.或标记为没有required参数。

In any case, your sp.default defines the value that will be put in the command dest, but it does not trigger the use of a_parser .在任何情况下,您的sp.default定义了将放入command dest 中的值,但它不会触发a_parser的使用。 That command='a' is never 'evaluated'.command='a'永远不会被“评估”。

The use of parse_known_args might allow you to devaluate the remaining strings with a_parser .采用parse_known_args可能允许您与贬值剩余的字符串a_parser

Without any arguments, we can do:没有任何参数,我们可以这样做:

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

Then conditionally run a_parser (if command is 'a' but no 'thing')然后有条件地运行a_parser (如果命令是 'a' 但没有 'thing')

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

But if I try to include a --thing value:但是,如果我尝试包含一个--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')

It tries to parse the 'ouch' as subparser name.它尝试将“ouch”解析为子解析器名称。 The main parser doesn't known anything about the --thing argument.主解析器对--thing参数--thing

As I explained in the other argparse question today, the toplevel parser parses the inputs until it finds something that fits the 'subparsers' command (or in this example raises an error).正如我在今天的另一个argparse问题中所解释的那样,顶级解析器会解析输入,直到找到适合“子解析器”命令的内容(或者在本示例中引发错误)。 Then it passes the parsing to the subparser.然后它将解析传递给子解析器。 It does not resume parsing after.之后它不会恢复解析。

Add top level argparse arguments after subparser args 在子解析器 args 之后添加顶级 argparse 参数

How to Set a Default Subparser using Argparse Module with Python 2.7 如何在 Python 2.7 中使用 Argparse 模块设置默认子解析器

My answer to this Py2 request might work for you.我对这个 Py2 请求的回答可能对你有用。 I first run a parse_known_args with a parser that doesn't have subparsers, and conditionally run a second parser that handles the subparsers.我第一次运行parse_known_args与不具有subparsers的分析器,并有条件地运行第二解析器处理该subparsers。

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

If extras doesn't have 'a' or 'b' call a_parser (alternatively just look at sys.argv[1:] directly):如果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')

Or modify extras to include the missing subparser command:或者修改extras以包含缺少的 subparser 命令:

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

In any case, optional subparsers is not well developed in argparse .在任何情况下, optional解析器在argparse都没有很好地开发。 It's the side effect of a change made a while back, rather than a well thought out feature.这是前一段时间所做更改的副作用,而不是经过深思熟虑的功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM