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

Python optparse通常允许用户多次指定一个选项,并默默地忽略所有选项但最后一个选项.例如,如果选项–foo的操作是store,而选项–flag的操作是store_const,store_true或store_false,则以下命令将是等效的:

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

(更新:默认情况下,argparse会做同样的事情.)

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

检测多次指定选项的最优雅方法是什么?请注意,相同的选项可以使用简短形式,长形式和缩写长形式(因此-f, – foobar,–foob和–foo都是相同的选项).如果有可能在同时指定具有相同目标的多个选项时检测到这种情况会更好,因此如果用户同时指定了–quiet和–verbose,则可以给出警告,而两个选项都存储值进入同一目的地并有效地互相覆盖.

更新:为了更加用户友好,警告应该引用命令行中使用的确切选项名称.使用追加操作而不是存储是可能的,但是当我们检测到冲突时,我们无法说明导致它的选项(是-q和–verbose还是–quiet –quiet?).

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

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

最佳答案 我认为正确的方法是以某种方式“定义你的行动”.

例如,您可以使用操作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中).

点赞