I want to call a python script through the command line with this kind of parameter (list could be any size, eg with 3):
python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
using click. From the docs, it is not stated anywhere that we can use a list as parameter to @click.option
And when I try to do this:
#!/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 __name__ == '__main__':
do_stuff()
in my test.py
, by calling it from the command line:
python test.py --option ["some option", "some option 2"]
I get an error:
Error: Got unexpected extra argument (some option 2])
I can't really use variadic arguments as only 1 variadic arguments per command is allowed (http://click.pocoo.org/5/arguments/#variadic-arguments)
So if anyone can point me to the right direction (using click preferably) it would be very much appreciated.
You can coerce click into taking multiple list arguments, if the lists are formatted as a string literals of python lists by using a custom option class like:
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)
This class will use Python's Abstract Syntax Tree module to parse the parameter as a python literal.
To use the custom class, pass the cls
parameter to @click.option()
decorator like:
@click.option('--option1', cls=PythonLiteralOption, default=[])
This works because click is a well designed OO framework. The @click.option()
decorator usually instantiates a click.Option
object but allows this behavior to be over ridden with the cls
parameter. So it is a relatively easy matter to inherit from click.Option
in our own class and over ride the desired methods.
In this case we over ride click.Option.type_cast_value()
and then call ast.literal_eval()
to parse the list.
@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 __name__ == '__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']