2011-11-23 6 views
12

Digamos que tengo un script que funciona en un archivo. Toma el nombre de este archivo en la línea de comando, pero si no se proporciona, se establece de manera predeterminada en un nombre de archivo conocido (content.txt, por ejemplo). Con pitón de argparse, utilizo el siguiente:Especificando nombres de archivo predeterminados con argparse, pero no abriéndolos en --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 

Esto funciona muy bien. El único problema es que si ejecuto python myscript --help, obtengo un ArgumentError si el archivo no está allí (lo cual creo que tiene sentido), y el texto de ayuda no se muestra. Prefiero que no intente abrir el archivo si el usuario simplemente quiere --help. ¿Hay alguna manera de hacer esto? Sé que podría convertir el argumento en una cadena y tener la precaución de abrir el archivo yo mismo más tarde (y he estado haciendo eso), pero sería conveniente tener argparse ocupérselo.

+0

Bueno, parece que vas a tener que tomar una decisión aquí. Puede hacer que el archivo predeterminado esté disponible (en virtud de que sea un "valor predeterminado") o simplemente abrir el archivo usted mismo, tal como se lo sugirió. Alternativamente, parece que puede usar stdin como predeterminado, sin embargo, no podrá especificar un nombre de archivo predeterminado, lo que podría no ser una mala opción si no desea llenar ese archivo. –

Respuesta

9

Si examina el código argparse, veo:

  • ArgumentParser.parse_args llamadas parse_known_args y se asegura de que no hay ningún argumento en espera de ser analizada.
  • ArgumentParser.parse_known_args valores conjuntos predeterminados y pide ArgumentParser._parse_known_args

Por lo tanto, la solución sería utilizar ArgumentParser._parse_known_args directamente para detectar -h y, después de eso, utilice ArgumentParser.parse_args como de costumbre.

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() 

Tenga en cuenta que ArgumentParser._parse_known_args necesita un par de parámetros: los argumentos de la línea de comandos y el espacio de nombres.

Por supuesto, no recomendaría este enfoque, ya que aprovecha la implementación interna argparse y que podría cambiar en el futuro. Sin embargo, no me parece demasiado desordenado, por lo que es posible que desee utilizarlo si cree que los riesgos de mantenimiento dan resultado.

+0

Parece que no hay realmente una buena solución para esto, pero esto servirá para una secuencia de comandos única. ¡Gracias! –

1

Tal vez podría definir su propio type o action en la llamada add_argument que comprueba si existe el archivo y devuelve un identificador de archivo y si lo hace None (o algo más) de lo contrario.

Esto también requeriría que escribieras algún código de ti mismo, pero si el valor predeterminado no siempre se puede utilizar, es probable que tengas que comprobarlo tarde o temprano. Al igual que Manny D, argumenta que es posible que desee reconsiderar su valor predeterminado.

12

Usted podría subclase 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() 

Esto funciona sin tener que tocar los métodos privados como ArgumentParser._parse_known_args.

2

Uso entrada estándar por defecto:

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