2012-07-18 14 views
35

Obecnie używam argparse tak:pliku jako argument wiersza polecenia dla argparse - komunikat o błędzie, jeśli argument nie jest prawidłowy

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) 

Teraz chciałbym zwrócić uwagę, że argument -i powinien być plik czytelny . Jak mogę to zrobić?

Próbowałem dodać type=open, type=argparse.FileType('r') i zadziałały, ale jeśli plik nie jest prawidłowy, chciałbym otrzymać komunikat o błędzie. Jak mogę to zrobić?

Odpowiedz

57

To całkiem proste. Trzeba tylko napisać funkcję, która sprawdza, czy plik jest prawidłowy i zapisuje błąd w przeciwnym razie. Użyj tej funkcji z opcją type. Zauważ, że możesz uzyskać więcej wyobraźni i utworzyć niestandardowe działanie, podklasy argparse.Action, ale nie sądzę, że jest to konieczne tutaj. W moim przykładzie, wracam otwarty uchwyt pliku (patrz poniżej):

#!/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 - Jeszcze jeden komentarz. 'os.path.isfile' może być bardziej odpowiednie niż' os.path.exists' (w zależności od tego, czy chcesz również akceptować katalogi) – mgilson

+9

Właściwie uważa się, że lepiej jest spróbować otworzyć plik za pomocą bloku try-except, niż sprawdzić istnienie – jarondl

+3

@jarondl ma rację. Należy to zmienić, aby użyć 'try: ... except IOError', aby uniknąć potencjalnych warunków wyścigu. W większości przypadków nie ma to znaczenia, ale ostatnio mnie to ugryzło. – AlexLordThorsen

13

Właśnie znalazł to jedno:

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) 

Źródło: fhcrc.github.com

+5

Jeśli użyjesz 'argparse.ArgumentTypeError' zamiast' argparse.ArgumentError', komunikat zostanie wydrukowany. – draganHR

16

sposób zrobić to w Pythonie 3.4 należy użyć klasy argparse.FileType. Po zakończeniu należy zamknąć strumień wejściowy. Jest to również użyteczne, ponieważ możesz użyć pseudo-argumentu '-' dla STDIN/STDOUT. Z dokumentacji:

obiekty filetype zrozumieć pseudo-argumentów '-' i automatycznie konwertować to pod sys.stdin dla czytelnych FileType obiektów i sys.stdout do zapisu dla FileType obiektów

Przykład:

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

I następnie po uruchomieniu ...

  • Bez argumentu:

    $ ./stack_overflow.py 
    usage: stack_overflow.py [-h] --infile INFILE 
    stack_overflow.py: error: the following arguments are required: --infile 
    
  • Z nieistniejącego pliku:

    $ ./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' 
    
  • z istniejącego pliku:

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

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

'argparse.FileType' jest również dostępny w Pythonie 2.7. – jared

Powiązane problemy