使用python argparse

时间:2019-01-10 09:05:54

标签: python argparse

我正在使用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参数命令分组到一个列表中,然后在循环中定义解析器。这听起来很合理,但我不知道是否可能。否则,随着工具数量的增加,解析器本身将变得难以维护。

1 个答案:

答案 0 :(得分:0)

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