Estoy buscando una forma Pythonic de validar argumentos cuando su validación depende lógicamente de los valores analizados de otros argumentos.
Aquí hay un ejemplo simple:
parser.add_argument( '--animal', choices=['raccoon', 'giraffe', 'snake'], default='raccoon', ) parser.add_argument( '--with-shoes', action='store_true', )En este caso, analizar este comando debería generar un error:
my_script.py --animal snake --with-shoesAgregar un grupo mutuamente excluyente no parece ayudar aquí, ya que los otros combos están bien:
my_script.py --animal raccoon --with-shoes my_script.py --animal raccoon my_script.py --animal snake my_script.py --animal giraffe --with-shoes my_script.py --animal giraffe Idealmente, el error de validación no debería estar vinculado al argumento --animal ni al argumento --with-shoes , ya que la interfaz no puede decirle qué valor debe cambiar aquí. Cada valor es válido, pero no se pueden usar en combinación.
Podemos hacer esto con el procesamiento posterior del espacio de nombres args , pero estoy buscando una solución que provoque que la llamada parser.parse_args() falle, es decir, en realidad fallamos durante el análisis de argumentos, no después.
Verificar los valores después del análisis es lo más simple. Incluso puede usar parser.error('...') para producir un mensaje de error en el formato argparse estándar.
argparse maneja cada argumento de forma independiente e intenta hacerlo de una manera que no se preocupa por el orden (excepto por los positionals ). Cada valor de entrada se agrega al espacio de nombres args mediante el objeto Action correspondiente (su método __call__ ). Una acción de store predeterminada simplemente usa setattr(args, dest, value) ; un store_true hace setattr(args, dest, True) .
Los grupos mutuamente excluyentes se manejan manteniendo un set de seen_actions y comparándolo con la propia lista de Acciones del grupo. He explorado generalizar los grupos para permitir otras combinaciones lógicas de acciones. A pesar de lo complicado que se ha vuelto (especialmente cuando se muestra el usage ), no imaginé probar los valores ni la ocurrencia.
Sería posible escribir clases de Action personalizadas, que verifiquen la co-ocurrencia, pero eso se vuelve más complicado.
Podríamos darle with-shoes una clase de acción que verifique los valores del atributo args.animal y genere un error si ese valor es snake . Pero, ¿qué pasa si el usuario proporciona primero la opción with-shoes ? Tendríamos que darle a animal una clase personalizada que verifique el valor de args.with_shoes y genere un error si es True , etc. Entonces, los shoes deben saber sobre animals y animals deben saber sobre los shoes . La prueba después del análisis le permite poner la lógica en un solo lugar.
Una de las grandes ventajas de usar un analizador como argparse es que genera los mensajes de uso, ayuda y error por usted. Pero la lógica de validación como esta es difícil de expresar automáticamente. Tal como está, el formato de uso para la lógica mutuamente excluyente relativamente simple es frágil y fácil de romper.
Un intento anterior de responder a este tipo de pregunta:
Dependencias de parámetros en Python: no puedo hacer que funcione