Je souhaite appeler un script python via la ligne de commande avec ce type de paramètre (la liste peut avoir n'importe quelle taille, par exemple avec 3):
python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
en utilisant click. Dans la documentation, il n’est indiqué nulle part que nous pouvons utiliser une liste en tant que paramètre pour @ click.option
Et quand j'essaie de faire ça:
#!/usr/bin/env python
import click
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', default=[])
def do_stuff(option):
return
# do stuff
if __== '__main__':
do_stuff()
dans mon test.py
, en l'appelant à partir de la ligne de commande:
python test.py --option ["some option", "some option 2"]
Je reçois une erreur:
Erreur: Vous avez un argument supplémentaire inattendu (option 2])
Je ne peux pas vraiment utiliser d'arguments variadiques car un seul argument par commande est autorisé ( http://click.pocoo.org/5/arguments/#variadic-arguments )
Donc, si quelqu'un peut m'indiquer la bonne direction (en utilisant click de préférence), ce serait très apprécié.
Vous pouvez forcer le clic à prendre plusieurs arguments de liste si les listes sont formatées comme des chaînes littérales de listes python en utilisant une classe d'options personnalisée comme:
import click
import ast
class PythonLiteralOption(click.Option):
def type_cast_value(self, ctx, value):
try:
return ast.literal_eval(value)
except:
raise click.BadParameter(value)
Cette classe utilisera le module Abstract Syntax Tree de Python pour analyser le paramètre en tant que littéral python.
Pour utiliser la classe personnalisée, transmettez le paramètre cls
au décorateur @click.option()
, comme suit:
@click.option('--option1', cls=PythonLiteralOption, default=[])
Cela fonctionne car click est un framework OO bien conçu. Le décorateur @click.option()
instancie généralement un objet click.Option
mais permet de surcharger ce comportement avec le paramètre cls
. Il est donc relativement facile d'hériter de click.Option
dans notre propre classe et d'utiliser les méthodes souhaitées.
Dans ce cas, nous dépassons click.Option.type_cast_value()
, puis appelons ast.literal_eval()
pour analyser la liste.
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option1', cls=PythonLiteralOption, default=[])
@click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
click.echo("Option 1, type: {} value: {}".format(
type(option1), option1))
click.echo("Option 2, type: {} value: {}".format(
type(option2), option2))
# do stuff
if __== '__main__':
import shlex
cli(shlex.split(
'''--option1 '["o11", "o12", "o13"]'
--option2 '["o21", "o22", "o23"]' '''))
Option 1, type: <type 'list'> value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'> value: ['o21', 'o22', 'o23']
Ce qui suit peut être un correctif de piratage plus facile:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
except ValueError:
pass
# do stuff
if __== '__main__':
do_stuff()
Cela peut vous aider à utiliser 'option' en tant que list
ou str
.
Le "hack facile" de @ Murphy a presque fonctionné pour moi, mais le fait est que option
sera un string
à moins que vous n'indiquiez les options en une seule fois. J'ai donc dû le faire pour recomposer la liste:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
# option = str(option) # this also works
except ValueError:
pass
option = option[1:-1] # trim '[' and ']'
options = option.split(',')
for i, value in enumerate(options):
# catch integers
try:
int(value)
except ValueError:
options[i] = value
else:
options[i] = int(value)
# Here use options as you need
# do stuff
if __== '__main__':
do_stuff()
Vous pourriez attraper d'autres types
Pour l'utiliser, mettez la liste entre guillemets:
python test.py --option "[o11, o12, o13]"
Ou vous pouvez éviter les citations en ne laissant pas d’espace:
python test.py --option [o11,o12,o13]