Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to reuse python @click.option decorators for multiple commands?

I have two Python CLI tools which share a set of common click.options. At the moment, the common options are duplicated:

@click.command()
@click.option('--foo', is_flag=True)
@click.option('--bar', is_flag=True)
@click.option('--unique-flag-1', is_flag=True)
def command_one():
    pass

@click.command()
@click.option('--foo', is_flag=True)
@click.option('--bar', is_flag=True)
@click.option('--unique-flag-2', is_flag=True)
def command_two():
    pass

Is it possible to extract the common options in to a single decorator that can be applied to each function?

like image 791
Gareth John Avatar asked Apr 27 '18 11:04

Gareth John


4 Answers

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
like image 118
Will Vousden Avatar answered Nov 09 '22 04:11

Will Vousden


Here is a decorator that uses the same principle from the previous answer:

def group_options(*options):
    def wrapper(function):
        for option in reversed(options):
            function = option(function)
        return function
    return wrapper

opt_1 = click.option("--example1")
opt_2 = click.option("--example2")
opt_3 = click.option("--example3")

@cli.command()
@click.option("--example0")
@group_options(opt_1, opt_2, opt_3)
def command(example0, example1, example2, example3):
    pass
like image 30
vzhd1701 Avatar answered Nov 09 '22 06:11

vzhd1701


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
like image 6
hotenov Avatar answered Nov 09 '22 06:11

hotenov


If you want to add parameters to such a function, you need to wrap it once more:

def common_options(mydefault=True):
    def inner_func(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, default=mydefault)(function)
        return function
    return inner_func

@click.command()
@common_options(mydefault=False)
def command():
    pass
like image 1
dothebart Avatar answered Nov 09 '22 04:11

dothebart