Pregunta sobre arguments, parameters, python, argparse – python, argparse: habilita el parámetro de entrada cuando se ha especificado otro

12

En mi script de Python, quiero poder usar un parámetro de entrada opcionalsolamente cuando se ha especificado otro parámetro opcional. Ejemplo:

$ python myScript.py --parameter1 value1
$ python myScript.py --parameter1 value1 --parameter2 value2

Pero no:

$ python myScript.py --parameter2 value2

¿Cómo hago esto con argparse?

¡Gracias!

Que quieres que pase simyScript.py --parameter2 value2 --parameter1 value1? Este es un caso muy difícil de tratar si quiere que pase. mgilson
bugs.python.org/issue11588 es una solicitud de error para unmutually_inclusive_group característica. Eso no funcionaría del todo en este caso, ya que--parameter1 puede ocurrir sin--parameter2. Contribuya a ese problema si tiene ideas de cómo se podrían implementar estas restricciones o las relacionadas. hpaulj

Tu respuesta

3   la respuesta
10

Usa una acción personalizada:

import argparse

foo_default=None    

class BarAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        didfoo=getattr(namespace,'foo',foo_default)
        if(didfoo == foo_default):
            parser.error( "foo before bar!")
        else:
            setattr(namespace,self.dest,values)

parser=argparse.ArgumentParser()
parser.add_argument('--foo',default=foo_default)
parser.add_argument('--bar',action=BarAction,help="Only use this if --foo is set")

#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())

Esto incluso puede hacerse de una manera un poco más fácil de mantener si está de acuerdo con confiar en algún comportamiento indocumentado de argparse:

import argparse

parser=argparse.ArgumentParser()
first_action=parser.add_argument('--foo',dest='cat',default=None)

class BarAction(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        didfoo=getattr(namespace,first_action.dest,first_action.default)
        if(didfoo == first_action.default):
            parser.error( "foo before bar!")
        else:
            setattr(namespace,self.dest,values)

parser.add_argument('--bar',action=BarAction,
                    help="Only use this if --foo is set")

#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())

En este ejemplo, obtenemos el valor predeterminado parafoo y es el destino del objeto de acción devuelto poradd_argument (El valor de retorno de add_argument no está documentado en ningún lugar que pueda encontrar). Esto sigue siendo un poco frágil (si desea especificar untype= palabra clave para el--foo argumento por ejemplo).

Finalmente, puedes comprobarsys.argv antes de analizar.

import sys
if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv):
    parser.error("parameter1 must be given if parameter2 is given")

Esto se vuelve un poco más complicado si--parameter1 También podría ser activado por--p1, Pero se entiende la idea. Entonces podrías usar

if (set(sys.argv).intersection(('--p2',...)) and 
    not set(sys.argv).intersection(('--p1',...)))

La ventaja aquí es que no requiere ningún orden en particular. (--p2 no necesita seguir--p1 en la línea de comandos). Y, como antes, puede obtener la lista de cadenas de comandos que activarán su acción particular a través deoption_strings atributo devuelto porparser.add_argument(...). p.ej.

import argparse
import sys   
parser=argparse.ArgumentParser()
action1=parser.add_argument('--foo')
action2=parser.add_argument('--bar',
                            help="Only use this if --foo is set")

argv=set(sys.argv)
if (( argv & set(action2.option_strings) ) and 
      not ( argv & set(action1.option_strings) )):
                #^ set intersection
     parser.error(' or '.join(action1.option_strings)+
                  ' must be given with '+
                  ' or '.join(action2.option_strings))
2

Puedes usarparse_known_args () para comprobar si--parameter1 fue dado antes de agregar--parameter2 al analizador.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--parameter1', dest='p1')
args = parser.parse_known_args()[0]
if args.p1:
  parser.add_argument('--parameter2', dest='p2')
args = parser.parse_args()

if args.p1:
  print args.p1
if args.p2:
  print args.p2

Resultados:

$ python myScript.py --parameter1 a
a
$ python myScript.py --parameter1 a --parameter2 b
a
b
$ python myScript.py --parameter2 b
usage: myScript.py [-h] [--parameter1 P1]
myScript.py: error: unrecognized arguments: --parameter2 b
--help Sin embargo, va a ser inexacto. pmav99
2

parser.parse_args() y levantar una excepción o de lo contrario fallará si--parameter2 se usa pero--parameter1 no es

También puede intentar establecer unacción personalizada (desplácese hacia abajo un poco) para--parameter2 comprobar si--parameter1 existe dentro del espacio de nombres.

Finalmente, podrías intentar usarsubparsers, aunque no sé si te permitirá especificar un valor para--parameter1.

Preguntas relacionadas