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

如何自省Click应用?DC应用命令信息提取方法问询

如何自省Click应用生成命令参考文档

我有一个基于click.Group构建的名为DC的Click应用cli(),包含大量子命令。我想生成一份文本文件,列出所有命令、参数、选项及帮助文本作为便捷参考,因此需要了解如何自省这个Click应用。

我查阅了Click的API参考文档但感到困惑。Command的部分方法(如get_usage())需要传入context对象作为首个参数,我只知道两种获取context的方式:

  • 在使用@pass_context装饰器的命令内部获取(并非总能实现)
  • 调用click.get_current_context()获取当前正在执行的底层命令对应的context

我尝试了以下代码:

from dc.__main__ import cli

current_ctx = click.get_current_context()
click.echo(cli.get_usage(current_ctx))

这段代码能打印出cli()函数的文档字符串,但执行click.echo(cli.commands)时得到的是空字典。后来我通过current_ctx.find_root().command.commands获取到了预期的所有顶层命令字典,想知道这是不是首选方法。


解答

关于获取顶层命令的方法

你用current_ctx.find_root().command.commands获取顶层命令的方法是可行的,但还有更直接的优化方向:

当你从模块导入cli(即click.Group实例)后,如果子命令是通过@cli.command()或cli.add_command()注册的,正常情况下cli.commands应该包含所有子命令。如果它是空字典,大概率是因为你的子命令采用了延迟加载(比如用了懒导入、动态注册逻辑),只有上下文初始化后子命令才会被加载,所以current_ctx.find_root().command.commands才能拿到完整列表。

更可靠的自省方案

如果要生成完整的命令参考,建议手动构建上下文,而非依赖click.get_current_context()(这个方法仅在命令执行过程中有效,直接运行脚本调用会报错)。可以手动实例化click.Context:

from dc.__main__ import cli
import click

# 手动创建根上下文
ctx = click.Context(cli)
# 触发参数解析,加载所有延迟注册的子命令
ctx.command.parse_args(ctx, [])

# 遍历所有顶层命令
for cmd_name, cmd in ctx.command.commands.items():
    print(f"命令: {cmd_name}")
    print(f"帮助文本: {cmd.help or '无说明'}")
    print(f"用法: {cmd.get_usage(ctx)}")
    
    # 打印选项
    print("选项:")
    for param in cmd.params:
        if isinstance(param, click.Option):
            print(f"  - {', '.join(param.opts)}: {param.help or '无说明'}")
    
    # 打印参数
    print("参数:")
    for param in cmd.params:
        if isinstance(param, click.Argument):
            print(f"  {param.name}: {param.help or '无说明'}")
    print("---")

递归遍历嵌套子命令

如果你的命令存在嵌套组(比如cli下有子组,子组下还有命令),可以用递归函数遍历所有层级:

def walk_commands(cmd, ctx, prefix=""):
    full_cmd = f"{prefix} {cmd.name}".strip()
    print(f"命令: {full_cmd}")
    print(f"帮助文本: {cmd.help or '无说明'}")
    print(f"用法: {cmd.get_usage(ctx)}")
    
    # 输出选项
    print("选项:")
    for param in cmd.params:
        if isinstance(param, click.Option):
            print(f"  - {', '.join(param.opts)}: {param.help or '无说明'}")
    
    # 输出参数
    print("参数:")
    for param in cmd.params:
        if isinstance(param, click.Argument):
            print(f"  {param.name}: {param.help or '无说明'}")
    print("---")
    
    # 如果是命令组,递归遍历子命令
    if isinstance(cmd, click.Group):
        for sub_cmd_name, sub_cmd in cmd.commands.items():
            walk_commands(sub_cmd, ctx, prefix=full_cmd)

# 初始化上下文并启动遍历
ctx = click.Context(cli)
ctx.command.parse_args(ctx, [])
walk_commands(cli, ctx)

这个方案无需依赖运行中的命令上下文,可直接在脚本中执行,能完整获取所有命令、参数、选项和帮助文本,适合生成静态参考文档。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:20:40