You can build your own decorator that encapsulates the common options:
def common_options(function):
function = click.option('--unique-flag-1', is_flag=True)(function)
function = click.option('--bar', is_flag=True)(function)
function = click.option('--foo', is_flag=True)(function)
return function
@click.command()
@common_options
def command():
pass
Answer from Will Vousden on Stack OverflowYou can build your own decorator that encapsulates the common options:
def common_options(function):
function = click.option('--unique-flag-1', is_flag=True)(function)
function = click.option('--bar', is_flag=True)(function)
function = click.option('--foo', is_flag=True)(function)
return function
@click.command()
@common_options
def command():
pass
And if you want to preserve click's option decorator syntax, you can implement your decorator in this way:
import functools
def common_options(f):
@click.option('--foo', is_flag=True)
@click.option('--bar', is_flag=True)
@functools.wraps(f)
def wrapper_common_options(*args, **kwargs):
return f(*args, **kwargs)
return wrapper_common_options
@click.command()
@common_options
@click.option('--unique-flag-1', is_flag=True)
def command_one():
pass
Option instance reuse with custom `cls` impossible
Reusing options at different commands
python - How to pass several list of arguments to @click.option - Stack Overflow
python - Merge arguments and options of multiple Click commands under a single CLI command - Stack Overflow
I have found a simple solution! I slightly edited the snippet from https://github.com/pallets/click/issues/108 :
import click
_cmd1_options = [
click.option('--cmd1-opt')
]
_cmd2_options = [
click.option('--cmd2-opt')
]
def add_options(options):
def _add_options(func):
for option in reversed(options):
func = option(func)
return func
return _add_options
@click.group()
def group(**kwargs):
pass
@group.command()
@add_options(_cmd1_options)
def cmd1(**kwargs):
print(kwargs)
@group.command()
@add_options(_cmd2_options)
def cmd2(**kwargs):
print(kwargs)
@group.command()
@add_options(_cmd1_options)
@add_options(_cmd2_options)
@click.option("--cmd3-opt")
def cmd3(**kwargs):
print(kwargs)
if __name__ == '__main__':
group()
Define a class with common parameters
class StdCommand(click.core.Command):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.params.insert(0, click.core.Option(('--default-option',), help='Every command should have one'))
Then pass the class to decorator when defining the command function
@click.command(cls=StdCommand)
@click.option('--other')
def main(default_option, other):
...
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 bar
foo
bar
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 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.
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 stuff
if __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']