2011-11-23 7 views
12

Diciamo che ho uno script che funziona su un file. Prende il nome di questo file sulla riga di comando, ma se non viene fornito, il valore predefinito è un nome file noto (content.txt, ad esempio). Con pitone di argparse, io uso il seguente:Specificare i nomi file predefiniti con argparse, ma non aprirli su --help?

parser = argparse.ArgumentParser(description='my illustrative example') 
parser.add_argument('--content', metavar='file', 
        default='content.txt', type=argparse.FileType('r'), 
        help='file to process (defaults to content.txt)') 
args = parser.parse_args() 
# do some work on args.content, which is a file-like object 

Questa grande opera. L'unico problema è che se corro python myscript --help, ottengo un ArgumentError se il file non è lì (che immagino abbia senso), e il testo di aiuto non viene mostrato. Preferisco non provare ad aprire il file se l'utente vuole solo --help. C'è un modo per fare questo? So che potrei fare l'argomento una stringa e prendersi cura di apertura del file stesso più tardi (e ho fatto quello), ma sarebbe conveniente avere argparse prendersi cura di esso.

+0

Beh, sembra che si dovrà prendere una decisione qui. Puoi rendere disponibile il file predefinito (in quanto è un 'default') o semplicemente aprire il file te stesso, come hai suggerito tu stesso. In alternativa, sembra che tu possa usare lo stdin come predefinito, tuttavia non sarai in grado di specificare un nome di file predefinito, che potrebbe non essere una cattiva opzione se non vuoi popolare quel file. –

risposta

9

Guardando il codice argparse, vedo:

  • ArgumentParser.parse_args chiamate parse_known_args e fa in modo che non v'è alcuna argomentazione in attesa di essere analizzato.
  • ArgumentParser.parse_known_args valori insiemi predefiniti e chiede ArgumentParser._parse_known_args

Quindi, la soluzione sarebbe quella di utilizzare ArgumentParser._parse_known_args direttamente per rilevare -h e, dopo che utilizzano ArgumentParser.parse_args come al solito.

import sys, argparse 
parser = argparse.ArgumentParser(description='my illustrative example', argument_default=argparse.SUPPRESS) 
parser.add_argument('--content', metavar='file', 
        default='content.txt', type=argparse.FileType('r'), 
        help='file to process (defaults to content.txt)') 
parser._parse_known_args(sys.argv[1:], argparse.Namespace()) 
args = parser.parse_args() 

Nota che ArgumentParser._parse_known_args ha bisogno di un paio di parametri: gli argomenti della riga di comando e lo spazio dei nomi.

Naturalmente, io non consiglio questo approccio in quanto sfrutta il argparse implementazione interna e che potrebbe cambiare in futuro. Tuttavia, non lo trovo troppo disordinato, quindi potresti ancora volerlo usare se pensi che i rischi per la manutenzione possano ripagare.

+0

Sembra che non ci sia davvero una bella soluzione a questo, ma lo farà per uno script one-off. Grazie! –

1

Forse si potrebbe definire il proprio type o action nel add_argument chiamata che controlla se il file esiste, e restituisce un handle di file se lo fa e None (o qualcos'altro) altrimenti.

Ciò richiederebbe di scrivere del codice di te stesso come bene però, ma se il valore predefinito non può sempre essere usato probabilmente si deve fare un po 'il controllo, prima o poi. Come Manny D sostiene che potresti voler riconsiderare il tuo valore predefinito.

12

Si potrebbe sottoclasse argparse.FileType:

import argparse 
import warnings 

class ForgivingFileType(argparse.FileType): 
    def __call__(self, string): 
     try: 
      super(ForgivingFileType,self).__call__(string) 
     except IOError as err: 
      warnings.warn(err) 

parser = argparse.ArgumentParser(description='my illustrative example') 
parser.add_argument('--content', metavar='file', 
        default='content.txt', type=ForgivingFileType('r'), 
        help='file to process (defaults to content.txt)') 
args = parser.parse_args() 

Questo funziona senza dover toccare i metodi privati ​​come ArgumentParser._parse_known_args.

2

Usa stdin come predefinito:

parser.add_argument('file', default='-', nargs='?', type=argparse.FileType('r'))