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