I've been using argparse
for a Python program that can -prepare
, -upload
or both:
我一直在使用一个Python程序的argparse,它可以-准备,-上传,或者两者都有:
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()
The program is meaningless without at least one parameter. How can I configure argparse
to force at least one parameter to be chosen?
没有至少一个参数,程序就毫无意义。如何配置argparse以强制选择至少一个参数?
UPDATE:
更新:
Following the comments: What's the Pythonic way to parametrize a program with at least one option?
注释:使用至少一个选项对程序进行参数化的python方法是什么?
9 个解决方案
#1
66
if not (args.process or args.upload):
parser.error('No action requested, add -process or -upload')
#2
20
args = vars(parser.parse_args())
if not any(args.values()):
parser.error('No arguments provided.')
#3
17
If not the 'or both' part (I have initially missed this) you could use something like this:
如果不是“或两者”部分(我最初错过了这个),您可以使用如下的方法:
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")
Though, probably it would be a better idea to use subcommands instead.
不过,使用子命令可能是更好的主意。
#4
8
Requirements Review
- use
argparse
(I will ignore this one) - 使用argparse(我将忽略这个)
- allow one or two actions to be called (at least one required).
- 允许调用一个或两个动作(至少需要一个)。
- try to by Pythonic (I would rather call it "POSIX"-like)
- 用python(我更愿意称它为POSIX)
There are also some implicit requirements when living on command line:
在命令行中也有一些隐含的需求:
- explain the usage to the user in a way which is easy to understand
- 用易于理解的方式向用户解释用法。
- options shall be optional
- 选择应可选
- allow specifying flags and options
- 允许指定标志和选项。
- allow combining with other parameters (like file name or names).
- 允许结合其他参数(如文件名或名称)。
Sample solution using docopt
(file managelog.py
):
"""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
Try to run it:
尝试运行:
$ python managelog.py
Usage:
managelog.py [options] process -- <logfile>...
managelog.py [options] upload -- <logfile>...
managelog.py [options] process upload -- <logfile>...
managelog.py -h
Show the help:
显示帮助:
$ 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>
And use it:
并使用它:
$ 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 alternative short.py
There can be even shorter variant:
甚至可以有更短的变体:
"""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
Usage looks like this:
使用看起来像这样:
$ 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}
Note, that instead of boolean values for "process" and "upload" keys there are counters.
注意,不是“进程”和“上传”键的布尔值,而是计数器。
It turns out, we cannot prevent duplication of these words:
事实证明,我们不能阻止这些词的重复:
$ 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}
Conclusions
Designing good command line interface can be challenging sometime.
设计好的命令行界面有时是很有挑战性的。
There are multiple aspects of command line based program:
基于命令行的程序有多个方面:
- good design of command line
- 良好的命令行设计。
- selecting/using proper parser
- 选择/使用适当的解析器
argparse
offers a lot, but restricts possible scenarios and can become very complex.
argparse提供了很多,但是限制了可能的场景,并且可能变得非常复杂。
With docopt
things go much shorter while preserving readability and offering high degree of flexibility. If you manage getting parsed arguments from dictionary and do some of conversions (to integer, opening files..) manually (or by other library called schema
), you may find docopt
good fit for command line parsing.
使用docopt的东西要短得多,同时保持可读性,并提供高度的灵活性。如果您管理从字典中获得解析的参数,并执行一些转换(到整数、打开文件..),手动(或者通过其他称为模式的库),您可能会发现docopt非常适合于命令行解析。
#5
7
I know this is old as dirt, but the way to require one option but forbid more than one (XOR) is like this:
我知道这很古老,但是需要一个选项但是禁止不止一个(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
Output:
输出:
>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
#6
4
If you require a python program to run with at least one parameter, add an argument that doesn't have the option prefix (- or -- by default) and set nargs=+
(Minimum of one argument required). The problem with this method I found is that if you do not specify the argument, argparse will generate a "too few arguments" error and not print out the help menu. If you don't need that functionality, here's how to do it in code:
如果您需要一个python程序以至少一个参数运行,则添加一个参数,该参数没有选项前缀(-或-默认),并设置nargs=+(至少需要一个参数)。这个方法的问题是,如果您没有指定参数,那么argparse将生成一个“太少的参数”错误,而不是打印帮助菜单。如果您不需要这个功能,下面是如何在代码中实现这个功能:
import argparse
parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()
I think that when you add an argument with the option prefixes, nargs governs the entire argument parser and not just the option. (What I mean is, if you have an --option
flag with nargs="+"
, then --option
flag expects at least one argument. If you have option
with nargs="+"
, it expects at least one argument overall.)
我认为当您添加一个带有选项前缀的参数时,nargs将管理整个参数解析器,而不仅仅是选项。(我的意思是,如果您有一个带有nargs="+"的选项标志,那么,选项标志至少需要一个参数。如果您有使用nargs="+"的选项,那么它至少需要一个参数。
#7
3
For http://bugs.python.org/issue11588 I am exploring ways of generalizing the mutually_exclusive_group
concept to handle cases like this.
对于http://bugs.python.org/e11588,我正在探索将mutually_sive_group概念一般化的方法来处理这样的情况。
With this development argparse.py
, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py I am able to write:
这种发展argparse。我可以写:
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)
which produces the following 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
This accepts inputs like '-u', '-up', '--proc --up' etc.
它接受诸如“-u”、“up”、“-proc -up”等输入。
It ends up running a test similar to https://*.com/a/6723066/901925, though the error message needs to be clearer:
它最终运行的测试类似于https://*.com/a/6723066/901925,但错误信息需要更清楚:
usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required
I wonder:
我想知道:
-
are the parameters
kind='any', required=True
clear enough (accept any of the group; at least one is required)?参数类型='any', required=True clear enough (accept any of the group;至少需要一个?
-
is usage
(-p | -u)
clear? A required mutually_exclusive_group produces the same thing. Is there some alternative notation?使用(-p | -u)清楚吗?一个必需的mutually_sive_group产生相同的东西。有没有其他的符号?
-
is using a group like this more intuitive than
phihag's
simple test?使用像这样的小组比phihag的简单测试更直观吗?
#8
1
Use append_const to a list of actions and then check that the list is populated:
使用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')
You can even specify the methods directly within the constants.
您甚至可以在常量中直接指定方法。
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()
#9
-1
The best way to do this is by using python inbuilt module add_mutually_exclusive_group.
最好的方法是使用python内置模块add_mutually_sive_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()
If you want only one argument to be selected by command line just use required=True as an argument for group
如果您只想用命令行来选择一个参数,那么就使用required=True作为组的参数。
group = parser.add_mutually_exclusive_group(required=True)
#1
66
if not (args.process or args.upload):
parser.error('No action requested, add -process or -upload')
#2
20
args = vars(parser.parse_args())
if not any(args.values()):
parser.error('No arguments provided.')
#3
17
If not the 'or both' part (I have initially missed this) you could use something like this:
如果不是“或两者”部分(我最初错过了这个),您可以使用如下的方法:
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")
Though, probably it would be a better idea to use subcommands instead.
不过,使用子命令可能是更好的主意。
#4
8
Requirements Review
- use
argparse
(I will ignore this one) - 使用argparse(我将忽略这个)
- allow one or two actions to be called (at least one required).
- 允许调用一个或两个动作(至少需要一个)。
- try to by Pythonic (I would rather call it "POSIX"-like)
- 用python(我更愿意称它为POSIX)
There are also some implicit requirements when living on command line:
在命令行中也有一些隐含的需求:
- explain the usage to the user in a way which is easy to understand
- 用易于理解的方式向用户解释用法。
- options shall be optional
- 选择应可选
- allow specifying flags and options
- 允许指定标志和选项。
- allow combining with other parameters (like file name or names).
- 允许结合其他参数(如文件名或名称)。
Sample solution using docopt
(file managelog.py
):
"""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
Try to run it:
尝试运行:
$ python managelog.py
Usage:
managelog.py [options] process -- <logfile>...
managelog.py [options] upload -- <logfile>...
managelog.py [options] process upload -- <logfile>...
managelog.py -h
Show the help:
显示帮助:
$ 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>
And use it:
并使用它:
$ 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 alternative short.py
There can be even shorter variant:
甚至可以有更短的变体:
"""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
Usage looks like this:
使用看起来像这样:
$ 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}
Note, that instead of boolean values for "process" and "upload" keys there are counters.
注意,不是“进程”和“上传”键的布尔值,而是计数器。
It turns out, we cannot prevent duplication of these words:
事实证明,我们不能阻止这些词的重复:
$ 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}
Conclusions
Designing good command line interface can be challenging sometime.
设计好的命令行界面有时是很有挑战性的。
There are multiple aspects of command line based program:
基于命令行的程序有多个方面:
- good design of command line
- 良好的命令行设计。
- selecting/using proper parser
- 选择/使用适当的解析器
argparse
offers a lot, but restricts possible scenarios and can become very complex.
argparse提供了很多,但是限制了可能的场景,并且可能变得非常复杂。
With docopt
things go much shorter while preserving readability and offering high degree of flexibility. If you manage getting parsed arguments from dictionary and do some of conversions (to integer, opening files..) manually (or by other library called schema
), you may find docopt
good fit for command line parsing.
使用docopt的东西要短得多,同时保持可读性,并提供高度的灵活性。如果您管理从字典中获得解析的参数,并执行一些转换(到整数、打开文件..),手动(或者通过其他称为模式的库),您可能会发现docopt非常适合于命令行解析。
#5
7
I know this is old as dirt, but the way to require one option but forbid more than one (XOR) is like this:
我知道这很古老,但是需要一个选项但是禁止不止一个(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
Output:
输出:
>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
#6
4
If you require a python program to run with at least one parameter, add an argument that doesn't have the option prefix (- or -- by default) and set nargs=+
(Minimum of one argument required). The problem with this method I found is that if you do not specify the argument, argparse will generate a "too few arguments" error and not print out the help menu. If you don't need that functionality, here's how to do it in code:
如果您需要一个python程序以至少一个参数运行,则添加一个参数,该参数没有选项前缀(-或-默认),并设置nargs=+(至少需要一个参数)。这个方法的问题是,如果您没有指定参数,那么argparse将生成一个“太少的参数”错误,而不是打印帮助菜单。如果您不需要这个功能,下面是如何在代码中实现这个功能:
import argparse
parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()
I think that when you add an argument with the option prefixes, nargs governs the entire argument parser and not just the option. (What I mean is, if you have an --option
flag with nargs="+"
, then --option
flag expects at least one argument. If you have option
with nargs="+"
, it expects at least one argument overall.)
我认为当您添加一个带有选项前缀的参数时,nargs将管理整个参数解析器,而不仅仅是选项。(我的意思是,如果您有一个带有nargs="+"的选项标志,那么,选项标志至少需要一个参数。如果您有使用nargs="+"的选项,那么它至少需要一个参数。
#7
3
For http://bugs.python.org/issue11588 I am exploring ways of generalizing the mutually_exclusive_group
concept to handle cases like this.
对于http://bugs.python.org/e11588,我正在探索将mutually_sive_group概念一般化的方法来处理这样的情况。
With this development argparse.py
, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py I am able to write:
这种发展argparse。我可以写:
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)
which produces the following 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
This accepts inputs like '-u', '-up', '--proc --up' etc.
它接受诸如“-u”、“up”、“-proc -up”等输入。
It ends up running a test similar to https://*.com/a/6723066/901925, though the error message needs to be clearer:
它最终运行的测试类似于https://*.com/a/6723066/901925,但错误信息需要更清楚:
usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required
I wonder:
我想知道:
-
are the parameters
kind='any', required=True
clear enough (accept any of the group; at least one is required)?参数类型='any', required=True clear enough (accept any of the group;至少需要一个?
-
is usage
(-p | -u)
clear? A required mutually_exclusive_group produces the same thing. Is there some alternative notation?使用(-p | -u)清楚吗?一个必需的mutually_sive_group产生相同的东西。有没有其他的符号?
-
is using a group like this more intuitive than
phihag's
simple test?使用像这样的小组比phihag的简单测试更直观吗?
#8
1
Use append_const to a list of actions and then check that the list is populated:
使用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')
You can even specify the methods directly within the constants.
您甚至可以在常量中直接指定方法。
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()
#9
-1
The best way to do this is by using python inbuilt module add_mutually_exclusive_group.
最好的方法是使用python内置模块add_mutually_sive_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()
If you want only one argument to be selected by command line just use required=True as an argument for group
如果您只想用命令行来选择一个参数,那么就使用required=True作为组的参数。
group = parser.add_mutually_exclusive_group(required=True)