2011-01-22 12 views
17

Si tengo los argumentos '-a', '-b', '-c', '-d', con la función add_mutually_exclusive_group() mi programa tendrá que usar solo uno de ellos. ¿Hay alguna manera de combinar eso para que el programa solo acepte '-a 999 -b 999' o '-c 999 -d 999'?¿Admite argparse (python) grupos de argumentos mutuamente excluyentes?

Editar: la adición de un programa sencillo para mayor claridad:

>>> parser = argparse.ArgumentParser() 
>>> group = parser.add_mutually_exclusive_group() 
>>> group.add_argument('-a') 
>>> group.add_argument('-b') 
>>> group.add_argument('-c') 
>>> group.add_argument('-d') 

Sólo entonces ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d puede ser llamado. ¿Es posible tener grupos argparse en los grupos de exclusión, de modo que solo se llame a ./app.py -a .. -b .. | ./app.py -c .. -d ..?

Respuesta

6

EDIT: No importa. Porque argparse hace la elección horrible de tener que crear una opción al invocar group.add_argument. Esa no sería mi elección de diseño. Si estás desesperado por esta característica, puede intentar hacerlo con ConflictsOptionParser:

# exclusivegroups.py 
import conflictsparse 

parser = conflictsparse.ConflictsOptionParser() 
a_opt = parser.add_option('-a') 
b_opt = parser.add_option('-b') 
c_opt = parser.add_option('-c') 
d_opt = parser.add_option('-d') 

import itertools 
compatible_opts1 = (a_opt, b_opt) 
compatible_opts2 = (c_opt, d_opt) 
exclusives = itertools.product(compatible_opts1, compatible_opts2) 
for exclusive_grp in exclusives: 
    parser.register_conflict(exclusive_grp) 


opts, args = parser.parse_args() 
print "opts: ", opts 
print "args: ", args 

Así, cuando invocamos a ella, podemos ver que conseguimos el efecto deseado.

$ python exclusivegroups.py -a 1 -b 2 
opts: {'a': '1', 'c': None, 'b': '2', 'd': None} 
args: [] 
$ python exclusivegroups.py -c 3 -d 2 
opts: {'a': None, 'c': '3', 'b': None, 'd': '2'} 
args: [] 
$ python exclusivegroups.py -a 1 -b 2 -c 3 
Usage: exclusivegroups.py [options] 

exclusivegroups.py: error: -b, -c are incompatible options. 

El mensaje de aviso no le informa que tanto '-a' y '-b' son incompatibles con '-c', sin embargo, un mensaje de error más apropiada podría ser elaborado. Mayor, respuesta incorrecta a continuación. EDITAR

MAYORES:[Esta edición está mal, aunque no sería sólo un mundo perfecto si argparse trabajado de esta manera?] Mi respuesta anterior en realidad era incorrecta, usted debería ser capaz de hacer esto con argparse especificando un grupo por opciones mutuamente excluyentes. Incluso podemos usar itertools para generalizar el proceso. Y que sea por lo que no tiene que escribir todas las combinaciones explícitamente:

import itertools 
compatible_opts1 = ('-a', '-b') 
compatible_opts2 = ('-c', '-d') 
exclusives = itertools.product(compatible_opts1, compatible_opts2) 
for exclusive_grp in exclusives: 
    group = parser.add_mutually_exclusive_group() 
    group.add_argument(exclusive_grp[0]) 
    group.add_argument(exclusive_grp[1]) 
+1

http://bugs.python.org/issue10984 tiene un parche que le permite colocar un argumento en más de un grupo mutuamente exclusivo. Hacer eso es un cambio fácil. Producir un uso significativo con grupos superpuestos es más complicado. – hpaulj

5

Sólo encontré con este problema por mí mismo. De mi lectura de los documentos argparse, no parece haber una manera simple de lograr eso dentro de argparse. Consideré usar parse_known_args, pero eso pronto equivale a escribir una versión de propósito especial de argparse ;-)

Quizás un informe de error esté en orden. Mientras tanto, si estás dispuesto a hacer que tu usuario escriba un poco más, puedes simularlo con subgrupos (por ejemplo, cómo funcionan los argumentos de git y svn), p.

subparsers = parser.add_subparsers() 
    p_ab = subparsers.add_parser('ab') 
    p_ab.add_argument(...) 

    p_cd = subparsers.add_parser('cd') 
    p_cd.add_argument(...) 

No es ideal, pero al menos te da lo bueno de argparse sin demasiado feo hackeo. Terminé eliminando los conmutadores y simplemente usando las operaciones del subparser con subargumentos necesarios.

Cuestiones relacionadas