Python 检测是否使用optparse或argparse多次指定了任何命令行选项
Python optparse通常允许用户多次指定一个选项,并自动忽略所有出现的选项,但最后一个选项除外。例如,如果选项Python 检测是否使用optparse或argparse多次指定了任何命令行选项,python,argparse,optparse,Python,Argparse,Optparse,Python optparse通常允许用户多次指定一个选项,并自动忽略所有出现的选项,但最后一个选项除外。例如,如果选项--foo的动作是store,选项--flag的动作是store\u const,store\u true或store\u false,则以下命令将是等效的: my-command --foo=bar --foo=another --flag --foo=last --flag my-command --flag --foo=last (更新:默认情况下,argparse执行
--foo
的动作是store
,选项--flag
的动作是store\u const
,store\u true
或store\u 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
还是-quiet--quiet
?)
不幸的是,我一直使用optparse,无法使用argparse,因为我必须支持Python 2.6
另外,如果你知道一个只适用于argparse的解决方案,也请发布它。虽然我试图尽量减少外部依赖项的数量,但在Python 2.6下使用argparse仍然是一种选择。您可以使用
action=“append”
(optpasse
)然后检查附加元素的数量。请看我认为正确的方法是以某种方式“定义你的行动”
例如,您可以使用该操作并实现实现所需行为的函数。
您可以编写一个函数,首先检查目标是否已填充,如果已填充,则将重叠选项存储到列表中。
解析完成后,您应该检查这些列表是否为空,如果没有,则引发相应的异常
另一种方法是定义自己的行为。你可以看看
使用回调的一个小示例:
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
中)。您可以在模块中绑定argparse,或者使其成为python 2.3及更高版本上的依赖项。好的,我如何使用argparse做到这一点?这是可能的,尽管不是完美的,也有点脆弱。将所有store
操作更改为append
。解析选项后,迭代值
对象的所有属性(它们在其\uuuu dict\uuuu
中),并用最后一个元素替换每个非空列表。如果列表包含多个元素,则发出警告。(哎呀,现在我们还不知道导致冲突的确切选项名称。)如果列表为空,请将其替换为该目标的默认值(手动,我们无法再使用optpass defaults机制)。要跳过的目的地的停止列表可能很方便