25

在 python 中OptionParser,我如何指示它忽略提供给方法的未定义选项parse_args

例如
,我只--foo为我的OptionParser实例定义了选项,但我parse_args用列表调用
[ '--foo', '--bar' ]

编辑:
我不在乎它是否将它们从原始列表中过滤出来。我只想忽略未定义的选项。

我这样做的原因是因为我使用 SCons 的 AddOption 接口来添加自定义构建选项。但是,其中一些选项指导目标的声明。因此,我需要在脚本的不同点将它们从 sys.argv 中解析出来,而无需访问所有选项。最后,顶级 Scons OptionParser 将捕获命令行中所有未定义的选项。

4

5 回答 5

38

这是将未知参数添加到 的结果args中的一种方法OptionParser.parse_args,使用一个简单的子类。

from optparse import (OptionParser,BadOptionError,AmbiguousOptionError)

class PassThroughOptionParser(OptionParser):
    """
    An unknown option pass-through implementation of OptionParser.

    When unknown arguments are encountered, bundle with largs and try again,
    until rargs is depleted.  

    sys.exit(status) will still be called if a known argument is passed
    incorrectly (e.g. missing arguments or bad argument types, etc.)        
    """
    def _process_args(self, largs, rargs, values):
        while rargs:
            try:
                OptionParser._process_args(self,largs,rargs,values)
            except (BadOptionError,AmbiguousOptionError), e:
                largs.append(e.opt_str)

这是一个片段,表明它有效:

# Show that the pass-through option parser works.
if __name__ == "__main__": #pragma: no cover
    parser = PassThroughOptionParser()
    parser.add_option('-k', '--known-arg',dest='known_arg',nargs=1, type='int')
    (options,args) = parser.parse_args(['--shazbot','--known-arg=1'])    
    assert args[0] == '--shazbot'
    assert options.known_arg == 1

    (options,args) = parser.parse_args(['--k','4','--batman-and-robin'])
    assert args[0] == '--batman-and-robin'
    assert options.known_arg == 4
于 2012-02-16T07:28:18.043 回答
11

默认情况下,无法修改error()传递未定义选项时引发的调用的行为。从关于 optparse 如何处理错误的部分底部的文档中:

如果 optparse 的默认错误处理行为不适合您的需要,您需要继承 OptionParser 并覆盖其 exit() 和/或 error() 方法。

最简单的例子是:

class MyOptionParser(OptionParser):
    def error(self, msg):
        pass

这只会让所有调用error()什么都不做。当然这并不理想,但我相信这说明了你需要做什么。请记住来自的文档字符串error(),您应该可以继续进行操作:

将包含“msg”的使用消息打印到标准错误并退出。如果您在子类中覆盖它,它不应该返回——它应该退出或引发异常。

于 2009-12-11T01:28:29.460 回答
7

Python 2.7(在提出这个问题时不存在)现在提供了argparse模块。您也许可以使用ArgumentParser.parse_known_args()来完成这个问题的目标。

于 2012-10-05T18:22:19.157 回答
3

这是pass_through.py来自Optik 发行版的示例。

#!/usr/bin/env python

# "Pass-through" option parsing -- an OptionParser that ignores
# unknown options and lets them pile up in the leftover argument
# list.  Useful for programs that pass unknown options through
# to a sub-program.

from optparse import OptionParser, BadOptionError

class PassThroughOptionParser(OptionParser):

    def _process_long_opt(self, rargs, values):
        try:
            OptionParser._process_long_opt(self, rargs, values)
        except BadOptionError, err:
            self.largs.append(err.opt_str)

    def _process_short_opts(self, rargs, values):
        try:
            OptionParser._process_short_opts(self, rargs, values)
        except BadOptionError, err:
            self.largs.append(err.opt_str)


def main():
    parser = PassThroughOptionParser()
    parser.add_option("-a", help="some option")
    parser.add_option("-b", help="some other option")
    parser.add_option("--other", action='store_true',
                      help="long option that takes no arg")
    parser.add_option("--value",
                      help="long option that takes an arg")
    (options, args) = parser.parse_args()
    print "options:", options
    print "args:", args

main()
于 2012-12-13T23:21:53.917 回答
1

根据 synack 在不同答案评论中的请求,我发布了我的解决方案,该解决方案在将输入传递给父级之前对其进行清理OptionParser

import optparse
import re
import copy
import SCons

class NoErrOptionParser(optparse.OptionParser):
    def __init__(self,*args,**kwargs):
        self.valid_args_cre_list = []
        optparse.OptionParser.__init__(self, *args, **kwargs)

    def error(self,msg):
        pass

    def add_option(self,*args,**kwargs):
        self.valid_args_cre_list.append(re.compile('^'+args[0]+'='))
        optparse.OptionParser.add_option(self, *args, **kwargs)

    def parse_args(self,*args,**kwargs):
        # filter out invalid options
        args_to_parse = args[0]
        new_args_to_parse = []
        for a in args_to_parse:
            for cre in self.valid_args_cre_list:
                if cre.match(a):
                    new_args_to_parse.append(a)


        # nuke old values and insert the new
        while len(args_to_parse) > 0:
            args_to_parse.pop()
        for a in new_args_to_parse:
            args_to_parse.append(a)

        return optparse.OptionParser.parse_args(self,*args,**kwargs)


def AddOption_and_get_NoErrOptionParser( *args, **kwargs):
    apply( SCons.Script.AddOption, args, kwargs)
    no_err_optparser = NoErrOptionParser(optparse.SUPPRESS_USAGE)
    apply(no_err_optparser.add_option, args, kwargs)

    return no_err_optpars
于 2010-01-27T16:56:43.227 回答