如何在Click中为组操作设置升级检查豁免装饰器
解决Click命令组默认执行升级检查、部分命令豁免的问题
你的代码失效的核心原因是Click的执行顺序问题:组的回调函数(common)会在命令的任何回调逻辑之前运行。你原来的bypass_upgrade_check装饰器是在命令执行时才修改state,但这时候common里的check_upgrade()已经跑完了,自然起不到跳过的作用。
下面给你两种可行的实现方案,都能实现「默认检查、标记豁免」的需求,不需要开发者手动添加检查逻辑:
方案一:给命令添加豁免标记(最简洁)
我们可以给需要跳过检查的命令函数添加一个自定义属性,然后在组的回调里直接判断当前命令是否带有这个标记:
import click def check_upgrade(): print("执行升级检查...") class State(object): def __init__(self): pass pass_state = click.make_pass_decorator(State, ensure=True) # 自定义装饰器:给命令函数打上豁免标记 def bypass_upgrade_check(func): func._skip_upgrade_check = True return func @click.group() @pass_state def common(state, ctx): # 获取当前正在执行的命令,检查其回调是否有豁免标记 if not getattr(ctx.command.callback, "_skip_upgrade_check", False): check_upgrade() @common.command() def cmd1(): print("运行命令cmd1") @bypass_upgrade_check @common.command() def cmd2(): print("运行命令cmd2(跳过升级检查)") if __name__ == "__main__": common()
原理说明
- 注册命令时,
@bypass_upgrade_check会给命令的回调函数添加一个_skip_upgrade_check属性。 - 组的回调
common执行时,通过ctx.command拿到当前执行的命令,直接检查其回调函数的标记,这样判断逻辑在检查之前执行,完全符合需求。
方案二:自定义命令类(适合复杂场景)
如果你的需求后续有扩展(比如需要在豁免时执行其他逻辑),可以通过自定义Click命令类,提前修改状态:
import click def check_upgrade(): print("执行升级检查...") class State(object): def __init__(self): self.bypass_upgrade_check = False pass_state = click.make_pass_decorator(State, ensure=True) # 自定义命令类:在命令执行前修改状态 class BypassUpgradeCommand(click.Command): def invoke(self, ctx): # 提前拿到State并设置豁免标记 state = ctx.ensure_object(State) state.bypass_upgrade_check = True # 执行原命令逻辑 return super().invoke(ctx) def bypass_upgrade_check(func): # 用自定义命令类包装目标函数 return click.command(cls=BypassUpgradeCommand)(func) @click.group() @pass_state def common(state): if not state.bypass_upgrade_check: check_upgrade() @common.command() def cmd1(): print("运行命令cmd1") # 用自定义装饰器创建命令,再添加到组中 @bypass_upgrade_check def cmd2(): print("运行命令cmd2(跳过升级检查)") common.add_command(cmd2) if __name__ == "__main__": common()
原理说明
- 自定义的
BypassUpgradeCommand重写了invoke方法,在执行命令核心逻辑前就修改了State的属性。 - 组的回调
common执行时,state.bypass_upgrade_check已经被设置为True,因此会跳过检查。
这两种方案都不需要开发者在每个命令里手动添加检查逻辑,只需要给豁免的命令加上@bypass_upgrade_check装饰器即可。
内容的提问来源于stack exchange,提问作者agelter
相关产品推荐
相关产品推荐

