是否可以重复使用Python @click.option装饰器进行多个命令



我有两个Python CLI工具,它们共享一组常见的click.options。目前,共同的选项是重复的:

@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

是否可以将共同选项提取到可以应用于每个功能的单个装饰器中?

您可以构建自己的装饰器,该装饰符封装共同选项:

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

,如果要保留点击的选项deconator语法,则可以以这种方式实现装饰器:

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

这是一个装饰器,使用了以前的答案中相同的原理:

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

如果要在此功能中添加参数,则需要再次包装它:

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

对于单个可重复使用的选项,我只是将click.option返回的装饰器存储在变量中。对于多种常用选择,我喜欢使用简单的构图作为助手。

import functools
compose = lambda *funcs: functools.reduce(lambda f, g: lambda x: f(g(x)), funcs)
# reusable single option or argument
spam = click.option("--spam") 
# reusable group
foo_bar_baz = compose(
    click.option("--foo", is_flag=True),
    click.option("--bar", is_flag=True),
    click.option("--baz", is_flag=True),
)
@click.command()
@foo_bar_baz
@spam
def command1(foo, bar, baz, spam):
    pass
@click.command()
@foo_bar_baz
@spam
@click.option('--unique-flag', is_flag=True)
def command2(foo, bar, baz, spam, unique_flag):
    pass

相关内容

最新更新