Python 2.7 argparse:如何正确嵌套可选的互斥参数?

12

我的程序应该包括以下选项,由 argparse 正确解析:

  1. 可选参数:[-h, --help][-v, --version]
  2. 互斥参数:[-f FILE, --file FILE][-u URL, --url URL]
  3. 如果选择了 --url,则此选项为可选参数:[-V, --verbose]
  4. 如果选择了 --file--url,则此选项为必选参数:[-F, --format FORMAT]

期望的使用方式为:

prog.py [-h] [-v] [-f FILE (-F FORMAT) | -u URL [-V] (-F FORMAT) ]

对于互斥组中的两个成员,-F需求适用于两者。不确定它是否应该是位置参数

因此,应该可以运行:

prog.py -u "http://foo.bar" -V -F csv

并且如果我忘记了-F参数(正如它应该做的那样),解析器会发出警告。

到目前为止,我已经做了什么:

parser = ArgumentParser(decription='foo')

group = parser.add_mutually_exclusive_group()    
group.add_argument('-f','--file', nargs=1, type=str, help='')
group.add_argument('-u','--url', nargs=1, type=str, help='')    

parser.add_argument('-V','--verbose', action='store_true', default=False, help='')
parser.add_argument('-F','--format', nargs=1, type=str, help='')

由于它有“香草模式”可无需命令行参数运行,因此所有参数都必须是可选的。

如何将第3点和第4点实现到我的代码中?

编辑:
我尝试了-f-u作为子解析器,如这里所描述的那样,但子命令似乎像位置参数一样被处理,如果我不使用参数运行它,则解析器会给出一个error: too few arguments


2
你考虑过使用docopt吗?缺点是它允许选项值以-开头,例如"-f a -F -u"(这里的格式是"-u")。(https://gist.github.com/zed/b94e3e9945debe25826d) - jfs
需要使用“-f”和“-u”中的一个吗?如果是这样,我想到了一种涉及子命令或位置参数的解决方案。 - chepner
1
@chepner:不是的。我希望程序即使没有参数和选项也能运行,这样它就会启动一个用户对话框或者甚至一个 GUI。 - rypel
@J.F.Sebastian:docopt 看起来很不错,我会深入研究并报告它是否符合我的需求。 - rypel
2个回答

5
使用nargs=2和元组metavar可以实现您的目标。
parser = argparse.ArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group()
group.add_argument('-f','--file', nargs=2, metavar=('FILE','FORMAT'))
group.add_argument('-u','--url', nargs=2, metavar=('URL','FORMAT'))
parser.add_argument('-V','--verbose', action='store_true',help='optional with url')

它会生成:

usage: PROG [-h] [-f FILE FORMAT | -u URL FORMAT] [-V]

optional arguments:
  -h, --help            show this help message and exit
  -f FILE FORMAT, --file FILE FORMAT
  -u URL FORMAT, --url URL FORMAT
  -V, --verbose         optional with url

这需要格式和文件名或URL,但不需要-F。正如其他人所指出的那样,在-f情况下可以忽略-V


我尝试了在此处描述的-f和-u作为子解析器,但是子命令似乎像位置参数一样被处理,如果我没有参数运行它,解析器会给我一个错误:参数太少。

在最新版本中,子命令不再被视为必需的位置参数。 我最好的猜测是,这是更改错误消息以提供更多信息的副作用。 代替_parse_known_args执行:

    if positionals:
        self.error(_('too few arguments'))

它扫描_actions以查看哪些是必需的,然后按名称在错误消息中列出它们。 这在http://bugs.python.org/issue9253中讨论过。我知道这个更改正在开发中(3.4版),也可能包括在3.3中。



2

当存在某个特定选项时,可以使用 optparse 中的 回调方法 来强制执行这些点。

然而,在 argparse 中这些不可用。

您可以为 urlfile 子选项添加 子解析器 并分别解析它们。 来自帮助文件:

请注意,由 parse_args() 返回的对象仅包含主解析器和由命令行选择的子解析器的属性 (而不是任何其他子解析器)。因此,在上面的示例中,当指定 a 命令时, 只有 foo 和 bar 属性存在,而当指定 b 命令时,只有 foo 和 baz 属性存在。

但我会正确记录使用情况,并忽略不适用的参数。

例如,让这两个命令行完全相同:

prog.py -f FILE -V
prog.py -f FILE

1
argparse 具有对具有可变数量参数的选项的内置支持,以及处理给定选项的参数的自定义操作。然而,在这种情况下,我同意最简单的方法就是允许 -V 并忽略它,如果使用了 -f - chepner
optparse已被弃用,argparse是其替代品。请参阅:https://docs.python.org/3/library/argparse.html#upgrading-optparse-code - HEADLESS_0NE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接