Python argparse:至少需要一个参数

时间:2011-07-17 09:24:12

标签: python argparse

我一直在使用argparse来创建一个可以-process-upload或两者兼有的Python程序:

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()

如果没有至少一个参数,程序就毫无意义。如何配置argparse以强制选择至少一个参数?

更新

评论之后:使用至少一个选项参数化程序的Pythonic方法是什么?

11 个答案:

答案 0 :(得分:83)

if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

答案 1 :(得分:26)

args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

答案 2 :(得分:20)

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

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")

尽管如此,使用subcommands可能更好。

答案 3 :(得分:14)

我知道这很古老,但需要一个选项但禁止多个(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  

答案 4 :(得分:8)

要求审核

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

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

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

使用docopt(文件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

尝试运行它:

$ 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}

请注意,“process”和“upload”键的布尔值不是计数器。

事实证明,我们无法阻止这些词的重复:

$ 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}

结论

设计良好的命令行界面有时可能具有挑战性。

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

  • 良好的命令行设计
  • 选择/使用适当的解析器

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

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

答案 5 :(得分:6)

执行此操作的最佳方法是使用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()

如果您只想通过命令行选择一个参数,请使用required = True作为组的参数

group = parser.add_mutually_exclusive_group(required=True)

答案 6 :(得分:4)

如果您需要使用至少一个参数运行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()

认为当您添加带有选项前缀的参数时,nargs控制整个参数解析器而不仅仅是选项。 (我的意思是,如果您的--option标记为nargs="+",那么--option标记至少需要一个参数。如果您option nargs="+" ,它预计至少有一个论点。)

答案 7 :(得分:4)

对于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'等输入。

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

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

我想知道:

  • 参数kind='any', required=True足够清楚(接受任何一组;至少需要一个)?

  • 使用(-p | -u)清楚了吗?必需的mutual_exclusive_group产生相同的东西。是否有其他替代符号?

  • 使用这样的组比phihag's简单测试更直观吗?

答案 8 :(得分:1)

将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()

答案 9 :(得分:1)

也许使用子解析器?

import argparse

parser = argparse.ArgumentParser(description='Log archiver arguments.')
subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help')
parser_process = subparsers.add_parser('process', help='Process logs')
parser_upload = subparsers.add_parser('upload', help='Upload logs')
args = parser.parse_args()

print("Subparser: ", args.subparser_name)

现在--help显示:

$ python /tmp/aaa.py --help
usage: aaa.py [-h] {process,upload} ...

Log archiver arguments.

positional arguments:
  {process,upload}  sub-command help
    process         Process logs
    upload          Upload logs

optional arguments:
  -h, --help        show this help message and exit
$ python /tmp/aaa.py
usage: aaa.py [-h] {process,upload} ...
aaa.py: error: too few arguments
$ python3 /tmp/aaa.py upload
Subparser:  upload

您也可以向这些子解析器添加其他选项。另外,除了使用该dest='subparser_name'之外,您还可以绑定要在给定子命令上直接调用的函数(请参见文档)。

答案 10 :(得分:0)

这可以达到目的,并且也会在argparse自动生成的--help输出中得到反映,这是大多数理智的程序员想要的(也可以使用可选参数):

parser.add_argument(
    'commands',
    nargs='+',                      # require at least 1
    choices=['process', 'upload'],  # restrict the choice
    help='commands to execute'
)

有关此的官方文档: https://docs.python.org/3/library/argparse.html#choices