How do I create an exception to a group action in click

五迷三道 提交于 2019-12-11 08:39:48

问题


I have a case where I'd like to run a common function (check_upgrade()) for most of my click commands, but there are a few cases where I don't want to run it. Rather than relying on developers to remember to add a decorator or function call to explicitly run this check, I'd prefer to instead run it by default and then have a decorator that one can add (e.g. @bypass_upgrade_check) for commands where check_upgrade() should not run.

I was hoping for something like:

class State(object):
    def __init__(self):
        self.bypass_upgrade_check = False

pass_state = click.make_pass_decorator(State, ensure=True)

def bypass_upgrade_check(func):
    @pass_state
    def wrapper(state, *args, **kwargs):
        state.bypass_upgrade_check = True
        func(*args, **kwargs)
    return wrapper 

@click.group()
@pass_state
def common(state):
    if not state.bypass_upgrade_check:
        check_upgrade()

@common.command()
def cmd1():
    # check_upgrade() runs here
    pass

@bypass_upgrade_check
@common.command()
def cmd2():
    # don't run check_upgrade() here
    pass

But this doesn't work. It doesn't actually ever call the bypass_upgrade_check() function.

Is there a way to decorate a command in such a way that I can modify the state before the group code runs? Or another method altogether that accomplishes this?


回答1:


To keep track of which commands bypass the upgrade check, I suggest that in the bypass marking decorator you store that state on the click.Command object. Then if you pass the click.Context to your group, you can then look at the command object to see if it is marked to allow skipping upgrade like:

Code:

def bypass_upgrade_check(func):
    setattr(func, 'do_upgrade_check', False)

@click.group()
@click.pass_context
def cli(ctx):
    sub_cmd = ctx.command.commands[ctx.invoked_subcommand]
    if getattr(sub_cmd, 'do_upgrade_check', True):
        check_upgrade()

Test Code:

import click

def check_upgrade():
    click.echo('Checking Upgrade!')

def bypass_upgrade_check(func):
    setattr(func, 'do_upgrade_check', False)

@click.group()
@click.pass_context
def cli(ctx):
    sub_cmd = ctx.command.commands[ctx.invoked_subcommand]
    if getattr(sub_cmd, 'do_upgrade_check', True):
        check_upgrade()

@cli.command()
def cmd1():
    # check_upgrade() runs here
    click.echo('cmd1')

@bypass_upgrade_check
@cli.command()
def cmd2():
    # don't run check_upgrade() here
    click.echo('cmd2')


if __name__ == "__main__":
    commands = (
        'cmd1',
        'cmd2',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            cli(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

Results:

Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> cmd1
Checking Upgrade!
cmd1
-----------
> cmd2
cmd2


来源:https://stackoverflow.com/questions/50263363/how-do-i-create-an-exception-to-a-group-action-in-click

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!