parseargs parse multiple metavar example python argparse

multiple - python argparse-opcional adjuntar argumento con opciones



python flags example (5)

En la documentación (http://docs.python.org/dev/library/argparse.html#default), se dice:

Para los argumentos posicionales con nargs igual a? o *, el valor predeterminado se usa cuando no hay ningún argumento de línea de comando presente.

Entonces, si lo hacemos:

acts = [''clear'',''copy'',''dump'',''lock''] p = argparse.ArgumentParser() p.add_argument(''action'', nargs=''*'', choices=acts, default=''clear'') print p.parse_args([])

Conseguimos lo que esperamos.

Namespace(action=''clear'')

El problema es cuando pones una lista por defecto. Pero lo he visto en el doc.

parser.add_argument(''bar'', nargs=''*'', default=[1, 2, 3], help=''BAR!'')

Por lo tanto, no sé :-(

De todos modos, aquí hay una solución que hace el trabajo que deseas:

import sys, argparse acts = [''clear'',''copy'',''dump'',''lock''] p = argparse.ArgumentParser() p.add_argument(''action'', nargs=''*'', choices=acts) args = [''dump'', ''clear''] # I set the default here ... if sys.argv[1:]: args = p.parse_args() print args

Tengo un script donde le pido al usuario una lista de acciones predefinidas para realizar. También quiero la posibilidad de asumir una lista particular de acciones cuando el usuario no define nada. Sin embargo, parece que tratar de hacer ambos juntos es imposible.

cuando el usuario no da argumentos, recibe un error de que la opción predeterminada no es válida

acts = [''clear'',''copy'',''dump'',''lock''] p = argparse.ArgumentParser() p.add_argument(''action'', nargs=''*'', action=''append'', choices=acts, default=[[''dump'', ''clear'']]) args = p.parse_args([]) >>> usage: [-h] [{clear,copy,dump,lock} [{clear,copy,dump,lock} ...]] : error: argument action: invalid choice: [[''dump'', ''clear'']] (choose from ''clear'', ''copy'', ''dump'', ''lock'')

y cuando definen un conjunto de acciones, el espacio de nombres resultante tiene las acciones del usuario anexadas al predeterminado, en lugar de reemplazar el predeterminado

acts = [''clear'',''copy'',''dump'',''lock''] p = argparse.ArgumentParser() p.add_argument(''action'', nargs=''*'', action=''append'', choices=acts, default=[[''dump'', ''clear'']]) args = p.parse_args([''lock'']) args >>> Namespace(action=[[''dump'', ''clear''], [''dump'']])


La acción se estaba agregando debido al parámetro "action = ''append''" que pasaste a argparse.

Después de eliminar este parámetro, los argumentos pasados ​​por un usuario se mostrarían por su cuenta, pero el programa generaría un error cuando no se pasaron los argumentos.

Agregar un prefijo ''-'' al primer parámetro resuelve esto de la manera más perezosa.

acts = [''clear'',''copy'',''dump'',''lock''] p = argparse.ArgumentParser() p.add_argument(''--action'', nargs=''*'', choices=acts, default=[[''dump'', ''clear'']]) args = p.parse_args()

La desventaja de este enfoque es que las opciones que pasa el usuario ahora deben ir precedidas por ''--action'', como:

app.py --action clear dump copy


Lo que necesita puede hacerse usando un argparse.Action personalizado como en el siguiente ejemplo:

import argparse parser = argparse.ArgumentParser() class DefaultListAction(argparse.Action): CHOICES = [''clear'',''copy'',''dump'',''lock''] def __call__(self, parser, namespace, values, option_string=None): if values: for value in values: if value not in self.CHOICES: message = ("invalid choice: {0!r} (choose from {1})" .format(value, '', ''.join([repr(action) for action in self.CHOICES]))) raise argparse.ArgumentError(self, message) setattr(namespace, self.dest, values) parser.add_argument(''actions'', nargs=''*'', action=DefaultListAction, default = [''dump'', ''clear''], metavar=''ACTION'') print parser.parse_args([]) print parser.parse_args([''lock''])

La salida del script es:

$ python test.py Namespace(actions=[''dump'', ''clear'']) Namespace(actions=[''lock''])


Puede probar si el usuario está suministrando acciones (en cuyo caso lo analiza como un argumento de posición requerido), o si no proporciona acciones (en cuyo caso lo analiza como un argumento opcional con valor predeterminado):

import argparse import sys acts = [''clear'', ''copy'', ''dump'', ''lock''] p = argparse.ArgumentParser() if sys.argv[1:]: p.add_argument(''action'', nargs = ''*'', choices = acts) else: p.add_argument(''--action'', default = [''dump'', ''clear'']) args = p.parse_args() print(args)

Cuando se ejecuta, produce estos resultados:

% test.py Namespace(action=[''dump'', ''clear'']) % test.py lock Namespace(action=[''lock'']) % test.py lock dump Namespace(action=[''lock'', ''dump''])

Probablemente tengas otras opciones para analizar también. En ese caso, podría usar parse_known_args para analizar las otras opciones, y luego manejar los argumentos unknown en una segunda pasada:

import argparse acts = [''clear'', ''copy'', ''dump'', ''lock''] p = argparse.ArgumentParser() p.add_argument(''--foo'') args, unknown = p.parse_known_args() if unknown: p.add_argument(''action'', nargs = ''*'', choices = acts) else: p.add_argument(''--action'', default = [''dump'', ''clear'']) p.parse_args(unknown, namespace = args) print(args)

Cuando se ejecuta, produce estos resultados:

% test.py Namespace(action=[''dump'', ''clear''], foo=None) % test.py --foo bar Namespace(action=[''dump'', ''clear''], foo=''bar'') % test.py lock dump Namespace(action=[''lock'', ''dump''], foo=None) % test.py lock dump --foo bar Namespace(action=[''lock'', ''dump''], foo=''bar'')


Terminé haciendo lo siguiente:

  • no append
  • agregue la lista vacía a las opciones posibles o de lo contrario los saltos de entrada vacíos
  • sin defecto
  • compruebe si hay una lista vacía después y establezca el valor predeterminado real en ese caso

Ejemplo:

parser = argparse.ArgumentParser() parser.add_argument( ''is'', type=int, choices=[[], 1, 2, 3], nargs=''*'', ) args = parser.parse_args([''1'', ''3'']) assert args.a == [1, 3] args = parser.parse_args([]) assert args.a == [] if args.a == []: args.a = [1, 2] args = parser.parse_args([''1'', ''4'']) # Error: ''4'' is not valid.