在同一次Python执行中多次调用OptionParser.parse_args()

4
我有以下示例设置:
|-- main_script.py
`-- module
    |-- __init__.py
    `-- submodule.py

主脚本的内容如下:

import optparse
import module

parser = optparse.OptionParser()
group = optparse.OptionGroup("submodules options")
group.add_option("","--main_script.bar", dest="bar", action="store_true")
parser.add_option_group(group)

opts,args = parser.parse_args()

if opts.bar:
    print ("Bar")

以下是submodule.py文件的内容:

import optparse
parser = optparse.OptionParser()
group = optparse.OptionGroup(parser, "submodules options")
group.add_option("","--module.submodule.foo", dest="foo", action="store_true")
parser.add_option_group(group)

opts,args = parser.parse_args()

if opts.foo:
    print ("Foo")

由于主脚本导入了子模块,所以从子模块中调用了parse_args。有没有办法将这些OptionParser实例合并起来,并在存在选项冲突时引发错误?

2个回答

2

最简单的方法是将逻辑拆分为函数。首先,您不应该在全局模块范围内执行逻辑,而是使用if name == "__main__"包装器结构。

您可以为必须定义选项的每个模块定义一个add_options(parser)函数,并在调用parse_args之前在根级别调用此函数:

import optparse
import submodule

def add_options(parser):
    parser.add_option(...)

def main():
    parser = optparse.OptionParser()
    add_options(parser)
    submodule.add_options(parser)
    opts, args = parser.parse_args()
    #...

if __main__ == "__main__":
    main()

如果我对'module'和'submodule'的客户端有完全控制权,上述方法将起作用。我在示例中使用了一种全局方法,但在我的实际代码中情况并非如此。我试图实现的目标是通过我的库中的各个模块来公开“命令行选项”。这样,任何公开命令行界面的库的客户端都可以访问包含的任何子模块公开的命令行选项,以启用诸如“调试模式”、“性能分析”等选项。 - Ali-Akber Saifee

0
为了从外部解决这个问题 - 我有一个初始实现,通过将OptionParser类替换为OptionParser的子类并重载parse_args方法+公开新的delayed_parse_args方法来修补optparse模块。我分享这个解决方案的片段,以防其他人发现它有用或可以对其进行改进。

optparse_patch.py

import optparse

def patch_opt_parser():
    optparse.stashed_parsers = {}

    class OptionParserEx(optparse.OptionParser):
        def delayed_parse_args(self, callback):
            optparse.stashed_parsers[self] = callback

        def parse_args(self, args=None, values=None):
            for parser, callback in getattr(optparse,"stashed_parsers").items():
                # add all the option_list & option_groups from the individual
                # parsers in stashed_parsers to `self`
            for parser, callback in getattr(optparse,"stashed_parsers").items():
                # update `parser` to inherit the option_lists and option_groups from 
                # self. then ....
                _o, _a = optparse._OptionParser.parse_args( parser, args, values )
                callback( _o, _a t)
            return getattr(optparse,"_OptionParser").parse_args(self, args, values)

    optparse._OptionParser = optparse.OptionParser
    optparse.OptionParser = OptionParserEx

patch_opt_parser()

这允许子模块“存储”其预期选项,并在模块的客户端实际提供OptionParser并调用其自己的OptionParser上的parse_args方法时,在稍后的阶段评估命令行选项。这样一个使用案例的示例如下:

module.py

import optparse_patch
import optparse
parser = optparse.OptionParser()
group = optparse.OptionGroup(parser, "module options")
group.add_option("-f", dest="flip", action="store_true")
parser.add_option_group(group)
def cli_callback ( opts, args ):
    if opts.flip: 
        print "flip"
opts, args = parser.delayed_parse_args ( cli_callback ) 

main.py

import module
import optparse


myparser = optparse.OptionParser()
mygroup = optparse.OptionGroup(myparser, "main options")
mygroup.add_option("-j", dest="jump", action="store_true")
myparser.add_option_group(mygroup)
opts, args = myparser.parse_args()
if opts.jump:
     print "jump"

调用程序 main.py 会产生以下输出:

python main.py --help

Usage: main.py [options]

Options:
  -h, --help  show this help message and exit

  module options:
    -f        

  main options:
    -j        

python main.py -j -f

flip
jump

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接