【问题标题】:command line arg parsing through introspection通过自省解析命令行参数
【发布时间】:2010-11-23 15:29:53
【问题描述】:

我正在开发一个管理脚本,该脚本通过大量命令行选项完成大量工作。脚本的前几次迭代使用 optparse 收集用户输入,然后运行页面,以适当的顺序测试每个选项的值,并在必要时执行操作。这导致代码丛林非常难以阅读和维护。

我正在寻找更好的东西。

我希望有一个系统,我可以在其中以或多或少的普通 python 方式编写函数,然后在运行脚本时,从我的函数生成选项(和帮助文本),在适当的情况下进行解析和执行命令。此外,我真的很希望能够构建 django 风格的子命令界面,其中 myscript.py installmyscript.py remove 完全分开工作(单独的选项、帮助等)

我找到了simon willison's optfunc,它做了很多这样的事情,但似乎只是错过了标记——我想把每个 OPTION 写成一个函数,而不是试图将整个选项集压缩成一个巨大的字符串选项。

我想象一个架构涉及一组主要功能的类,并且类的每个定义的方法对应于命令行中的特定选项。这种结构的优势在于让每个选项都位于它修改的功能代码附近,从而简化了维护。我不太清楚如何处理命令的顺序,因为类方法的顺序不是确定性的。

在我重新发明轮子之前:是否还有其他行为类似的现有代码?其他容易修改的东西?提出这个问题已经阐明了我自己对什么是好的想法的想法,但欢迎就为什么这是一个糟糕的想法或它应该如何工作提供反馈。

【问题讨论】:

    标签: python command-line parsing


    【解决方案1】:

    WSGI 库 werkzeug 提供 Management Script Utilities 可以做你想做的事,或者至少给你一个提示如何自己做内省。

    from werkzeug import script
    
    # actions go here
    def action_test():
        "sample with no args"
        pass
    
    def action_foo(name=2, value="test"):
        "do some foo"
        pass
    
    if __name__ == '__main__':
        script.run()
    

    这将生成以下帮助消息:

    $ python /tmp/test.py --help
    usage: test.py <action> [<options>]
           test.py --help
    
    actions:
      foo:
        do some foo
    
        --name                        integer   2
        --value                       string    test
    
      test:
        sample with no args
    

    动作是同一模块中以“action_”开头的函数,它接受多个参数,其中每个参数都有一个默认值。默认值的类型指定参数的类型。

    然后可以通过位置或使用 shell 中的 --name=value 来传递参数。

    【讨论】:

      【解决方案2】:

      不要在“自省”上浪费时间。

      每个“命令”或“选项”都是一个具有两组方法函数或属性的对象。

      1. 向 optparse 提供设置信息。

      2. 实际去做。

      这是所有命令的超类

      class Command( object ):
          name= "name"
          def setup_opts( self, parser ):
              """Add any options to the parser that this command needs."""
              pass
          def execute( self, context, options, args ):
              """Execute the command in some application context with some options and args."""
              raise NotImplemented
      

      您为InstallRemove 以及您需要的所有其他命令创建子类。

      您的整个应用程序看起来像这样。

      commands = [ 
          Install(),
          Remove(),
      ]
      def main():
          parser= optparse.OptionParser()
          for c in commands:
              c.setup_opts( parser )
          options, args = parser.parse()
          command= None
          for c in commands:
              if c.name.startswith(args[0].lower()):
                  command= c
                  break
          if command:
              status= command.execute( context, options, args[1:] )
          else:
              logger.error( "Command %r is unknown", args[0] )
              status= 2
          sys.exit( status )
      

      【讨论】:

        猜你喜欢
        • 2013-03-21
        • 2012-01-26
        • 2011-08-15
        • 1970-01-01
        相关资源
        最近更新 更多