parser - Usar la misma opción varias veces en argparse de Python
python argparse argumentparser() (3)
Intento escribir un script que acepte varias fuentes 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 puedo entender cómo hacer esto usando argparse
. Parece que está configurado para que cada indicador de opción solo se pueda usar una vez. Sé cómo asociar múltiples argumentos con una sola opción ( nargs=''*''
o nargs=''+''
), pero eso no me deja usar la bandera -i
varias veces. ¿Cómo hago para lograr esto?
Para que quede claro, lo que al final me gustaría es una lista de cadenas de caracteres. 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 de 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 2 or 3 argument
(aunque escribí un parche hace algún tiempo para un error / problema de Python que manejaría dicho rango).
¿Qué tal una definición de argumento por separado con nargs=3
y metavar=(''url'',''name'',''other'')
?
El metavar
tupla también se puede usar con nargs=''+''
y nargs=''*''
; las 2 cuerdas se usan como [-u A [B ...]]
o [-u [A [B ...]]]
.
Esto es simple; simplemente agregue both action=''append''
y nargs=''*''
(o ''+''
).
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(''-i'', action=''append'', nargs=''+'')
args = parser.parse_args()
Luego, 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'']]
-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("-i a b c -i d e f -i g h i".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 para -i
es una cadena delimitada por comas, con el número de divisiones limitado a 2. Necesitaría postprocesar los valores para asegurarse de que hay al menos dos valores especificados.
>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action=''append'')
>>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split())
Namespace(i=[[''a'', ''b'', ''c''], [''d'', ''e''], [''g'', ''h'', ''i,j'']])
Para obtener más control, defina una acción personalizada. Este amplía la _AppendAction
(usada por action=''append''
), pero solo hace un cierto rango verificando la cantidad 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)