如果参数无效,则将该文件作为 argparse-error 消息的命令行参数

我目前使用的 argparse 是这样的:

import argparse
from argparse import ArgumentParser


parser = ArgumentParser(description="ikjMatrix multiplication")
parser.add_argument("-i", dest="filename", required=True,
help="input file with two matrices", metavar="FILE")
args = parser.parse_args()


A, B = read(args.filename)
C = ikjMatrixProduct(A, B)
printMatrix(C)

现在我要注意的是,-i的参数应该是一个可读的文件。我该怎么做?

我已经尝试添加 type=opentype=argparse.FileType('r')和他们的工作,但如果文件是无效的,我想得到一个错误消息。我该怎么做?

96783 次浏览

It's pretty easy actually. You just need to write a function which checks if the file is valid and writes an error otherwise. Use that function with the type option. Note that you could get more fancy and create a custom action by subclassing argparse.Action, but I don't think that is necessary here. In my example, I return an open file handle (see below):

#!/usr/bin/env python


from argparse import ArgumentParser
import os.path




def is_valid_file(parser, arg):
if not os.path.exists(arg):
parser.error("The file %s does not exist!" % arg)
else:
return open(arg, 'r')  # return an open file handle




parser = ArgumentParser(description="ikjMatrix multiplication")
parser.add_argument("-i", dest="filename", required=True,
help="input file with two matrices", metavar="FILE",
type=lambda x: is_valid_file(parser, x))
args = parser.parse_args()


A, B = read(args.filename)
C = ikjMatrixProduct(A, B)
printMatrix(C)

I have just found this one:

def extant_file(x):
"""
'Type' for argparse - checks that file exists but does not open.
"""
if not os.path.exists(x):
# Argparse uses the ArgumentTypeError to give a rejection message like:
# error: argument input: x does not exist
raise argparse.ArgumentTypeError("{0} does not exist".format(x))
return x


if __name__ == "__main__":
import argparse, sys, os
from argparse import ArgumentParser


parser = ArgumentParser(description="ikjMatrix multiplication")
parser.add_argument("-i", "--input",
dest="filename", required=True, type=extant_file,
help="input file with two matrices", metavar="FILE")
args = parser.parse_args()


A, B = read(args.filename)
C = ikjMatrixProduct(A, B)
printMatrix(C, args.output)

Source: fhcrc.github.com

A way to do this in Python 3.4 is to use the argparse.FileType class. Make sure to close the input stream when you are finished. This is also useful because you can use the pseudo-argument '-' for STDIN/STDOUT. From the documentation:

FileType objects understand the pseudo-argument '-' and automatically convert this into sys.stdin for readable FileType objects and sys.stdout for writable FileType objects

Example:

#!/usr/bin/env python3


import argparse


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--infile', type=argparse.FileType('r', encoding='UTF-8'),
required=True)
args = parser.parse_args()
print(args)
args.infile.close()

And then when ran...

  • Without argument:

    $ ./stack_overflow.py
    usage: stack_overflow.py [-h] --infile INFILE
    stack_overflow.py: error: the following arguments are required: --infile
    
  • With nonexistent file:

    $ ./stack_overflow.py --infile notme
    usage: stack_overflow.py [-h] --infile INFILE
    stack_overflow.py: error: argument --infile: can't open 'notme': [Errno 2] No such file or directory: 'notme'
    
  • With an existing file:

    $ ./stack_overflow.py --infile ./stack_overflow.py
    Namespace(infile=<_io.TextIOWrapper name='./stack_overflow.py' mode='r' encoding='UTF-8'>)
    
  • Using '-' for STDIN:

    $ echo 'hello' | ./stack_overflow.py --infile -
    Namespace(infile=<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>)
    

Using argparse on python3.8+. This returns Pathlib.Path.

import argparse
from pathlib import Path


def validate_file(arg):
if (file := Path(arg)).is_file():
return file
else:
raise FileNotFoundError(arg)


parser = argparse.ArgumentParser()
parser.add_argument(
"--file", type=validate_file, help="Input file path", required=True
)
args = parser.parse_args()