使用optparse或argparse检测是否多次指定了任何命令行选项

时间:2012-09-17 14:09:39

标签: python argparse optparse

Python optparse通常允许用户多次指定一个选项,并默默地忽略所有选项但最后一个选项。例如,如果选项--foo的操作为store且选项--flag的操作为store_conststore_truestore_false,则以下操作命令将是等效的:

my-command --foo=bar --foo=another --flag --foo=last --flag
my-command --flag --foo=last

(更新:argparse默认会做同样的事情。)

现在,我有很多选择,并且不止一次指定其中任何一个都没有意义。如果用户多次指定相同的选项,我想警告他们可能的错误。

检测多次指定选项的最优雅方法是什么?请注意,相同的选项可以包含简短形式,长格式和缩写长格式(以便-f--foobar--foob--foo都是相同的选项) 。如果同时指定具有相同目的地的多个选项可以检测到这种情况会更好,这样如果用户同时指定--quiet--verbose,而两个选项都将值存储到同一目的地,并有效地相互覆盖。

更新:为了更加用户友好,警告应该引用命令行中使用的确切选项名称。可以使用append操作而不是store,但是当我们检测到冲突时,我们无法说出导致冲突的选项(是-q--verbose还是{{1} }?)。

不幸的是我坚持使用optparse并且不能使用argparse,因为我必须支持Python 2.6。

P上。 S.如果你知道一个只适用于argparse的解决方案,请发布它。虽然我尝试最小化外部依赖项的数量,但在Python 2.6下使用argparse仍然是一种选择。

2 个答案:

答案 0 :(得分:1)

您可以使用action="append"optparse),然后检查附加元素的数量。见http://docs.python.org/library/optparse.html#other-actions

答案 1 :(得分:1)

我认为正确的方法是以某种方式“定义你的行动”。

例如,您可以使用操作callback并实现一个实现所需行为的函数。 您可以编写一个函数,首先检查目标是否已填充,如果已填充,则将重叠选项存储到列表中。 解析完成后,您应检查这些列表是否为空,如果它们没有引发相应的异常。

另一种方法是定义自己的行动。你可以看看here

使用回调的一个小例子:

import sys
import functools
from optparse import OptionParser


bad_option = 'BAD OPTION'

def store(option, opt, value, parser, dest, val):
    """Set option's destination *dest* to *val*  if there are no conflicting options."""
    list_name = dest + '_options_list'
    try:
        # if this option is a conflict, save its name and set the value to bad_option
        getattr(parser.values, list_name).append(opt)
        setattr(parser.values, dest, bad_option)
    except AttributeError:
        # no conflicts, set the option value and add the options list
        setattr(parser.values, dest, val)
        setattr(parser.values, list_name, [opt])

store_true = functools.partial(store, val=True)
store_false = functools.partial(store, val=False)


parser = OptionParser()
parser.add_option('-v', '--verbose',
                  action='callback', callback=store_true,
                  help='Increase output verbosity',
                  callback_kwargs={'dest': 'verbose'})

parser.add_option('-q', '--quiet',
                  action='callback', callback=store_false,
                  help='Decrease output verbosity',
                  callback_kwargs={'dest': 'verbose'})

opts, args = parser.parse_args()

# detects all conflicting options for all destinations
found = False
for dest in ('verbose',):
    if getattr(opts, dest) == bad_option:
        conflicting_opts = ', '.join(getattr(opts, dest + '_options_list'))
        print('Conflicting options %s for destination %s'
              % (conflicting_opts, dest))
        found = True

if found:
    parser.print_usage()
    sys.exit(2)

输出:

$ python testing_optparse.py -v -q
Conflicting options -v, -q for destination verbose
Usage: prova_optparse.py [options]

在检测到冲突时提升OptionValueError可能会更好,即使这样只会产生几个冲突的选项。如果要获取所有冲突的选项,则必须解析剩余的参数(在parser.rargs中)。