如何让 optparse 的 OptionParser 忽略无效选项?

发布于 2024-08-14 06:16:15 字数 530 浏览 5 评论 0原文

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

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

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

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

In python's OptionParser, how can I instruct it to ignore undefined options supplied to method parse_args?

e.g.

I've only defined option --foo for my OptionParser instance, but I call parse_args with list: [ '--foo', '--bar' ]

I don't care if it filters them out of the original list. I just want undefined options ignored.

The reason I'm doing this is because I'm using SCons' AddOption interface to add custom build options. However, some of those options guide the declaration of the targets. Thus I need to parse them out of sys.argv at different points in the script without having access to all the options. In the end, the top level Scons OptionParser will catch all the undefined options in the command line.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

¢好甜 2024-08-21 06:16:15

下面是一种通过简单的子类将未知参数添加到 OptionParser.parse_args 的结果 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

Here's one way to have unknown arguments added to the result args of OptionParser.parse_args, with a simple subclass.

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)

And here's a snippet to show that it works:

# 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
疯到世界奔溃 2024-08-21 06:16:15

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

如果 optparse 的默认错误处理行为不满足您的需求,您需要
子类 OptionParser 并重写其 exit() 和/或 error() 方法。

最简单的例子是:

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

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

打印包含“msg”的使用消息到 stderr 并
出口。
如果你在子类中重写它,它不应该返回——它
应该退出或引发异常。

By default there is no way to modify the behavior of the call to error() that is raised when an undefined option is passed. From the documentation at the bottom of the section on how optparse handles errors:

If optparse‘s default error-handling behaviour does not suit your needs, you’ll need to
subclass OptionParser and override its exit() and/or error() methods.

The simplest example of this would be:

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

This would simply make all calls to error() do nothing. Of course this isn't ideal, but I believe that this illustrates what you'd need to do. Keep in mind the docstring from error() and you should be good to go as you proceed:

Print a usage message incorporating 'msg' to stderr and
exit.
If you override this in a subclass, it should not return -- it
should either exit or raise an exception.

策马西风 2024-08-21 06:16:15

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

Python 2.7 (which didn't exist when this question was asked) now provides the argparse module. You may be able to use ArgumentParser.parse_known_args() to accomplish the goal of this question.

撩起发的微风 2024-08-21 06:16:15

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

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

This is pass_through.py example from 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()
仙女 2024-08-21 06:16:15

根据不同答案评论中 synack 的请求,我发布了一个解决方案的 hack,该解决方案在将输入传递给父 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

Per synack's request in a different answer's comments, I'm posting my hack of a solution which sanitizes the inputs before passing them to the parent 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文