How to pass several list of arguments to @click.option How to pass several list of arguments to @click.option python python

How to pass several list of arguments to @click.option


If you don't insist on passing something that looks like a list, but simply want to pass multiple variadic arguments, you can use the multiple option.

From the click documentation

@click.command()@click.option('--message', '-m', multiple=True)def commit(message):    click.echo('\n'.join(message))
$ commit -m foo -m barfoobar


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:

Custom Class:

import clickimport astclass 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.

Custom Class Usage:

To use the custom class, pass the cls parameter to @click.option() decorator like:

@click.option('--option1', cls=PythonLiteralOption, default=[])

How does this work?

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.

Test Code:

@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 stuffif __name__ == '__main__':    import shlex    cli(shlex.split(        '''--option1 '["o11", "o12", "o13"]'         --option2 '["o21", "o22", "o23"]' '''))

Test Results:

Option 1, type: <type 'list'>  value: ['o11', 'o12', 'o13']Option 2, type: <type 'list'>  value: ['o21', 'o22', 'o23']


The following can be an easier hack fix:

#!/usr/bin/env pythonimport clickimport 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 stuffif __name__ == '__main__':    do_stuff()

This can help you to use 'option' as a list or a str.