Tuesday, 21 May 2019

Commands with multiple common options going into one argument using custom decorator

I would like to make a module that makes it very simple to build click commands that share a lot of options. Those options are distilled into a single object that is passed into the command. As an illustrative example

from magic import magic_command
import click

@magic_command('Colored')
@click.option('--color')
def cmd(magic, color):
    pass

The total command would then have many --magic-... options that go into the magic object passed into cmd. I was able to achieve that using the following:

def magic_command(name):
    def decorator(func):
        @click.option('--magic-foo')
        @click.option('--magic-bar')
        def wrapper(magic_foo, magic_bar, **kwargs):
            print(f'initializing Magic with {magic_foo} and {magic_bar}')
            magic = Magic(magic_foo, magic_bar)
            func(magic, **kwargs)

        try:
            wrapper.__click_params__.extend(func.__click_params__)
        except AttributeError:
            pass

        return click.command(f'{name}-Magic')(wrapper)
    return decorator

However, messing with the __click_params__ doesn't seem particularly clean.

The question is somewhat similar to this one, however this approach does not allow me to condense the many magic options into a magic object.

To elaborate, with this approach I would have to do

@magic_command('Colored')
@click.option('--color')
def cmd(magic_foo, magic_bar, color):
    magic = Magic(magic_foo, magic_bar)
    pass

But that means the custom code needs to be aware what magic options there are and how to construct the magic. I guess that can be simplified using **kwargs but still - ideally I'd like to just have a ready magic object passed to cmd.



from Commands with multiple common options going into one argument using custom decorator

No comments:

Post a Comment