2016-05-26 21 views
9

Czy jest możliwe, aby za pomocą modułu argparse dodać sprawdzanie poprawności podczas analizowania argumentów?Python: Sprawdzanie poprawności podczas sprawdzania argumentów

from argparse import ArgumentParser 

parser = ArgumentParser(description='Argument parser for PG restore') 

parser.add_argument('--database', dest='database', 
        default=None, required=False, help='Database to restore') 

parser.add_argument('--backup', dest='backup', 
        required=True, help='Location of the backup file') 

parsed_args = parser.parse_args() 

Czy byłoby możliwe, aby dodać sprawdzanie poprawności do tego analizatora argumentów, aby upewnić się, że istnieje plik kopii zapasowej/baza danych? Zamiast konieczności dodawania dodatkowej kontroli po tym dla każdego parametru ...

from os.path import exists 
if not database_exists(parsed_args.database): 
    raise DatabaseNotFoundError 
if not exists(parsed_args.backup): 
    raise FileNotFoundError 

Odpowiedz

11

Fabryka argparse.FileType jest klasą fabryczną, która może otworzyć plik, i oczywiście w procesie wywołuje błąd, jeśli plik nie istnieje lub nie można go utworzyć. Możesz spojrzeć na jego kod, aby zobaczyć, jak stworzyć własną klasę (lub funkcję), aby przetestować swoje dane wejściowe.

Argument type parametr jest wymagalne (funkcja, etc), która pobiera ciąg, testuje go, ile potrzeba, i konwertuje je (w razie potrzeby) do rodzaju wartości chcesz zapisać się do nazw args. Więc może wykonać dowolne testy. Jeśli type wywoła błąd, to analizator tworzy komunikat o błędzie (i użycie) i kończy działanie.

To, czy to odpowiednie miejsce do przeprowadzenia testu, zależy od Twojej sytuacji. Czasami otwieranie pliku z FileType jest w porządku, ale musisz go zamknąć sam lub poczekać na zakończenie programu. Nie możesz użyć tego otwartego pliku w kontekście with open(filename) as f:. To samo może dotyczyć twojej bazy danych. W złożonym programie możesz nie chcieć otwierać ani tworzyć pliku od razu.

Napisałem dla błędu/wydania Pythona odmianę FileType, która utworzyła obiekt context, obiekt, który może być użyty w kontekście with. Użyłem także testów os, aby sprawdzić, czy plik istnieje, czy może zostać utworzony, bez faktycznego wykonania. Wymagało to jednak dalszych sztuczek, jeśli file byłby , którego nie chcesz zamykać. Czasami próby zrobienia tego w ten sposób w argparse to po prostu więcej pracy niż jest warta.

W każdym razie, jeśli masz łatwą metodę testowania, można owinąć je w prosty type funkcję tak:

def database(astring): 
    from os.path import exists 
    if not database_exists(astring): 
     raise ValueError # or TypeError, or `argparse.ArgumentTypeError 
    return astring 

parser.add_argument('--database', dest='database', 
       type = database, 
       default=None, required=False, help='Database to restore') 

Nie sądzę, jest to ważne dużo czy wdrożenie takiego badania w type lub . Myślę, że type jest prostszy i bardziej zgodny z intencjami programisty.

+1

Świetna odpowiedź! Chciałbym polecić użycie argparse.ArgumentTypeError (message) w celu wydrukowania "message" na konsoli. – tabata

10

Na pewno! Musisz tylko określić akcję niestandardową jako klasę i zastąpić __call__(..). Link to documentation.

Coś jak:

import argparse 

class FooAction(argparse.Action): 
    def __call__(self, parser, namespace, values, option_string=None): 
     if values != "bar": 
      print "Got value:", values 
      raise ValueError("Not a bar!") 
     setattr(namespace, self.dest, values) 


parser = argparse.ArgumentParser() 
parser.add_argument("--foo", action=FooAction) 

parsed_args = parser.parse_args() 

W danym przypadku, wyobrażam sobie, że masz DatabaseAction i FileAction (lub coś podobnego).

Powiązane problemy