Python argparse require选项,取决于定义的标志

SaA*_*mic 2 python arguments parameter-passing optional-parameters argparse

我有一个小的python脚本,argparse用于让用户定义选项。它为不同的模式使用两个标志,并使用一个参数让用户定义文件。请参见下面的简化示例:

#!/usr/bin/python3

import argparse
from shutil import copyfile

def check_file(f):
    # Mock function: checks if file exists, else "argparse.ArgumentTypeError("file not found")"
    return f

def main():
    aFile = "/tmp/afile.txt"

    parser = argparse.ArgumentParser(description="An example",formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument("-f", "--file", help="A file, used with method A.", default=aFile, type=check_file)
    parser.add_argument("-a", "--ay", help="Method A, requires file.", action='store_true')
    parser.add_argument("-b", "--be", help="Method B, no file required.", action='store_true')

    args = parser.parse_args()
    f = args.file
    a = args.ay
    b = args.be

    if a:
        copyfile(f, f+".a")
    elif b:
        print("Method B")

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

方法A需要该文件。

方法B没有。

如果使用方法A运行脚本,则将使用默认文件或使用-f/ 定义的文件--file。该脚本检查文件是否存在,并且一切正常。

现在,如果我使用方法B运行脚本,则该脚本不需要该文件,但是将检查默认选项,并且如果不存在该默认选项,则argparse函数将引发异常并退出脚本。

如何配置argparse以使其成为-f可选(如果-b已定义)并要求它(如果-a已定义)?

编辑:我只是意识到,这将是足以让我做-f-b相互排斥。但是,如果我-b仅运行,check_file则无论如何都会执行。有办法防止这种情况吗?

#!/usr/bin/python3

import argparse
from shutil import copyfile

def check_file(f):
    # Mock function: checks if file exists, else "argparse.ArgumentTypeError("file not found")"
    print("chk file")
    return f

def main():
    aFile = "/tmp/afile.txt"

    parser = argparse.ArgumentParser(description="An example",formatter_class=argparse.RawTextHelpFormatter)
    group = parser.add_mutually_exclusive_group(required=True)

    group.add_argument("-f", "--file", help="A file, used with method A.", default=aFile, type=check_file)
    parser.add_argument("-a", "--ay", help="Method A, requires file.", action='store_true')
    group.add_argument("-b", "--be", help="Method B, no file required.", action='store_true')

    args = parser.parse_args()
    f = args.file
    a = args.ay
    b = args.be

    if a:
        print("File: "+str(f))
    elif b:
        print("Method B")
        print("file: "+str(f))

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

输出:

chk file
Method B
file: /tmp/afile.txt
Run Code Online (Sandbox Code Playgroud)

小智 5

您可以使用y / be作为子命令定义子解析器,或者为a声明第二个解析器实例。就像是:

parser = argparse.ArgumentParser(
    description="An example",
    formatter_class=argparse.RawTextHelpFormatter
)
# ensure either option -a or -b only
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-a", "--ay", help="Method A, requires file.",
                   action='store_true')
group.add_argument("-b", "--be", help="Method B, no file required.",
                   action='store_true')
# define a parser for option -a
parser_a = argparse.ArgumentParser()
parser_a.add_argument("-f", "--file", help="A file, used with method A.",
                      type=check_file, required=True)
parser_a.add_argument("-a", "--ay", help="Method A, requires file.",
                      action='store_true')

# first parse - get either -a/-b
args = parser.parse_known_args(sys.argv[1:])
# if -a, use the second parser to ensure -f is in argument
# note parse_known_args return tuple, the first one is the populated namespace
if args[0].ay:
    args = parser_a.parse_args(sys.argv[1:])
Run Code Online (Sandbox Code Playgroud)