使用 argparse 设置真正不需要的子解析器

问题描述 投票:0回答:1

我希望我的程序允许任何字符串作为参数传递,但也允许子命令。例如,这些都是有效的:

$ python argtest.py 'hello world'
$ python argtest.py version
$ python argtest.py help

我不希望用户必须使用

--
,例如
python argparse.py -- 'hello world'

如果我设置一个子命令解析器来处理“版本”和“帮助”,它会抱怨“hello world”不是有效的子命令。

我的代码:

parser = argparse_flags.ArgumentParser()
subparsers = parser.add_subparsers(required=False)
subparsers.add_parser('version')
subparsers.add_parser('help')
ns, remainder = parser.parse_known_args(argv[1:])

产量:

$ python argtest.py 'hello world'
usage: argtest.py [-h] {version,help} ...
argtest.py: error: invalid choice: 'hello world' (choose from 'version', 'help')

我想出的唯一修复方法是创建一个“后备”子命令,然后通过以下任一方式使用

parser.parse_known_args(['fallback'] + argv[1:])
手动添加它:

  • 查找第一个不带“-”前缀的参数,然后查看它是否在
    subparsers.choices
    中。
  • 当没有子解析器匹配时,捕获 argparse 引发的 SystemExit(并临时重定向 stderr,这样它就不会向 CLI 发送垃圾邮件)。

所有这些都有点恶心,有没有更好的方法来获得我想要的行为?我只是希望 argparse 对于找不到子命令更加冷静。

python argparse
1个回答
0
投票

add_subparsers
add_argument
的变体,使用
Action
创建
nargs=argparse.PARSER
子类。

只有

optionals
才能按值选择其
flag
字符串。位置严格按照职位和
nargs
分配。这是在
_get_values
中完成的。对于解析器

 # PARSER arguments convert all values, but check only the first
        elif action.nargs == PARSER:
            value = [self._get_value(action, v) for v in arg_strings]
            self._check_value(action, value[0])

因此

arg_strings
中所有剩余的字符串都被分配。
_get_value
针对
type
进行测试,这里只是通过
str
_check_value
对照
choices
测试该列表中的第一个。

对于子解析器,

choices
是子解析器名称及其别名。所以这就是你的“hello_world”失败的地方。

正如您所注意到的,可以捕获退出错误。最近添加了一个

exit_on_error
参数,该参数将引发错误而不是退出。它并非在所有情况下都有效,但我认为它在这里应该有效。正如文档所述,您还可以调整
error
exit
方法来更改引发错误的方式。

通常,仅当

positional
为“?”时,才不需要
nargs
或者 '*'。由于旧补丁的调整,还有这个“PARSER”案例。如果字符串失败
type
choices
,则没有机制可以重试分配字符串。

如果有多个

positionals
,则以
re
贪婪的方式分配字符串。第一个参数可以获取尽可能多的值,等等。因此,在字符串“+*?”时要小心
nargs
在一起。

总之,我认为如果为主解析器定义一堆

optionals
,然后定义
add_subparsers
操作,子解析器机制效果最好。这样它就可以处理
optionals
(如果有),然后分支到所选的子解析器来处理其余部分。可以为主解析器定义
positional
,但避免开放式
nargs

子解析器的另一件事。在主解析器和子解析器中使用不同的参数

dest
。这样子解析器默认值就不会踩在主解析器默认值上。

© www.soinside.com 2019 - 2024. All rights reserved.