【问题标题】:argparse: How to separate unknown(and optional) args when subparsers are present.(subparsers are also optional)argparse:当存在子解析器时如何分离未知(和可选)参数。(子解析器也是可选的)
【发布时间】:2019-05-04 18:05:30
【问题描述】:

我有以下代码

parser = argparse.ArgumentParser(allow_abbrev=False, add_help=False)
parser.add_argument('--conf', nargs=1)
parser.add_argument('-h', '--help', nargs='?', const='generic')
parser.add_argument('-v', '--version', action="store_true")

subparsers = parser.add_subparsers()
subparsers.required = False
parser_start = subparsers.add_parser('start')
group1 = parser_start.add_mutually_exclusive_group()
group1.add_argument('--quiet', action="store_true")
group1.add_argument('-V', '--verbose', nargs="*")

# parser_console = subparsers.add_parser('console')

print(argv)
parsed_args = parser.parse_known_args(argv)

现在,当我将argv 传递为argv = ['abc', 'def']argv = ['abc']

我明白了

['abc', 'def']
usage: lbrynet [--conf CONF] [-h [HELP]] [-v] {start} ...
lbrynet: error: invalid choice: 'abc' (choose from 'start')

我期待的是在未知参数的元组中获得['abc', 'def']。 我检查了很多 stackoverflow 的答案(例如 ans 1ans 2ans 3ans 4)和错误报告(例如 br 1)和 lot,但我可以似乎没有找到办法。这是一个未解决的错误吗?我期望可以做到这一点是不是错了。如果无法做到这一点,是否有任何解决方法?

另外澄清一下,从元组中得到的['abc', 'def'] 必须传递给其他要处理的函数。

很高兴提供任何进一步的澄清和/或消除任何歧义。

【问题讨论】:

  • 对于主解析器,subparsers 只是一个positional 参数(带有一个特殊的action 参数)。由于您没有定义任何其他位置,因此第一个非标志字符串分配给subparsers,它在choices 测试中失败。 argparse 将字符串分配给位置,然后测试有效性,而不是相反。
  • 另一种说法 - 仅仅因为 subparsers 不是必需的,并不意味着这是一个标记的 (optional) 参数。这只是意味着如果您不提供字符串(在 positional 参数意义上),它不会抱怨。
  • ['start','abc', 'def'] 应该将 2 个字符串放在 extras 中。这是因为调用了“开始”解析器,但不使用额外的字符串,并将它们传递回主解析器。
  • 有没有办法不必提供['start'] 并且仍然可以获得额外的参数。假设我“调用”程序的主要命令是X。这意味着我将以X abc def 的身份运行该程序
  • 我也确实查看了 argparse 的代码,我看到 abc, def 首先被标记为 postionals(按模式“AA”),然后由 start 子解析器解析。但是不应该是因为abcdef都不匹配子命令start,所以它甚至不应该进入start子命令“空格”??

标签: python argparse


【解决方案1】:

正如我在评论中所写,子解析器是一个位置参数。

用一个简单的位置来说明:

In [307]: parser = argparse.ArgumentParser()
In [308]: a1 = parser.add_argument('foo')

In [309]: parser.parse_known_args(['one','two'])
Out[309]: (Namespace(foo='one'), ['two'])

'one' 分配给第一个位置。现在给foo选择:

In [310]: a1.choices = ['bar','test']
In [311]: parser.parse_known_args(['one','two'])
usage: ipython3 [-h] {bar,test}
ipython3: error: argument foo: invalid choice: 'one' (choose from 'bar', 'test')

它仍在尝试将第一个字符串分配给foo。由于它与choices 不匹配,因此会引发错误。

In [312]: parser.parse_known_args(['bar','one','two'])
Out[312]: (Namespace(foo='bar'), ['one', 'two'])

字符串是根据位置而不是值分配给位置的。任何值检查,例如类型或选项检查都是在赋值后完成的。

choices 更改为type 测试:

In [313]: a1.choices = None
In [314]: a1.type = int
In [315]: parser.parse_known_args(['bar','one','two'])
usage: ipython3 [-h] foo
ipython3: error: argument foo: invalid int value: 'bar'

In [316]: parser.parse_known_args(['12','one','two'])
Out[316]: (Namespace(foo=12), ['one', 'two'])

【讨论】:

  • 我理解您想要表达的意思。那很有帮助。有没有办法实现我想要的功能?(不需要基于子解析器)功能如下X --version -> 获取版本X start --quiet -> 在安静模式下启动守护进程X get media1 -> 将命令get media1 发送到进一步处理我无法事先计算开发人员将要输入的内容以代替get,因此getmedia1 将在某处“收集”,然后发送以进一步处理“内部”处理。
猜你喜欢
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2021-05-11
  • 2012-01-21
  • 2021-01-10
相关资源
最近更新 更多