' argparse'带有以dash开头的可选位置参数

时间:2017-11-09 15:21:33

标签: python argparse

我们正在尝试使用我们正在使用的命令行工具构建包装器脚本。我们想根据包装器脚本中的选项设置一些工具参数。我们还希望能够直接将命令行工具传递给命令行工具。

以下是我们提出的建议:

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('positional')
parser.add_argument('-f', '--foo', action='store_true')
parser.add_argument('-b', '--bar', action='store_true')

parser.add_argument('native_arg', nargs='*')

args = parser.parse_args()
print (args)

positional是强制性的。根据选项-f-b,我们会为工具调用添加一些额外选项。之后留下的任何内容(如果有的话)应该被视为本机工具参数并直接提供给工具。使用-h调用我们的脚本会产生以下用法:

usage: test.py [-h] [-f] [-b] positional [native_arg [native_arg ...]]

诀窍是这些原生参数本身就是工具的选项,并包含前导短划线,例如-native0-native1。我们已经知道使用双短划线阻止 argparse 寻找更多选项的技巧。以下电话:

./test.py pos -- -native0 -native1

生成预期的解析参数:

Namespace(bar=False, foo=False, native_arg=['-native0', '-native1'], positional='pos')

但是,在第一个位置参数之后尝试添加选项并不起作用。更具体地说,以下呼叫:

./test.py pos --foo -- -native0 -native1

产生以下输出:

usage: [...shortened...]
test.py: error: unrecognized arguments: -- -native0 -native1

将可选参数放在位置之前:

./test.py --foo pos -- -native0 -native1

似乎有效,打印如下:

Namespace(bar=False, foo=True, native_arg=['-native0', '-native1'], positional='pos')

更奇怪的是,将nargs的{​​{1}}的值更改为native_arg适用于上述所有情况(当然需要注意的是,至少有一个'+'预计)。

我们在Python代码中做错了什么,或者这是某种 argparse 错误?

2 个答案:

答案 0 :(得分:3)

当您将非必需的位置参数与可选参数混合时,

argparse确实很难(有关错误报告的详细信息,请参阅https://stackoverflow.com/a/47208725/1399279)。我不打算提出解决这个问题的方法,而是提出另一种方法。

您应该查看为您描述的情况创建的parse_known_args方法(即将选项传递给包装工具)。

In [1]: import argparse

In [2]: parser = argparse.ArgumentParser()

In [3]: parser.add_argument('positional')

In [4]: parser.add_argument('-f', '--foo', action='store_true')

In [5]: parser.add_argument('-b', '--bar', action='store_true')

In [6]: parser.parse_known_args(['pos', '--foo', '-native0', '-native1'])
Out[6]: (Namespace(bar=False, foo=True, positional='pos'), ['-native0', '-native1'])

parse_args不同,parse_known_args的输出是一个双元素元组。第一个元素是您希望从Namespace获得的parse_args实例,它包含调用add_argument定义的所有属性。第二个元素是解析器未知的所有参数的列表。

我个人更喜欢这种方法,因为用户不需要记住有关如何调用程序的任何技巧,或者哪个选项顺序不会导致错误。

答案 1 :(得分:2)

这是一个已知问题(https://bugs.python.org/issue15112 argparse:nargs =&#39; *&#39;如果前面有选项和其他位置,则位置参数不接受任何项目< /强>)

解析交替处理位置和选项。在处理位置时,它会尝试处理输入字符串所需的数量。但?*位置符合[],这是一个空字符串列表。另一方面,+至少需要一个字符串

./test.py pos --foo -- -native0 -native1

解析器给出了&#39; pos&#39;到positional[]native-arg。然后它给出了&#39; - foo&#39;到它的可选。暂时没有positionals剩下的字符串,所以它会引发错误。

输入字符串的分配是使用regex字符串匹配的程式化形式完成的。想象一下,匹配看起来像AA?的模式。

要纠正这个问题,解析器必须向前看,并延迟处理native-arg。我们已经建议补丁,但它们还没有投入生产。

@ SethMMorton建议使用parse_known_args是一个很好的建议。

早期的解析器(例如Optparse)处理所有标记的参数,但将其余的位置作为无差别列表返回。用户可以拆分该列表。 argparse添加了命名和解析positionals的功能,但该算法在修复nargs时效果最佳,并且变量太多nargs