2011-03-02 13 views
7

Quiero usar argparse para crear una herramienta con subcomando. La sintaxis posible podría sersubmandato python argparse con dependencia y conflicto

/tool.py descarga --de 1234 --interval 60

descarga /tool.py --build 1432

/tool.py --numbers limpias 10

así que quiero utilizar para implementar argparse:

  1. garantizar '--de' y '--interval' son una iempre usan juntos
  2. asegurar '--build' no se usa nunca con otros argumentos

Pero no he encontrado una manera de emparejar '--de' y '--internal' a un grupo, a continuación, hacer que el grupo sea exclusivo en mutuo con '--build'.

A continuación se muestra mi código actual, y solo hace que '- from' y '--build' sean mutuamente exclusivos. Tampoco garantice que '- from' y '--interval' se unan, ni tampoco garantice que '--interval' y '--build' sean mutuamente exclusivos.

parser = argparse.ArgumentParser(description='A Tool') 
subparsers = parser.add_subparsers(help='sub-command help') 

#create the parser for the 'download' command 
download_parser = subparsers.add_parser('download', help='download help') 
download_parser.add_argument('--interval', dest='interval', type=int,help='interval help') 
group = download_parser.add_mutually_exclusive_group() 
group.add_argument('--from',type=int, help='from help') 
group.add_argument('--build', type=int, help='interval help') 

Por ejemplo,

descarga /tool.py --de 1234

No se debe permitir porque '--de' debe trabajar con '--interval'. Pero mi código lo acepta en silencio.

Y

/tool.py descarga --interval 1234 --build 5678

No se debe permitir porque '--build' no se puede utilizar con otro argumento. Pero mi código también lo acepta.

Cualquier sugerencia será muy apreciada. Gracias.

+0

tiene código allí, pero ¿qué no está funcionando? Dé un ejemplo del comportamiento incorrecto y explique cómo lo espera. –

+0

Agregué 2 ejemplos de comportamientos incorrectos. Gracias por tu sugerencia. – Landy

Respuesta

6

Se puede usar para este custom actions:

import argparse 
import sys 


class VerifyNoBuild(argparse.Action): 
    def __call__(self, parser, args, values, option_string=None): 
     # print 'No: {n} {v} {o}'.format(n=args, v=values, o=option_string) 
     if args.build is not None: 
      parser.error(
       '--build should not be used with --from or --interval') 
     setattr(args, self.dest, values) 


class VerifyOnlyBuild(argparse.Action): 
    def __call__(self, parser, args, values, option_string=None): 
     # print 'Only: {n} {v} {o}'.format(n=args, v=values, o=option_string) 
     if getattr(args, 'from') is not None: 
      parser.error('--from should not be used with --build') 
     if getattr(args, 'interval') is not None: 
      parser.error('--interval should not be used with --build') 
     setattr(args, self.dest, values) 

parser = argparse.ArgumentParser(description='A Tool') 
subparsers = parser.add_subparsers(help='sub-command help') 

# create the parser for the 'download' command 
download_parser = subparsers.add_parser('download', help='download help') 

download_parser.add_argument('--interval', 
          type=int, help='interval help', 
          action=VerifyNoBuild) 
download_parser.add_argument('--from', 
          type=int, action=VerifyNoBuild) 
download_parser.add_argument('--build', 
          type=int, action=VerifyOnlyBuild) 

args = parser.parse_args('download --from 1234 --interval 60'.split()) 
print(args) 
# Namespace(build=None, from=1234, interval=60) 

args = parser.parse_args('download --build 1432'.split()) 
print(args) 
# Namespace(build=1432, from=None, interval=None) 

args = parser.parse_args('download --build 1432 --from 1234'.split()) 
print(args) 
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD] 
# test.py download: error: --build should not be used with --from or --interval 

args = parser.parse_args('download --build 1432 --interval 60'.split()) 
print(args) 
# usage: test.py download [-h] [--interval INTERVAL] [--from FROM] [--build BUILD] 
# test.py download: error: --build should not be used with --from or --interval 

Pero, en realidad, creo que esto es más corto y más simple:

def parse_options(): 
    parser = argparse.ArgumentParser(description='A Tool') 
    subparsers = parser.add_subparsers(help='sub-command help') 

    #create the parser for the 'download' command 
    download_parser = subparsers.add_parser('download', help='download help') 
    download_parser.add_argument('--interval', type=int, help='interval help') 
    download_parser.add_argument('--from', type=int) 
    download_parser.add_argument('--build', type=int) 

    opt=parser.parse_args() 
    from_interval=[getattr(opt,key) is not None for key in ('from','interval')] 
    if opt.build is not None: 
     if any(from_interval): 
      sys.exit('error!') 
    elif not all(from_interval): 
     sys.exit('error!') 
    return opt 
+0

Gracias. Las acciones personalizadas son muy útiles. Modifiqué tu código para asegurar que --from y --interval siempre se usaran juntos. Funciona bien. ¡Gracias! :) – Landy

+0

@Landy: Ah sí, me olvidé de esa condición. ¿Logró verificar esa condición desde dentro de la clase 'VerifyNoBuild'? Si es así, ¿podría publicar su solución? Me gustaría ver cómo se hace eso. Modifiqué la solución alternativa para manejar esa condición. – unutbu

+0

Perdón por la respuesta tardía. En realidad, mi código es bastante simple.Como dijiste, modifiqué la clase ** VerifyNoBuild **, agregué las siguientes líneas antes de ** se llama setattr() **: 'if (args.begin es None) o (args.interval es None): sys.exit ('--from and - interval se deben usar juntos') ' – Landy

Cuestiones relacionadas