如何创建具有多个位置参数的argparse互斥组?

时间:2016-01-27 17:36:34

标签: python command-line-arguments argparse

我正在尝试解析命令行参数,以便下面的三种可能性是可能的:

script
script file1 file2 file3 …
script -p pattern

因此,文件列表是可选的。如果指定了-p pattern选项,则命令行上不能有任何其他选项。以“使用”格式表示,它可能看起来像这样:

script [-p pattern | file [file …]]

我认为使用Python的argparse模块执行此操作的方式如下:

parser = argparse.ArgumentParser(prog=base)
group = parser.add_mutually_exclusive_group()
group.add_argument('-p', '--pattern', help="Operate on files that match the glob pattern")
group.add_argument('files', nargs="*", help="files to operate on")
args = parser.parse_args()

但是Python抱怨我的位置参数需要是可选的:

Traceback (most recent call last):
  File "script", line 92, in <module>
    group.add_argument('files', nargs="*", help="files to operate on")
…
ValueError: mutually exclusive arguments must be optional

但是argparse documentation表示"*"的{​​{1}}参数意味着它是可选的。

我无法找到nargs的任何其他价值。我最接近的是使用nargs,但这只会抓取一个文件,而不是任何数字的可选列表。

是否可以使用nargs="?"组成这种参数语法?

3 个答案:

答案 0 :(得分:7)

简短回答

default添加到*位置

引发错误的代码是,

    if action.required:
        msg = _('mutually exclusive arguments must be optional')
        raise ValueError(msg)

如果我在解析器中添加*,我会看到required属性已设置:

In [396]: a=p.add_argument('bar',nargs='*')
In [397]: a
Out[397]: _StoreAction(option_strings=[], dest='bar', nargs='*', const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [398]: a.required
Out[398]: True

?则为假。我将在代码中进一步深入研究,看看为什么会出现差异。它可能是一个错误或被忽视的功能,或者可能是一个很好的理由。一个棘手的问题&#39;可选&#39;位置是无答案是一个答案,也就是说,一个空的值列表是有效的。

In [399]: args=p.parse_args([])
In [400]: args
Out[400]: Namespace(bar=[], ....)

因此,mutual_exclusive必须有一些方法来区分默认[]和真实[]

现在我建议使用--files,如果您希望argparse执行互斥测试,则使用标记的参数而不是位置参数。

设置位置的required属性的代码是:

    # mark positional arguments as required if at least one is
    # always required
    if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
        kwargs['required'] = True
    if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
        kwargs['required'] = True

因此,解决方案是指定*

的默认值
In [401]: p=argparse.ArgumentParser()
In [402]: g=p.add_mutually_exclusive_group()
In [403]: g.add_argument('--foo')
Out[403]: _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [404]: g.add_argument('files',nargs='*',default=None)
Out[404]: _StoreAction(option_strings=[], dest='files', nargs='*', const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [405]: p.parse_args([])
Out[405]: Namespace(files=[], foo=None)

默认值甚至可以是[]。解析器能够区分您提供的默认值和未使用的默认值。

oops - default=None错了。它通过了add_argumentrequired测试,但产生了mutual_exclusive错误。详细信息在于代码如何区分用户定义的默认值和自动默认值。所以请使用None以外的任何内容。

我在文档中没有看到有关此内容的任何内容。我必须检查错误/问题才能看到主题已经讨论过。它之前也可能出现在SO上。

答案 1 :(得分:0)

您正在尝试使用&#39;文件&#39;捕获大量文件的参数,但您没有在cmdline示例中提供它。我认为图书馆感到困惑,因为你没有使用短划线前缀。我建议如下:

import argparse

parser = argparse.ArgumentParser(prog="base")
group = parser.add_mutually_exclusive_group()
group.add_argument('-p', '--pattern', action="store", help="Operate on files that match the glob pattern")
group.add_argument('-f', '--files',  nargs="*", action="store", help="files to operate on")

args = parser.parse_args()
print args.pattern
print args.files

答案 2 :(得分:0)

    import argparse
    parse  = argparse.ArgumentParser()
    parse.add_argument("-p",'--pattern',help="Operates on File")
    parse.add_argument("files",nargs = "*",help="Files to operate on")

    arglist = parse.parse_args(["-p","pattern"])
    print arglist
    arglist = parse.parse_args()
    print arglist
    arglist = parse.parse_args(["file1","file2","file3"])
    print arglist