2009-12-11 33 views
23

Trong python's OptionParser, làm cách nào tôi có thể hướng dẫn nó bỏ qua các tùy chọn không xác định được cung cấp cho phương thức parse_args?Tôi làm cách nào để có được OptionParser của optparse để bỏ qua các tùy chọn không hợp lệ?

ví dụ:
Tôi chỉ lựa chọn --foo định nghĩa cho OptionParser dụ của tôi, nhưng tôi gọi parse_args với danh sách
[ '--foo', '--bar' ]

EDIT:
Tôi không quan tâm nếu nó lọc chúng ra khỏi danh sách gốc. Tôi chỉ muốn bỏ qua các tùy chọn không xác định.

Lý do tôi làm điều này là vì tôi đang sử dụng giao diện AddOption của SCons để thêm tùy chọn tạo tùy chỉnh. Tuy nhiên, một số tùy chọn đó hướng dẫn việc khai báo các mục tiêu. Vì vậy, tôi cần phải phân tích chúng ra khỏi sys.argv tại các điểm khác nhau trong tập lệnh mà không cần truy cập vào tất cả các tùy chọn. Cuối cùng, Scons OptionParser cấp cao nhất sẽ bắt tất cả các tùy chọn không xác định trong dòng lệnh.

+0

lọc chúng ra? – jldupont

+0

Ummm ... Đối số bổ sung là lỗi, theo định nghĩa. Bạn đang cố làm gì vậy? –

+0

xem các chỉnh sửa đối với bài đăng gốc ở trên. –

Trả lời

1

Theo yêu cầu synack trong bình luận một câu trả lời khác nhau, tôi đang gửi bài hack của tôi về một giải pháp mà sanitizes đầu vào trước khi đi qua họ để phụ huynh 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

Giải pháp thú vị. Cảm ơn bạn đã dành thời gian đăng lại. – jathanism

10

Theo mặc định, không có cách nào để sửa đổi hành vi của cuộc gọi thành error() được tăng khi tùy chọn không xác định được chuyển. Từ các tài liệu ở dưới cùng của phần này trên how optparse handles errors:

Nếu optparse của lỗi xử lý mặc định hành vi không phù hợp với nhu cầu của bạn, bạn sẽ cần phải lớp con OptionParser và ghi đè thoát của nó() và/hoặc phương thức error().

Ví dụ đơn giản nhất của việc này sẽ là:

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

này chỉ đơn giản sẽ làm cho tất cả các cuộc gọi đến error() làm gì cả. Tất nhiên đây không phải là lý tưởng, nhưng tôi tin rằng điều này minh họa những gì bạn cần làm. Hãy ghi nhớ những docstring từ error() và bạn sẽ được tốt để đi như bạn tiến hành:

In nhắn sử dụng kết hợp 'msg' để stderr và thoát. Nếu bạn ghi đè lên điều này trong một phân lớp, nó không nên trả lại - nó nên thoát hoặc đưa ra một ngoại lệ.

+1

Sau khi thử nghiệm thêm, điều này không hoạt động. Lỗi được che dấu, nhưng trình phân tích cú pháp dừng phân tích các đối số. Điều này chỉ hoạt động nếu các cờ không hợp lệ nằm ở cuối dòng lệnh. –

+0

Tôi đã kết thúc khử trùng các đầu vào trước khi chuyển chúng sang OptionParser. Ít nhất nó được thực hiện ở một nơi. –

+0

Thú vị tìm thấy. Bạn có phiền khi đăng giải pháp của mình, vì nó không chứa dữ liệu nhạy cảm? Tôi tò mò làm thế nào bạn giải quyết này. – jathanism

37

Dưới đây là một cách để có lập luận chưa biết được thêm vào kết quả args của OptionParser.parse_args, với một phân lớp đơn giản.

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) 

Và đây là một đoạn để chứng minh rằng nó hoạt động:

# 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 Câu trả lời hay. – ThomasH

+0

Câu trả lời hữu ích nhất cho đến nay. –

+0

Giải pháp khá hay! Tôi đã cố gắng để tạo ra một kịch bản tùy chỉnh mà cải trang thành một kịch bản phức tạp khác và tôi chỉ cần hỗ trợ một tập nhỏ các tùy chọn của nó, vì vậy giải pháp này có vẻ như nó sẽ hoạt động rất tốt. – haridsv

6

Python 2.7 (mà không tồn tại khi câu hỏi này được hỏi) hiện nay cung cấp các mô-đun argparse. Bạn có thể sử dụng ArgumentParser.parse_known_args() để hoàn thành mục tiêu của câu hỏi này.

3

Đây là pass_through.py ví dụ từ 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

Trình phân tích cú pháp này thu gọn một '" -abc "' thành '" -a "' – Nick

+0

@Nick: các tùy chọn dài được xác định là "" --abc "' trong cú pháp không hợp lệ. Tôi sợ không có gì có thể được thực hiện về điều này ngay cả với lớp con 'PassThroughOptionParser'. '" -abc "' trong ví dụ trên là tùy chọn '-a' hợp lệ với đối số' bc' (mà nó yêu cầu, BTW). –

+1

Nói chung, optparse xử lý "-abc" giống như "-a -b -c". Trong trường hợp này, mặc dù "-abc" được xử lý giống như "-a" (khi "-a", "-b" và "-c" không được công nhận). – Nick

Các vấn đề liên quan