如何用click库基于前序参数限制命令参数可选值?
可以用Click实现动态依赖前序参数的补全
当然可以实现,Click支持通过自定义补全函数来实现这种依赖前序参数的动态补全,不需要依赖静态的click.Choice。下面是完整的代码示例:
实现步骤
1. 编写工具类扫描目录文件
先实现一个ToolsFinder类,负责动态扫描目标目录D,提取工具名称和对应的版本:
import os import re class ToolsFinder: FILE_PATTERN = re.compile(r"^(?P<name>[^_]+)_(?P<version>[^_]+)\.zip$") TARGET_DIR = "/path/to/your/directory/D" # 替换成实际目录路径 @classmethod def get_all_tools(cls): """扫描目录,返回{name: [versions]}的字典""" tools = {} if not os.path.exists(cls.TARGET_DIR): return tools for filename in os.listdir(cls.TARGET_DIR): match = cls.FILE_PATTERN.match(filename) if match: name = match.group("name") version = match.group("version") if name not in tools: tools[name] = [] tools[name].append(version) # 对版本排序,可选 for name in tools: tools[name].sort() return tools @classmethod def get_names(cls): """获取所有工具名称""" return list(cls.get_all_tools().keys()) @classmethod def get_versions(cls, name): """根据工具名称获取对应的版本列表""" return cls.get_all_tools().get(name, [])
2. 实现带动态补全的Click命令
利用Click的autocompletion参数为每个参数指定自定义补全函数,其中版本参数的补全函数会通过上下文(ctx)获取已经输入的工具名称:
import click def complete_tool_names(ctx, args, incomplete): """工具名称的补全函数""" all_names = ToolsFinder.get_names() return [name for name in all_names if name.startswith(incomplete)] def complete_versions(ctx, args, incomplete): """版本的补全函数,依赖已输入的工具名称""" # 从上下文获取已经输入的name参数值 tool_name = ctx.params.get("name") if not tool_name: return [] all_versions = ToolsFinder.get_versions(tool_name) return [version for version in all_versions if version.startswith(incomplete)] @click.command() @click.argument("name", autocompletion=complete_tool_names) @click.argument("version", autocompletion=complete_versions) def install(name, version): """安装指定名称和版本的工具""" click.echo(f"准备安装 {name} 的 {version} 版本") # 这里添加实际的安装逻辑 if __name__ == "__main__": install()
关键说明
- 每次触发补全时,
complete_tool_names和complete_versions都会重新调用ToolsFinder扫描目录,确保候选值是实时更新的,新增/删除文件后不需要修改代码。 - 版本补全函数通过
ctx.params.get("name")获取用户已经输入的工具名称,只有当用户输入了有效的名称后,才会返回对应的版本候选。 - 补全函数返回的列表会自动过滤掉和当前输入前缀不匹配的项(通过
startswith(incomplete)),符合Tab补全的常规逻辑。
测试验证
- 执行
mytool install <TAB>,会自动列出目录中所有工具名称(name1、name2、name3等)。 - 输入
mytool install name2 <TAB>,会列出name2对应的所有版本(version1、version2等)。 - 新增
name2_version3.zip和name4_version1.zip后,再次触发Tab补全,候选值会自动更新。
内容的提问来源于stack exchange,提问作者Kraal
相关产品推荐
相关产品推荐

