[英]Two argparse arguments that can be either positional or optional
我正在尝试在 Python 3.5(Debian 9 提供的 Python 版本)中制作一个程序,该程序采用两个命令行参数:输入文件名和输出文件名。
-i
开头。-i
,则它必须跟在输入文件名之后或本身前面有-o
。因此我想接受以下命令行:
programname.py infilename
programname.py -i infilename
programname.py infilename outfilename
programname.py -i infilename outfilename
programname.py infilename -o outfilename
programname.py -i infilename -o outfilename
programname.py outfilename -i infilename
programname.py -o outfilename -i infilename
programname.py -o outfilename infilename
使用消息可能如下所示:
programname.py [-i] infilename [[-o] outfilename]
但是我无法从argparse
模块的文档中得知如何在add_argument()
参数中表达这一点。 当我为单个参数指定两个名称时,一个是位置名称,一个是命名参数, add_argument()
会引发异常:
ValueError: invalid option string 'infilename': must start with a character '-'
我在 Stack Overflow 上搜索了类似的问题,并找到了hpaulj 对 Python argparse 的回答 - 强制参数 - 位置或可选以及hpaulj 对 argparse 的回答:让相同的必需参数为位置或可选。 这些答案中的构造使用一组两个相互排斥的参数,一个是位置参数,一个是命名参数。 但它似乎不适用于多个此类参数。 尝试使用以这种方式构建的解析器解析-i infilename outfilename
会产生不同的异常:
argparse.ArgumentError: argument INFILE: not allowed with argument -i
但是, argparse
本身无法打印此异常,甚至无法显示--help
:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
[8+ layers of method calls within `argparse.py` omitted]
File "/usr/lib/python3.5/argparse.py", line 396, in _format_actions_usage
start = actions.index(group._group_actions[0])
IndexError: list index out of range
不推荐使用的optparse
模块将位置参数存储在一个单独的列表中,解析后运行的代码可以读取以填充每个is None
参数。 argparse
此列表的直接对应物是parser.add_argument('args', nargs=argparse.REMAINDER)
。 在调用parse_args()
之后手动处理位置参数是使用argparse
接受上面显示的所有命令行形式的唯一方法吗?
#!/usr/bin/env python3
import argparse
import traceback
def mkparser1():
"""Raise an error.
ValueError: invalid option string 'infilename': must start with a character '-'
"""
parser = argparse.ArgumentParser()
parser.add_argument("infilename", "-i", metavar="INFILE")
parser.add_argument("outfilename", "-o", required=False, metavar="INFILE")
return parser
def mkparser2():
"""Do not raise an error but return an inadequate parser.
When asked -i infilename outfilename
"""
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("infilename", nargs="?", metavar="INFILE")
group.add_argument('-i', dest="infilename", metavar="INFILE")
group = parser.add_mutually_exclusive_group(required=False)
parser.add_argument("outfilename", nargs="?", metavar="OUTFILE")
parser.add_argument("-o", dest="outfilename", metavar="OUTFILE")
return parser
def test():
parser = mkparser2()
argstrings = [
"infilename",
"-i infilename",
"infilename outfilename",
"-i infilename outfilename",
"infilename -o outfilename",
"-i infilename -o outfilename",
"outfilename -i infilename",
"-o outfilename -i infilename",
"-o outfilename infilename",
"--help",
]
for s in argstrings:
print("for", s)
try:
pargs = parser.parse_args(s.split())
except Exception as e:
traceback.print_exc()
else:
print("infilename is %s and outfilename is %s"
% (pargs.infilename, pargs.outfilename))
if __name__=='__main__':
test()
您也许可以让您的程序接受可变数量的位置参数(0 到 2 之间),这些参数将添加到位置参数列表(使用action="append"
),并调用add_argument("-i",...)
和add_argument("-o",...)
来处理标志等价物。
通常,argparse 选项属于位置或可选类别(但不是两者)。 因此,您需要将设置传递给 argparse 以允许一些冗余,并在解析后处理冲突。 例如,您可以将 argparse 配置为通过-i INPUT
和作为位置INPUT
接受输入文件,然后在解析后添加自定义检查以确保仅使用两种形式之一。
伪代码:
parser.add_argument('infile', metavar="INFILE", nargs='?',
type=argparse.FileType('r'),
action='append', dest="positional_args")
parser.add_argument('outfile', metavar="OUTFILE", nargs='?',
type=argparse.FileType('w'),
action='append', dest="positional_args")
parser.add_argument('-i', metavar="INFILE", dest="infile", default=None)
parser.add_argument('-o', metavar="OUTFILE", dest="outfile", default=None)
args = parser.parse_args([....])
# here insert check for conflicts between len(args.positional_args) and -i and -o
# example:
if sum([len(args.positional_args),
args.infile is not None,
args.outfile is not None]) != 2:
parser.print_help()
sys.exit(1)
...
infile = args.infile or args.positional_args.pop(0)
outfile = args.outfile or args.positional_args.pop(0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.