2011-03-02 219 views
7

我想使用argparse來構建一個帶有子命令的工具。可能的語法是python argparse子命令依賴和衝突

/tool.py下載--from 1234 --interval 60

/tool.py下載--build 1432個

/tool.py乾淨--numbers 10

所以我想argparse使用來實現:

  1. 確保 '--from' 和 '--interval' 是一個lways一起使用
  2. 確保「--build」不會與其它參數

使用,但我沒有找到一個方法來配對「--from」和「--internal」爲一組,然後使該組與'--build'互斥。

下面是我目前的代碼,它只會使'--from'和'--build'是互斥的。既不確保' - 從'和' - 間隔'在一起,也不確保' - 間隔'和' - 建立'是互斥的。

parser = argparse.ArgumentParser(description='A Tool') 
subparsers = parser.add_subparsers(help='sub-command help') 

#create the parser for the 'download' command 
download_parser = subparsers.add_parser('download', help='download help') 
download_parser.add_argument('--interval', dest='interval', type=int,help='interval help') 
group = download_parser.add_mutually_exclusive_group() 
group.add_argument('--from',type=int, help='from help') 
group.add_argument('--build', type=int, help='interval help') 

例如,

/tool.py下載--from 1234

不應該被允許的,因爲 '--from' 必須以 '--interval' 工作。但是我的代碼默默接受它。

而且

/tool.py下載--interval 1234 --build 5678

不應該被允許的,因爲 '--build' 不能與其他參數一起使用。但我的代碼也接受它。

任何建議將不勝感激。謝謝。

+0

你的代碼有,但究竟是不是工作?給出一個錯誤行爲的例子,並解釋你期望如何。 – 2011-03-02 09:29:19

+0

我加了2個錯誤行爲的例子。感謝您的建議。 – Landy 2011-03-02 10:09:18

回答

6

您可以使用此custom actions

import argparse 
import sys 


class VerifyNoBuild(argparse.Action): 
    def __call__(self, parser, args, values, option_string=None): 
     # print 'No: {n} {v} {o}'.format(n=args, v=values, o=option_string) 
     if args.build is not None: 
      parser.error(
       '--build should not be used with --from or --interval') 
     setattr(args, self.dest, values) 


class VerifyOnlyBuild(argparse.Action): 
    def __call__(self, parser, args, values, option_string=None): 
     # print 'Only: {n} {v} {o}'.format(n=args, v=values, o=option_string) 
     if getattr(args, 'from') is not None: 
      parser.error('--from should not be used with --build') 
     if getattr(args, 'interval') is not None: 
      parser.error('--interval should not be used with --build') 
     setattr(args, self.dest, values) 

parser = argparse.ArgumentParser(description='A Tool') 
subparsers = parser.add_subparsers(help='sub-command help') 

# create the parser for the 'download' command 
download_parser = subparsers.add_parser('download', help='download help') 

download_parser.add_argument('--interval', 
          type=int, help='interval help', 
          action=VerifyNoBuild) 
download_parser.add_argument('--from', 
          type=int, action=VerifyNoBuild) 
download_parser.add_argument('--build', 
          type=int, action=VerifyOnlyBuild) 

args = parser.parse_args('download --from 1234 --interval 60'.split()) 
print(args) 
# Namespace(build=None, from=1234, interval=60) 

args = parser.parse_args('download --build 1432'.split()) 
print(args) 
# Namespace(build=1432, from=None, interval=None) 

args = parser.parse_args('download --build 1432 --from 1234'.split()) 
print(args) 
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD] 
# test.py download: error: --build should not be used with --from or --interval 

args = parser.parse_args('download --build 1432 --interval 60'.split()) 
print(args) 
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD] 
# test.py download: error: --build should not be used with --from or --interval 

不過說真的,我覺得這是更短,更簡單:

def parse_options(): 
    parser = argparse.ArgumentParser(description='A Tool') 
    subparsers = parser.add_subparsers(help='sub-command help') 

    #create the parser for the 'download' command 
    download_parser = subparsers.add_parser('download', help='download help') 
    download_parser.add_argument('--interval', type=int, help='interval help') 
    download_parser.add_argument('--from', type=int) 
    download_parser.add_argument('--build', type=int) 

    opt=parser.parse_args() 
    from_interval=[getattr(opt,key) is not None for key in ('from','interval')] 
    if opt.build is not None: 
     if any(from_interval): 
      sys.exit('error!') 
    elif not all(from_interval): 
     sys.exit('error!') 
    return opt 
+0

謝謝。自定義操作非常有幫助。我修改了你的代碼,以確保--from和--interval總是一起使用。它運作良好。謝謝! :) – Landy 2011-03-03 08:10:42

+0

@蘭迪:啊,是的,我忘了這種情況。你是否設法從'VerifyNoBuild'類中驗證這個條件?如果是這樣,請您提供您的解決方案嗎?我想看看這是如何完成的。我已經修改了替代解決方案來處理這種情況。 – unutbu 2011-03-03 08:25:27

+0

對不起,遲到的迴應。其實我的代碼很簡單。正如你所說,我修改了** VerifyNoBuild **類,在調用setattr()**之前添加了以下行:'if(args.begin is None)or(args.interval is None):sys.exit (' - from和 - interval必須一起使用')' – Landy 2011-03-07 02:36:39