Python argparse:至less需要一个参数

我一直在使用argparse来进行Python程序的准备, -prepare或两者:

 parser = argparse.ArgumentParser(description='Log archiver arguments.') parser.add_argument('-process', action='store_true') parser.add_argument('-upload', action='store_true') args = parser.parse_args() 

没有至less一个参数,程序是没有意义的。 如何configurationargparse强制至lessselect一个参数?

更新:

在评论之后:什么是至less有一个选项参数化程序的Pythonic方法?

 if not (args.process or args.upload): parser.error('No action requested, add -process or -upload') 
 args = vars(parser.parse_args()) if not any(args.values()): parser.error('No arguments provided.') 

如果不是'或两个'部分(我最初错过了这个),你可以使用这样的东西:

 parser = argparse.ArgumentParser(description='Log archiver arguments.') parser.add_argument('--process', action='store_const', const='process', dest='mode') parser.add_argument('--upload', action='store_const', const='upload', dest='mode') args = parser.parse_args() if not args.mode: parser.error("One of --process or --upload must be given") 

不过,也许最好是使用子命令来代替。

需求审查

  • 使用argparse (我会忽略这个)
  • 允许调用一个或两个动作(至less需要一个动作)。
  • 尝试通过Pythonic(我宁可称之为“POSIX”样)

在命令行上也有一些隐含的要求:

  • 以易于理解的方式向用户解释用法
  • 选项应是可选的
  • 允许指定标志和选项
  • 允许与其他参数(如文件名或名称)结合使用。

使用docopt (文件managelog.py )的示例解决scheme:

 """Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print args 

尝试运行它:

 $ python managelog.py Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h 

显示帮助:

 $ python managelog.py -h Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> P managelog.py [options] upload -- <logfile>... Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> 

并使用它:

 $ python managelog.py -V -U user -P secret upload -- alfa.log beta.log {'--': True, '--pswd': 'secret', '--user': 'user', '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': False, 'upload': True} 

短替代short.py

可以有更短的变体:

 """Manage logfiles Usage: short.py [options] (process|upload)... -- <logfile>... short.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print args 

用法如下所示:

 $ python short.py -V process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 1, 'upload': 1} 

请注意,而不是“进程”和“上传”键的布尔值有计数器。

事实certificate,我们不能防止这些词的重复:

 $ python short.py -V process process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 2, 'upload': 1} 

结论

devise好的命令行界面在某些时候可能会遇到挑战。

基于命令行的程序有多个方面:

  • 好的命令行devise
  • select/使用适当的分析器

argparse提供了很多,但限制了可能的情况,并可能变得非常复杂。

随着docopt事情变得更短,同时保持可读性和提供高度的灵活性。 如果您pipe理从字典中获取分析的参数并手动(或通过其他库称为schema )进行一些转换(整数,打开文件..),您可能会发现docopt很适合命令行parsing。

我知道这是旧的污垢,但要求一个选项,但禁止多个(XOR)的方式是这样的:

 parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args() print args 

输出:

 >opt.py usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: one of the arguments -process -upload is required >opt.py -upload Namespace(process=False, upload=True) >opt.py -process Namespace(process=True, upload=False) >opt.py -upload -process usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: argument -process: not allowed with argument -upload 

如果您需要使用至less一个参数运行python程序,请添加一个没有选项前缀的参数( – 或 – 默认情况下)并设置nargs=+ (最less需要一个参数)。 我发现这个方法的问题是,如果你不指定参数,argparse将会产生一个“太less的参数”的错误,而不会打印出帮助菜单。 如果你不需要这个function,下面是代码中的方法:

 import argparse parser = argparse.ArgumentParser(description='Your program description') parser.add_argument('command', nargs="+", help='describe what a command is') args = parser.parse_args() 

认为当你添加一个带有选项前缀的参数时,nargs控制整个参数parsing器而不仅仅是选项。 (我的意思是,如果你有一个带有nargs="+" option ,那么 – --option标志至less有一个参数,如果你有option ,那么至less有一个参数。)

对于http://bugs.python.org/issue11588我正在探索通用处理像这样的情况的;mutually_exclusive_group概念的方法。

有了这个开发argparse.pyhttps://github.com/hpaulj/argparse_issues/blob/nested/argparse.py我可以写:;

 parser = argparse.ArgumentParser(prog='PROG', description='Log archiver arguments.') group = parser.add_usage_group(kind='any', required=True, title='possible actions (at least one is required)') group.add_argument('-p', '--process', action='store_true') group.add_argument('-u', '--upload', action='store_true') args = parser.parse_args() print(args) 

这会产生以下help

 usage: PROG [-h] (-p | -u) Log archiver arguments. optional arguments: -h, --help show this help message and exit possible actions (at least one is required): -p, --process -u, --upload 

这接受像“-u”,“-up”,“ – proc –up”等input。

它最终运行一个类似于https://stackoverflow.com/a/6723066/901925的testing,但错误消息需要更清楚:;

 usage: PROG [-h] (-p | -u) PROG: error: some of the arguments process upload is required 

我在想:

  • 是参数kind='any', required=True清楚的(接受任何一个组;至less有一个是必需的)?

  • 是用法(-p | -u)清除吗? 一个必需的互斥分组产生相同的事情。 有一些备选符号吗?

  • 比起phihag's简单testing,使用这样一个组更直观?

将append_const用于一系列操作,然后检查列表是否已填充:

 parser.add_argument('-process', dest=actions, const="process", action='append_const') parser.add_argument('-upload', dest=actions, const="upload", action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested') 

你甚至可以直接在常量中指定方法。

 def upload: ... parser.add_argument('-upload', dest=actions, const=upload, action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested') else: for action in args.actions: action() 

最好的方法是使用python内置模块add_mutually_exclusive_group

 parser = argparse.ArgumentParser(description='Log archiver arguments.') group = parser.add_mutually_exclusive_group() group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args() 

如果只想通过命令行select一个参数,只需使用required = True作为组的参数

 group = parser.add_mutually_exclusive_group(required=True)