2012-07-18 25 views
35

我目前使用argparse这样有效:文件作为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=open,type=argparse.FileType('r')他们工作,但如果文件无效,我想获得一个错误信息。我怎样才能做到这一点?

回答

57

实际上这很容易。你只需要编写一个函数来检查文件是否有效,否则写入错误。与type选项一起使用该功能。请注意,您可以获得更多幻想并通过继承argparse.Action来创建自定义操作,但我认为这不是必要的。在我的例子,我返回一个打开的文件句柄(见下文):

#!/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) 
+0

@moose - 一个其他评论。 'os.path.isfile'可能比'os.path.exists'更合适(取决于你是否也想接受目录) – mgilson 2012-07-18 12:44:13

+9

实际上,尝试使用try-except块打开文件被认为是更好的做法,比检查是否存在 – jarondl 2013-07-06 12:45:50

+3

@jarondl是对的。这应该改为使用'try:...除了IOError'以避免潜在的竞争条件。对于大多数情况下它并不重要,但最近这让我感到困扰。 – AlexLordThorsen 2015-05-27 00:27:31

13

我刚刚发现这一个:

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) 

来源:fhcrc.github.com

+5

如果使用'argparse.ArgumentTypeError'而不是'argparse.ArgumentError',则会打印出消息。 – draganHR 2015-09-22 10:56:44

16

在Python做到这一点的方法3.4是使用argparse.FileType类。确保完成后关闭输入流。这也很有用,因为您可以使用STDIN/STDOUT的伪参数'-'。从文档:

FILETYPE对象理解伪参数'-',并自动转换为sys.stdin为可读FileType对象和sys.stdout这对于可写FileType对象

实施例:

#!/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() 

而然后当跑...

  • 没有参数:

    $ ./stack_overflow.py 
    usage: stack_overflow.py [-h] --infile INFILE 
    stack_overflow.py: error: the following arguments are required: --infile 
    
  • 有了不存在的文件:

    $ ./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' 
    
  • 与现有的文件:

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

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

'argparse.FileType'在Python 2.7中也可用。 – jared 2016-07-11 18:22:11