如何在 Cookiecutter 中动态生成配置选项

4次阅读

如何在 Cookiecutter 中动态生成配置选项

cookiecutter 的 `cookiecutter.json` 是静态文件,不支持直接执行函数。可通过预处理脚本在运行 cookiecutter 前动态注入系统可用程序列表,实现运行时选择项生成。

在数据科学项目模板中,常需根据宿主系统已安装的外部工具(如 python、R、CUDA 或特定 CLI 工具)提供版本选择。由于这些选项依赖运行环境且变化频繁,硬编码在 cookiecutter.json 中既不灵活也不可维护——而该文件本身又不支持表达式或函数调用(如 “program_version”: [“generate_program_choices()”] 会被原样当作字符串处理,不会执行)。

✅ 正确做法:使用预生成脚本(pre-gen script) 动态更新配置文件

步骤详解

  1. 编写 generate_program_choices.py(示例)
    该脚本负责探测系统并返回合法选项列表(如已安装的 Python 版本):
# generate_program_choices.py import subprocess import re  def get_python_versions():     try:         result = subprocess.run(["pyenv", "versions", "--bare"],                                capture_output=True, text=True, check=True)         versions = [v.strip() for v in result.stdout.splitlines() if v.strip()]         # 过滤出语义化版本(如 3.9.18, 3.11.9)         return sorted(set(v for v in versions if re.match(r"^d+.d+.d+$", v)))     except (subprocess.CalledProcessError, FileNotFoundError):         # 回退:尝试用 python --version + 系统查找         return ["3.9", "3.10", "3.11", "3.12"]  if __name__ == "__main__":     print("Available versions:", get_python_versions())     # 可选:直接输出供调试
  1. 编写 update_choices.py(预处理主脚本)
    在运行 cookiecutter 前执行,自动重写 cookiecutter.json:
# update_choices.py import json import sys from pathlib import Path  # 导入你的探测逻辑(确保在 PYTHONPATH 中或同目录) sys.path.insert(0, str(Path(__file__).parent)) from generate_program_choices import get_python_versions  # 读取并更新 cookiecutter.json config_path = Path("cookiecutter.json") with config_path.open(encoding="utf-8") as f:     config = json.load(f)  # 动态注入选项 —— 注意:必须是 list 类型,且元素为字符串 config["program_version"] = get_python_versions()  # 写回(保留格式与缩进) with config_path.open("w", encoding="utf-8") as f:     json.dump(config, f, indent=4, ensure_ascii=False)  print(f"✅ Updated 'program_version' with {len(config['program_version'])} options.")
  1. 执行流程(推荐封装为一键命令)
    python update_choices.py && cookiecutter .

⚠️ 关键注意事项

  • cookiecutter.json 中 “program_version” 字段值必须为字符串列表(如 [“3.11.9”, “3.12.3”]),不可为函数引用或空值;
  • 若模板被多人协作或 CI 使用,建议将 update_choices.py 加入 .gitignore 的生成产物(但脚本本身应纳入版本控制);
  • 如需更高阶控制(如条件跳过、交互式确认),可在脚本中加入 input() 或 argparse;
  • 避免在 pre_gen_project.py 中修改 cookiecutter.json:该钩子在 cookiecutter 解析 JSON 之后 才运行,无法影响变量选择界面。

通过此方案,你既保持了 Cookiecutter 的声明式体验,又获得了运行时环境感知能力——简洁、可靠,且完全符合数据科学模板“一次生成、长期稳定”的设计目标。

text=ZqhQzanResources