2009-12-11 78 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