【问题标题】:Parse variable number of commands with python argparse使用 python argparse 解析可变数量的命令
【发布时间】:2019-01-13 00:14:38
【问题描述】:

我正在用 Python 开发一个命令行工具,它的功能被分解成许多子命令,基本上每个子命令都作为参数输入和输出文件。棘手的部分是每个命令需要不同数量的参数(有些不需要输出文件,有些需要多个输入文件等)。

理想情况下,接口将被称为:

./test.py ncinfo inputfile

然后,解析器会意识到ncinfo 命令需要一个参数(如果这不适合输入命令,它会抱怨),然后它会调用函数:

ncinfo(inputfile)

这才是真正的工作。

当命令需要更多选项时,例如

./test.py timmean inputfile outputfile

解析器会意识到这一点,检查是否确实给出了两个参数,然后它会调用:

timmean(inputfile, outputfile)

此方案理想地推广到任意列表的 1 参数命令、2 参数命令等。

但是,我正在努力使用 Python argparse 来实现这种行为。这是我目前所拥有的:

#! /home/navarro/SOFTWARE/anadonda3/bin/python
import argparse

# create the top-level parser
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

# create the parser for the "ncinfo" command
parser_1 = subparsers.add_parser('ncinfo', help='prints out basic netCDF strcuture')
parser_1.add_argument('filein', help='the input file')

# create the parser for the "timmean" command
parser_2 = subparsers.add_parser('timmean', help='calculates temporal mean and stores it in output file')
parser_2.add_argument('filein', help='the input file')
parser_2.add_argument('fileout', help='the output file')


# parse the argument lists
parser.parse_args()

print(parser.filein)
print(parser.fileout)    

但这并没有按预期工作。首先,当我调用不带参数的脚本时,我没有收到错误消息告诉我有哪些选项。其次,当我尝试运行程序以使用ncinfo 时,出现错误

./test.py ncinfo testfile
Traceback (most recent call last):
  File "./test.py", line 21, in <module>
    print(parser.filein)
AttributeError: 'ArgumentParser' object has no attribute 'filein'

我做错了什么导致我无法实现预期的行为?在这种情况下使用subparsers 是否合理?

奖励点:有没有办法概括命令的定义,这样我就不需要手动添加每个命令?例如,将所有 1 参数命令分组到一个列表中,然后在循环中定义解析器。这听起来很合理,但我不知道这是否可能。否则,随着工具数量的增加,解析器本身将变得难以维护。

【问题讨论】:

  • 您可以执行for name in one_arg_commands: 之类的操作,然后为此创建每个子解析器,然后创建for name in two_arg_commands:,等等。
  • 通常你会从argparse-h--help 得到help。没有参数时没有默认行为。在调试期间,我喜欢print(args) 来清楚地了解它设置了哪些属性。您可能还想将dest 添加到add_subparsers 以查看正在使用的子解析器。并设置args=parser.parse_args()。解析创建一个args命名空间;它不会修改parser
  • 我是个菜鸟,所以我可以相信默认设置是有充分理由的……但我不明白。当命令行不满足任何预期配置时,让程序继续运行似乎是个坏主意。事实上,@simleo 响应中的示例在没有给出参数时会崩溃(引发异常)。我希望解析器的行为就像使用了 -h 标志一样。实际上,这是不使用子命令时的行为。我很想相信这是一个错误......

标签: python argparse


【解决方案1】:
import argparse
import sys

SUB_COMMANDS = [
    "ncinfo",
    "timmean"
]


def ncinfo(args):
    print("executing: ncinfo")
    print("  inputfile: %s" % args.inputfile)


def timmean(args):
    print("executing: timmean")
    print("  inputfile: %s" % args.inputfile)
    print("  outputfile: %s" % args.outputfile)


def add_parser(subcmd, subparsers):
    if subcmd == "ncinfo":
        parser = subparsers.add_parser("ncinfo")
        parser.add_argument("inputfile", metavar="INPUT")
        parser.set_defaults(func=ncinfo)
    elif subcmd == "timmean":
        parser = subparsers.add_parser("timmean")
        parser.add_argument("inputfile", metavar="INPUT")
        parser.add_argument("outputfile", metavar="OUTPUT")
        parser.set_defaults(func=timmean)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--common-option', action='store_true')
    subparsers = parser.add_subparsers(help="sub-commands")
    for cmd in SUB_COMMANDS:
        add_parser(cmd, subparsers)
    args = parser.parse_args(sys.argv[1:])
    if args.common_option:
        print("common option is active")
    try:
        args.func(args)
    except AttributeError:
        parser.error("too few arguments")

一些使用示例:

$ python test.py --help
usage: test.py [-h] [-o] {ncinfo,timmean} ...

positional arguments:
  {ncinfo,timmean}     sub-commands

optional arguments:
  -h, --help           show this help message and exit
  -o, --common-option
$ python test.py ncinfo --help
usage: test.py ncinfo [-h] INPUT

positional arguments:
  INPUT

optional arguments:
  -h, --help  show this help message and exit
$ python test.py timmean --help
usage: test.py timmean [-h] INPUT OUTPUT

positional arguments:
  INPUT
  OUTPUT

optional arguments:
  -h, --help  show this help message and exit
$ python test.py -o ncinfo foo
common option is active
executing: ncinfo
  inputfile: foo
$ python test.py -o timmean foo bar
common option is active
executing: timmean
  inputfile: foo
  outputfile: bar

【讨论】:

  • 非常感谢您直接明确的回答。这确实解决了这个问题。我仍然看到的唯一警告是,当没有给出参数时,这个程序会崩溃(引发 AttributeError 异常)。我希望在这种情况下,解析器的行为就像使用了 -h 标志一样。当使用没有子解析器的更简单的解析器时,这似乎确实是行为。这种行为是不是不一致?是否可以在不提供参数时更改行为以停止脚本?
  • 是的,这是不一致的,它看起来像是在 Python 3 中引入的。如果你在 Python2 中运行没有参数的脚本,它会以“错误:参数太少”干净地退出。我已经更新了上面的代码以在 Python 3 中获得相同的行为
猜你喜欢
  • 2013-09-13
  • 2014-07-10
  • 2016-01-18
  • 2020-09-06
  • 2013-02-27
  • 2012-05-13
  • 2017-01-31
相关资源
最近更新 更多