usage python3 parser metavar float example ejemplo argumentparser argument arg python argparse

python3 - Argumentos Python Argparse condicionalmente requeridos



parser python example (5)

He investigado lo más posible, pero no he encontrado la mejor manera de hacer que ciertos argumentos de cmdline sean necesarios solo bajo ciertas condiciones, en este caso solo si se han dado otros argumentos. Esto es lo que quiero hacer en un nivel muy básico:

p = argparse.ArgumentParser(description=''...'') p.add_argument(''--argument'', required=False) p.add_argument(''-a'', required=False) # only required if --argument is given p.add_argument(''-b'', required=False) # only required if --argument is given

Por lo que he visto, otras personas parecen agregar su propio cheque al final:

if args.argument and (args.a is None or args.b is None): # raise argparse error here

¿Hay alguna manera de hacer esto de forma nativa dentro del paquete argparse?


Hasta que se solucione http://bugs.python.org/issue11588 , solo usaría nargs :

p = argparse.ArgumentParser(description=''...'') p.add_argument(''--arguments'', required=False, nargs=2, metavar=(''A'', ''B''))

De esta manera, si alguien proporciona --arguments , tendrá 2 valores.

Quizás su resultado de CLI sea menos legible, pero el código es mucho más pequeño. Puedes arreglar eso con buenos documentos / ayuda.


He estado buscando una respuesta simple a este tipo de pregunta por algún tiempo. Todo lo que necesita hacer es verificar si ''--argument'' está en sys.argv , así que básicamente para el ejemplo de código que podría hacer:

import argparse import sys if __name__ == ''__main__'': p = argparse.ArgumentParser(description=''...'') p.add_argument(''--argument'', required=False) p.add_argument(''-a'', required=''--argument'' in sys.argv) #only required if --argument is given p.add_argument(''-b'', required=''--argument'' in sys.argv) #only required if --argument is given args = p.parse_args()

De esta manera, se required sea True o False dependiendo de si el usuario utiliza o no el --argument . Ya lo probé, parece funcionar y garantiza que -a y -b tienen un comportamiento independiente entre ellos.


Para los argumentos, he encontrado una solución rápida como esta. Supuestos: (1) ''--help'' debe mostrar ayuda y no quejarse del argumento requerido y (2) estamos analizando sys.argv

p = argparse.ArgumentParser(...) p.add_argument(''-required'', ..., required = ''--help'' not in sys.argv )

Esto se puede modificar fácilmente para que coincida con una configuración específica. Para los posicionales requeridos (que no serán necesarios si, por ejemplo, se proporciona ''--help'' en la línea de comando), he encontrado lo siguiente: [los posicionales no permiten una palabra clave required=... arg]

p.add_argument(''pattern'', ..., narg = ''+'' if ''--help'' not in sys.argv else ''*'' )

Básicamente, esto convierte el número de ocurrencias requeridas de ''patrón'' en la línea de comando de uno o más a cero o más en caso de que se especifique ''--help''.


Puede implementar una verificación proporcionando una acción personalizada para --argument , que tomará un argumento de palabra clave adicional para especificar qué otras acciones deben ser necesarias si se usa --argument .

import argparse class CondAction(argparse.Action): def __init__(self, option_strings, dest, nargs=None, **kwargs): x = kwargs.pop(''to_be_required'', []) super(CondAction, self).__init__(option_strings, dest, **kwargs) self.make_required = x def __call__(self, parser, namespace, values, option_string=None): for x in self.make_required: x.required = True try: return super(CondAction, self).__call__(parser, namespace, values, option_string) except NotImplementedError: pass p = argparse.ArgumentParser() x = p.add_argument("--a") p.add_argument("--argument", action=CondAction, to_be_required=[x])

La definición exacta de CondAction dependerá de lo que, exactamente, debe hacer --argument . Pero, por ejemplo, si --argument es un tipo de acción regular, toma un argumento y argparse._StoreAction , entonces simplemente heredar de argparse._StoreAction debería ser suficiente.

En el analizador de ejemplo, guardamos una referencia a la opción --a dentro de la opción --argument , y cuando se ve --argument en la línea de comando, establece el indicador required en --a en True . Una vez que se procesan todas las opciones, argparse verifica que se haya establecido cualquier opción marcada como requerida.


Su prueba de análisis posterior está bien, especialmente si la prueba de valores predeterminados con is None adecuada para sus necesidades.

http://bugs.python.org/issue11588 ''Add "necessarily inclusive" groups to argparse'' busca implementar este tipo de pruebas utilizando el mecanismo de groups (una generalización de mutuall_exclusive_groups).

He escrito un conjunto de UsageGroups de UsageGroups que implementan pruebas como xor (mutuamente excluyentes) and , or , y not . Pensé que eran exhaustivos, pero no he podido expresar su caso en términos de esas operaciones. (parece que necesito nand - no y, ver más abajo)

Esta secuencia de comandos utiliza una clase de Test personalizada, que esencialmente implementa su prueba de análisis posterior. seen_actions es una lista de acciones que el análisis ha visto.

class Test(argparse.UsageGroup): def _add_test(self): self.usage = ''(if --argument then -a and -b are required)'' def testfn(parser, seen_actions, *vargs, **kwargs): "custom error" actions = self._group_actions if actions[0] in seen_actions: if actions[1] not in seen_actions or actions[2] not in seen_actions: msg = ''%s - 2nd and 3rd required with 1st'' self.raise_error(parser, msg) return True self.testfn = testfn self.dest = ''Test'' p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter) g1 = p.add_usage_group(kind=Test) g1.add_argument(''--argument'') g1.add_argument(''-a'') g1.add_argument(''-b'') print(p.parse_args())

La salida de muestra es:

1646:~/mypy/argdev/usage_groups$ python3 issue25626109.py --arg=1 -a1 usage: issue25626109.py [-h] [--argument ARGUMENT] [-a A] [-b B] (if --argument then -a and -b are required) issue25626109.py: error: group Test: argument, a, b - 2nd and 3rd required with 1st

usage mensajes de usage y error todavía necesitan trabajo. Y no hace nada que la prueba posterior al análisis no pueda.

Su prueba genera un error si (argument & (!a or !b)) . A la inversa, lo que está permitido es !(argument & (!a or !b)) = !(argument & !(a and b)) . Al agregar una prueba de UsageGroup a mis clases de UsageGroup , puedo implementar su caso como:

p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter) g1 = p.add_usage_group(kind=''nand'', dest=''nand1'') arg = g1.add_argument(''--arg'', metavar=''C'') g11 = g1.add_usage_group(kind=''nand'', dest=''nand2'') g11.add_argument(''-a'') g11.add_argument(''-b'')

El uso es (usando !() Para marcar una prueba ''nand''):

usage: issue25626109.py [-h] !(--arg C & !(-a A & -b B))

Creo que esta es la forma más breve y clara de expresar este problema utilizando grupos de uso de propósito general.

En mis pruebas, las entradas que se analizan con éxito son:

'''' ''-a1'' ''-a1 -b2'' ''--arg=3 -a1 -b2''

Los que se supone que aumentan los errores son:

''--arg=3'' ''--arg=3 -a1'' ''--arg=3 -b2''