You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Click所有命令/子命令统一执行操作并支持命令选择退出?

解决Click命令嵌套层级下的升级检查自动执行问题

要实现所有层级的Click命令(包括嵌套子命令)自动执行check_upgrade(),仅标记@bypass_upgrade_check的命令跳过,核心是递归定位最终被调用的具体命令,可以通过自定义click.Group类来实现。下面是完整的解决方案:

1. 定义跳过检查的装饰器

首先我们需要一个装饰器,给不需要检查的命令打上标记:

import click

def bypass_upgrade_check(f):
    # 给命令函数添加自定义属性,标记需要跳过升级检查
    f._bypass_upgrade = True
    return f

2. 自定义Group类处理递归查找

重写click.Group的invoke方法,递归遍历命令树,找到最终被用户调用的具体命令(而非中间的子命令组),然后判断是否需要执行升级检查:

class UpgradeCheckGroup(click.Group):
    def invoke(self, ctx):
        # 递归查找最终被调用的目标命令
        def find_target_command(current_ctx):
            invoked_subcmd = current_ctx.invoked_subcommand
            if invoked_subcmd:
                # 获取子命令对象
                sub_cmd = current_ctx.command.get_command(current_ctx, invoked_subcmd)
                if isinstance(sub_cmd, click.Group):
                    # 如果是子命令组,继续递归查找下一层
                    return find_target_command(current_ctx)
                else:
                    # 找到具体执行的命令
                    return sub_cmd
            else:
                # 没有子命令,当前命令就是目标
                return current_ctx.command

        # 获取最终目标命令
        target_command = find_target_command(ctx)
        # 检查是否需要跳过升级检查
        if not getattr(target_command, '_bypass_upgrade', False):
            check_upgrade()
        
        # 执行原始的命令逻辑
        return super().invoke(ctx)

# 示例升级检查函数,替换成你的实际逻辑
def check_upgrade():
    click.echo("🔍 Running upgrade check...")

3. 使用自定义Group构建命令树

在顶层命令组使用cls=UpgradeCheckGroup参数,之后所有嵌套的子命令组和命令都会自动应用升级检查逻辑:

@click.group(cls=UpgradeCheckGroup)
def cli():
    pass

# 顶层普通命令 - 会执行升级检查
@cli.command()
def sync():
    click.echo("✅ Syncing data...")

# 顶层跳过检查的命令
@cli.command()
@bypass_upgrade_check
def version():
    click.echo("📦 Version 1.0.0")

# 嵌套子命令组
@cli.group()
def config():
    pass

# 子组下的普通命令 - 会执行升级检查
@config.command()
def set():
    click.echo("⚙️ Setting configuration...")

# 子组下跳过检查的命令
@config.command()
@bypass_upgrade_check
def show():
    click.echo("📋 Showing configuration...")

# 更深层的嵌套子组
@config.group()
def advanced():
    pass

@advanced.command()
def reset():
    click.echo("🔄 Resetting advanced config...")

@advanced.command()
@bypass_upgrade_check
def export():
    click.echo("📤 Exporting advanced config...")

if __name__ == "__main__":
    cli()

关键逻辑说明

  • 递归查找命令:通过find_target_command函数,从当前上下文开始,逐层深入子命令组,直到找到最终执行的具体命令(非Group类型)。
  • 标记检查:利用自定义属性_bypass_upgrade判断是否跳过检查,这个属性通过装饰器添加到命令函数上。
  • 兼容性:自定义Group完全兼容Click的原有语法,嵌套多少层子命令都能正常工作。

额外场景处理

如果希望直接调用子命令组(比如cli config)时也跳过升级检查,只需给子组添加@bypass_upgrade_check装饰器:

@cli.group()
@bypass_upgrade_check
def config():
    click.echo("📂 Config subgroup")

这样执行cli config时就不会触发升级检查了。

内容的提问来源于stack exchange,提问作者agelter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:07:48