'Python Click: Multiple Key Value Pair Arguments
I'm using the Python Click library for my command-line interface. I'd like to have a command that takes multiple key value pairs. I'm flexible on the api. For example
my_cli my_command FOO=1 BAR=2
or maybe
my_cli my_command FOO 1 BAR 2
or even
my_cli my_command {"FOO": 1, "BAR": 2}
Is there an easy way to do this with Click?
Solution 1:[1]
The simplest solution is basically the same thing you'd do with a regular Python function where you wanted an API like this.
Take a single parameter that groups the variable-length stream of arguments into a tuple. Then, what you do depends on whether you want separate arguments:
>>> def func(*args):
... d = dict(zip(args[::2], args[1::2]))
... print(d)
>>> func('FOO', 1, 'BAR', 2)
{'FOO': 1, 'BAR': 2}
… or combined key:value
arguments:
>>> def func(*args):
... d = dict(arg.split(':') for arg in args)
... print(d)
This one is a bit hacky to use, because in Python, arguments aren't just space-separated words, but bear with me on that:
>>> func('FOO:1', 'BAR:2')
{'FOO': 1, 'BAR': 2}
The click
equivalent for the first looks like this:
@click.command()
@click.argument('args', nargs=-1)
def my_command(args):
d = dict(zip(args[::2], args[1::2]))
click.echo(d)
(Obviously you can stick that in a click.group
, etc., just like any other command.)
And now:
$ ./clicky.py FOO 1 BAR 2
{'FOO': 1, 'BAR': 2}
And the second looks like this:
@click.command()
@click.argument('args', nargs=-1)
def my_command(args):
d = dict(arg.split(':') for arg in args)
click.echo(d)
And notice that now, using it is not hacky at all, because to your shell, arguments are just words separated by spaces:
$ ./clicky.py FOO:1 BAR:2
{'FOO': 1, 'BAR': 2}
What if you want to handle both KEY=VALUE
and KEY:VALUE
? Then you just have to write something slightly more complicated than arg.split(':')
. And you'll probably want some better error handling too. But that should be enough to get you started.
Solution 2:[2]
The same is possible with options instead of arguments, see Tuples as Multi Value Options in combination with Multiple Options.
import click
@click.command()
@click.option("--dict", "-d", "mydict", type=(str, int), multiple=True)
def cli(mydict):
d = dict(mydict)
click.echo(d)
if __name__ == "__main__":
cli()
Example:
$ python3 ./clickexample.py -d hello 1 -d foo 2 -d baz 3
{'hello': 1, 'foo': 2, 'baz': 3}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | reox |