Usando la misma opción varias veces en el argparse de Python

Estoy tratando de escribir un script que acepte múltiples fonts de entrada y haga algo para cada una. Algo como esto

./my_script.py \ -i input1_url input1_name input1_other_var \ -i input2_url input2_name input2_other_var \ -i input3_url input3_name # notice inputX_other_var is optional 

Pero no sé cómo hacer esto usando argparse . Parece que está configurado para que cada marca de opción solo se pueda usar una vez. Sé cómo asociar varios argumentos con una sola opción ( nargs='*' o nargs='+' ), pero eso todavía no me permite usar la -i varias veces. ¿Cómo hago para lograr esto?

Para que quede claro, lo que me gustaría al final es una lista de listas de cadenas. Asi que

 [["input1_url", "input1_name", "input1_other"], ["input2_url", "input2_name", "input2_other"], ["input3_url", "input3_name"]] 

Aquí hay un analizador que maneja un argumento repetido 2 opcional, con nombres definidos en el metavar :

 parser=argparse.ArgumentParser() parser.add_argument('-i','--input',action='append',nargs=2, metavar=('url','name'),help='help:') In [295]: parser.print_help() usage: ipython2.7 [-h] [-i url name] optional arguments: -h, --help show this help message and exit -i url name, --input url name help: In [296]: parser.parse_args('-i one two -i three four'.split()) Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']]) 

Esto no maneja el caso de 2 or 3 argument (aunque escribí un parche hace algún tiempo para un error / problema de Python que manejaría tal rango).

¿Qué tal una definición de argumento separada con nargs=3 y metavar=('url','name','other') ?

El metavar tupla también se puede usar con nargs='+' y nargs='*' ; las 2 cadenas se utilizan como [-u A [B ...]] o [-u [A [B ...]]] .

-i debe configurarse para aceptar 3 argumentos y para usar la acción de append .

 >>> p = argparse.ArgumentParser() >>> p.add_argument("-i", nargs=3, action='append') _AppendAction(...) >>> p.parse_args("-iabc -idef -ighi".split()) Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]) 

Para manejar un valor opcional, puede intentar usar un tipo personalizado simple. En este caso, el argumento de -i es una sola cadena delimitada por comas, con el número de divisiones limitadas a 2. Necesitará procesar posteriormente los valores para asegurarse de que haya al menos dos valores especificados.

 >>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append') >>> print p.parse_args("-ia,b,c -id,e -ig,h,i,j".split()) Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']]) 

Para mayor control, define una acción personalizada. Este amplía la _AppendAction (utilizada por action='append' ), pero solo verifica el número de argumentos dados a -i .

 class TwoOrThree(argparse._AppendAction): def __call__(self, parser, namespace, values, option_string=None): if not (2 <= len(values) <= 3): raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values))) super(TwoOrThree, self).__call__(parser, namespace, values, option_string) p.add_argument("-i", nargs='+', action=TwoOrThree) 

Esto es simple; solo agrega action='append' y nargs='*' (o '+' ).

 import argparse parser = argparse.ArgumentParser() parser.add_argument('-i', action='append', nargs='+') args = parser.parse_args() 

Entonces cuando lo ejecutas, obtienes

 In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i ...: nput2_name input2_other_var -i input3_url input3_name In [33]: args.i Out[33]: [['input1_url', 'input1_name', 'input1_other_var'], ['input2_url', 'input2_name', 'input2_other_var'], ['input3_url', 'input3_name']]