【问题标题】:Detecting if any command-line options were specified more than once with optparse or argparse使用 optparse 或 argparse 检测是否多次指定任何命令行选项
【发布时间】:2012-09-09 18:39:12
【问题描述】:

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 都是相同的选项)。如果能够检测到同时指定具有相同destination 的多个选项的情况会更好,这样如果用户同时指定--quiet 和@987654334 就会发出警告@ 而这两个选项都将一个值存储到同一个目的地并有效地相互覆盖。

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

不幸的是,我被 optparse 卡住了,无法使用 argparse,因为我必须支持 Python 2.6。

P。 S. 如果您知道仅适用于 argparse 的解决方案,请也发布它。虽然我尽量减少外部依赖项的数量,但在 Python 2.6 下使用 argparse 仍然是一种选择。

【问题讨论】:

  • 您可以将 argparse 捆绑到您的模块中或使其成为依赖项
  • argparse 适用于 python 2.3 及更高版本。
  • 好的,我该如何使用 argparse?

标签: python argparse optparse


【解决方案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)。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这是可能的,虽然不完美而且有点脆弱。将所有 store 操作更改为 append。解析选项后,遍历Values 对象的所有属性(它们在其__dict__ 中)并将每个非空列表替换为其最后一个元素。如果列表包含多个元素,则发出警告。 (糟糕,此时我们不知道导致冲突的确切选项名称。)如果列表为空,请将其替换为该目的地的默认值(手动,我们不能再使用 optparse 默认机制)。要跳过的目的地的停止列表可能会派上用场
    猜你喜欢
    • 2018-10-05
    • 2015-05-07
    • 2020-07-10
    • 2015-04-27
    • 1970-01-01
    • 2013-11-11
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    相关资源
    最近更新 更多