Creating a wrapper decorator for click.options()

106 views Asked by At

I am trying to create a wrapper decorator for the click decorator @click.options('--foo', required=True):

import click

def foo_option(func):
    orig_decorator = click.option('--foo', required=True)(func)
    def decorator(*args, **kwargs):
        orig_decorator(*args, **kwargs)
    return decorator

@click.command()
@foo_option
def bar1(foo: str) -> None:
    print(f"bar1: {foo}")

if __name__ == '__main__':
    bar1()

This does not work. When I run it like script.py --foo=1 I get error:

Usage: script.py [OPTIONS]
Try 'script.py --help' for help.

Error: No such option: --foo

Expected output should be:

bar1: 1

What am I missing? See Refactor @click.option() arguments for background information.

1

There are 1 answers

0
Anis Rafid On BEST ANSWER

The issue is with how you have structured the decorator. In this case, you are wrapping around the click.option which is unnecessary. When you create a decorator to wrap around another decorator (like click.option), you should consider that decorators work from bottom to top. here is the updated code:

import click


def foo_option(func):
    return click.option('--foo', required=True)(func)


@click.command()
@foo_option
def bar1(foo: str) -> None:
    print(f"bar1: {foo}")


if __name__ == '__main__':
    bar1()

When you run the script, you will get the expected output.