2009-12-11 75 views
23

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

例如
我只定义的选项--fooOptionParser实例,但我打电话parse_args与列表
[ '--foo', '--bar' ]

编辑:
如果它过滤出来的原单的我不在乎。我只想要忽略未定义的选项。

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

+0

将它们滤除? – jldupont 2009-12-11 01:17:54

+0

嗯......根据定义,额外的参数是一个错误。你想做什么? – 2009-12-11 11:22:22

+0

请参阅上述原始帖子的修改。 – 2009-12-11 21:13:01

回答

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 
+0

有趣的解决方案。感谢您抽出时间将其发回。 – jathanism 2010-01-27 22:56:44

10

默认情况下,无法修改调用error()的行为,这是在传递未定义的选项时引发的。从该部分的底部上how optparse handles errors文档:

如果optparse的默认错误处理行为不适合你的需求,你需要 子类OptionParser并覆盖其出口()和/或error()方法。

的最简单的例子是:

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

这只是让所有的呼叫,error()什么也不做。当然这并不理想,但我相信这说明了你需要做的事情。请记住文档字符串从error(),你应该去的好,因为你进入:

打印包含“味精”标准错误和 退出用法信息。 如果你在一个子类中覆盖它,它不应该返回 - 它应该退出或引发异常。

+1

经过进一步测试,这不起作用。错误被屏蔽,但解析器停止解析参数。这只适用于无效标志位于命令行末尾的情况。 – 2009-12-15 22:13:21

+0

我最终在将它们传递给OptionParser之前清理了输入。至少它是在一个地方完成的。 – 2009-12-15 23:00:06

+0

有趣的发现。您是否介意发布您的解决方案,因为它不包含敏感数据?我很好奇你是如何解决这个问题的。 – jathanism 2009-12-16 17:37:15

37

这里有未知参数的一种方法添加到结果argsOptionParser.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 
+2

+1很好的答案。 – ThomasH 2012-06-05 13:39:40

+0

迄今为止最有用的答案。 – 2013-02-09 01:37:02

+0

很不错的解决方案!我试图创建一个伪装成另一个复杂脚本的自定义脚本,我只需要支持它的一小部分选项,所以这个解决方案看起来很好。 – haridsv 2015-04-14 14:57:01

3

这是pass_through.py例如从Optik distribution

#!/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() 
+1

此解析器将无法识别的'“-abc”折叠为'“-a”' – Nick 2013-06-20 21:16:59

+0

@Nick:long选项在optparse语法中指定为“--abc”。即使使用'PassThroughOptionParser'子类,我恐怕也没有办法做到这一点。 ''-abc''在上面的例子中是有效的'-a'选项,带'bc'参数(它需要,顺便说一下)。 – 2013-06-21 20:30:16

+1

一般optparse将“-abc”视为“-a -b -c”。在这种情况下,“-abc”与“-a”的处理方式相同(当“-a”,“-b”和“-c”无法识别时)。 – Nick 2013-06-28 21:10:39