2011-03-02 85 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