2012-08-28 30 views
5

我希望能夠使用argparse.ArgumentParser對象的全局選項覆蓋/增加子命令的默認值。argparse通過全局選項擴充子命令的默認值

的一個例子是顯示的幫助體現了全局更新,即以下玩具例子:

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",然後在運行時使用選項命名空間解決此問題,但我希望幫助更加明確。

我收集另一種解決辦法是嘗試分析論證,一旦獲得全局選項,即

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() 

雖然這似乎有點哈克。有更好的方法/解決方案嗎?

回答

4

在定義全局選項之後,但在定義子命令之前,請撥打parse_known_args以找出--user的值。然後,使用--user的值來定義子分析器命令,以定義缺省值--config,之後 調用parse_args來解析命令行上的所有選項。

這與您的選擇稍有不同,但它保留了​​對象內的所有命令行處理。

(我下調代碼一點只是爲了縮短這個答案。)

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() 
+0

感謝您的答覆。這種方法肯定比我的方法更簡潔和更簡單,並且更類似於我在沒有argparse的情況下嘗試的方法,即兩次解析參數。我可以查看代碼,看看如何在提供「--help」參數時使parse_known_args()返回選項(而不是退出),而不是按照我的示例移除它。 – John

+0

哦,我忘了那個。你可以捕獲'parse_known_args()'在調用'ArgumentParser.exit'(這是一個相對較薄的'sys.exit'包裝器)時會拋出的'SystemExit'異常。 – chepner

+0

嘿,是的,我已經嘗試過,但是嘗試/除了問題是選項未定義。 – John

0

下面是直接修改求助熱線,在運行時的解決方案。它也可以修改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)