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.py
, https://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)