【问题标题】:argparse augment sub-command defaults via global optionsargparse 通过全局选项增加子命令默认值
【发布时间】:2012-08-23 10:21:11
【问题描述】:

我希望能够使用 argparse.ArgumentParser 对象中的全局选项来覆盖/增加子命令的默认值。

一个例子是显示的帮助反映了全局更新,即,对于以下玩具示例:

import argparse
import os
import sys

# Global parser and options.
parser = argparse.ArgumentParser(
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument("--user", 
                    dest="user", 
                    default=os.environ.get("USER"),
                    help="Override the setting of the $USER variable.")

# Sub-command parser and options.
subparsers = parser.add_subparsers()

command = subparsers.add_parser(
    "command",
    formatter_class=argparse.ArgumentDefaultsHelpFormatter)

command.add_argument("--config",
                     dest="config",
                     default="~%s/config" % os.environ.get("USER"),
                     help="The config file.")

options = parser.parse_args()

理想情况下,当我在帮助模式下运行时,我会得到,

> python example.py --user thing command --help
usage: example.py command [-h] [--config CONFIG]

optional arguments:
  -h, --help       show this help message and exit
  --config CONFIG  The config file. (default: ~thing/config)

即,配置文件路径是用户特定的(事物)。我意识到我可以将默认配置更改为 "~%(user)s/config",然后在运行时使用 options 命名空间解决这个问题,但是我希望帮助更明确。

我收集的另一种解决方案是尝试解析参数一次以获得全局选项,即

if "--help" in sys.argv:

    # Parse the command minus the help to obtain the global options. 
    args = sys.argv[1:]
    args.remove("--help")

    # Update the defaults with the global options.
    options = parser.parse_args(args) 
    command.set_defaults(config="~%s/config" % options.user)

    # Re-parse the options.
    parser.parse_args()

虽然这看起来有点 hacky。有更好的方法/解决方案吗?

【问题讨论】:

    标签: python arguments default command-line-arguments argparse


    【解决方案1】:

    在定义全局选项之后,在定义子命令之前,调用parse_known_args 找出--user 的值是什么。然后,完成子解析器命令的定义,使用--user的值定义--config的默认值,之前 调用parse_args解析命令行上的所有选项。

    这与您的替代方案略有不同,但它将所有命令行处理保留在 argparse 对象中。

    (我把你的代码剪短了一点,只是为了缩短这个答案。)

    import os
    import argparse
    
    # Global preparser and options.
    preparser = argparse.ArgumentParser(add_help=False)
    preparser.add_argument("--user", dest="user", default=os.environ.get("USER"))
    
    # ****** NEW *******
    options, _ = preparser.parse_known_args() # Ignore what we haven't defined yet
    user = options.user                       # Use this to define the default of --config
    
    parser = argparse.ArgumentParser(parents=[ preparser ], add_help=True,
                       formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    
    # Sub-command parser and options.
    subparsers = parser.add_subparsers()
    
    command = subparsers.add_parser("command")
    
    # ****** MODIFIED *******
    command.add_argument("--config", dest="config", default="~%s/config" % (user,))
    
    options = parser.parse_args()
    

    【讨论】:

    • 感谢您的回复。这种方法绝对比我的方法更干净/更简单,并且更类似于我在没有 argparse 的情况下尝试的方法,即两次解析参数。当提供“--help”参数而不是按照我的示例删除它时,我可能会查看代码以了解如何让 parse_known_args() 以选项返回(而不是退出)。
    • 哦,我忘了。您可以捕获parse_known_args() 在调用ArgumentParser.exit 时将抛出的SystemExit 异常(这是sys.exit 的一个相对薄的包装器)。
    • 嘿,是的,我试过了,但是 try/except 的问题是选项未定义。
    • 查看我的更新;定义一个禁用帮助的“预解析器”;在它调用parse_known_args 之后,您将使用预解析器作为父级创建“真实”解析器,这样您就不必重新定义所有选项。这也避免了捕获SystemExit 的需要。
    • 谢谢,太棒了。尽管您的解决方案明显更清洁,但我在考虑禁用和重新启用帮助的相同思路。
    【解决方案2】:

    这是一个在运行时直接修改帮助行的解决方案。它也可以修改os.environ 或其他一些全局变量,但我会保持简单。关键是将add_argument('--config'...) 创建的操作分配给一个变量。 help 只是该变量的一个属性。您可以随意修改。

    class FooAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            config.help = 'new user (%s)'% values
            setattr(namespace, self.dest, values)
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--user',action=FooAction)
    sub = parser.add_subparsers()
    cmd = sub.add_parser('cmd')
    config = cmd.add_argument('--config',help='initial help')
    config.help = 'default help' # alt way of setting 'help'
    # print config  # to see other attributes of the config action
    args = parser.parse_args()
    print args
    

    仅使用cmd -h 调用我们得到default help

    $ python stack12167228.py cmd -h
    usage: stack12167228.py cmd [-h] [--config CONFIG]
    
    optional arguments:
      -h, --help       show this help message and exit
      --config CONFIG  default help
    

    --user xxx cmd -h调用,自定义帮助

    $ python stack12167228.py --user xxx cmd -h
    usage: stack12167228.py cmd [-h] [--config CONFIG]
    
    optional arguments:
      -h, --help       show this help message and exit
      --config CONFIG  new user (xxx)
    

    【讨论】:

      猜你喜欢
      • 2011-09-15
      • 2019-06-14
      • 2014-06-11
      • 1970-01-01
      • 2017-03-12
      • 2022-08-05
      • 2013-12-01
      • 2021-12-13
      • 1970-01-01
      相关资源
      最近更新 更多