Python 工程化: 用 Copier 打造“自我进化“的项目脚手架

什么是 copier

Copier 是一个开源的项目模板生成工具

  • 基于 Jinja2 模板引擎
  • 模板支持本地路径 和 Git URL
  • 项目可以包含任意文件
  • 支持动态替换任何文本文件中的值
  • 双向同步: 如果模板发生变化, 可以将更新同步到已生成的项目中

安装

bash 复制代码
# 基本安装
uv tool install copier

# 安装插件
uv tool install copier --with copier-template-extensions

QuickStart

创建一个模板:

plaintext 复制代码
📁 my_copier_template                   # your template project
├── 📄 copier.yml                       # your template configuration
├── 📁 {{project_name}}                 # a folder with a templated name
│    └── 📄 {{module_name}}.py.jinja    # a file with a templated name
└─ {{_copier_conf.answers_file}}.jinja  # answers are recorded here

copier.yml 文件内容:

yaml 复制代码
project_name:
    type: str
    default: "{{ _folder_name  }}"
    help: What is your project name?

module_name:
    type: str
    help: What is your Python module name?

{``{module_name}}.py.jinja 文件内容:

python 复制代码
print("Hello from {{module_name}}!")

{``{_copier_conf.answers_file}}.jinja 文件内容:

复制代码
# Changes here will be overwritten by Copier
{{ _copier_answers|to_nice_yaml -}}

从模板生成项目:

bash 复制代码
copier copy path/to/template path/to/destionation

底层机制

Copier 运转依赖两个基石: Jinja2(模板渲染) + Git(差异对比与合并) . 最核心的秘密武器是它在目标项目下生成的 .copier-answers.yml 文件。这个文件相当于项目的 DNA 记录,它记住了:你用的是哪个版本的模板,以及你当时回答了什么问题(项目名、作者等)

操作逻辑:

  1. 定义 : 创建一个包含 copier.yml(定义要问用户的问题)和模板文件(包含 {``{ question_answer }} 变量)的 模板
  2. 生成 : 运行 copier copy <模板URL> <本地目录>。 Copier 提问 -> 渲染文件 -> 存下 .copier-answers.yml
  3. 更新 : 当你修改了模板, 在本地项目目录运行 copier update
    • 先重新生成一个 "旧版本模板对应的干净项目"
    • 用它和 "当前项目" 做 diff, 算出你后来做过哪些改动
    • 再把当前项目按新模板升级
    • 最后再把刚才那份 diff 补回来 (有冲突则抛出)

创建模板

模板是一个目录, 生成项目时:

  • 普通文件: 原样复制到目标位置
  • .jinja 结尾: 模板引擎将渲染它们
  • 如果一个带后缀的文件与另一个不带后缀的文件相邻, 不带后缀的文件将被忽略

模板辅助函数

除了 Jinja 支持的所有功能外, Copier 还支持 jinja2-ansible-filters 提供的所有函数和过滤器

复制代码
{{ project_name | b64encode }}

{{ project_name | md5 }}

{{ project_name | replace('a', 'A') }}

全局变量

如下变量在 Jinja 模板中始终可用:

  • _copier_answers: 问题答案字典
  • _folder_name: copy命令后跟的项目根目录的名称
  • ...

配置模板

如下为 copier.yml 中支持的配置

exclude: 排除文件

yaml 复制代码
_exclude:
    - copier.yml
    - extensions.py
    - .git
    - .git/**
    - __pycache__
    - __pycache__/**
    - .ruff_cache
    - .venv
    - uv.lock

tasks: 项目生成/更新后要执行的命令

yaml 复制代码
_tasks:
  - command: git init
    when: "{{ _copier_operation == 'copy' }}"
  - command: git add .
    when: "{{ _copier_operation == 'copy' }}"
  - command: git commit -m "Initial commit"
    when: "{{ _copier_operation == 'copy' }}"
  - command: uv venv .venv --python {{python_version}}
    when: "{{ _copier_operation == 'copy' }}"

复制项目

bash 复制代码
# 建议使用完整路径, 避免后续 `copier update` 找不到模板路径
copier copy path/to/project/template path/to/destination

# --data 参数, 通过命令行指定问题的答案

默认情况下, copier 会复制最新 Git tag 对应的版本, 按照 PEP440 进行排序

复制代码
0.9
0.9.1
0.9.2
...
0.9.10
0.9.11
1.0
1.0.1
1.1
2.0
2.0.1
...

可以使用 --vcs-ref 参数来指定要使用的分支、tag 或 引用

bash 复制代码
# 使用仓库中 main 分支
copier copy --vcs-ref main https://github.com/foo/copier-template.git ./path/to/destination

# 使用本地模板中最新版本(包含未提交的修改)
copier copy --vcs-ref HEAD path/to/project/template path/to/destination

更新项目

当如下条件满足时, 才可以更新项目:

  • 目标文件夹中包含一个有效的 .copier-answers.yml 文件
  • 模板使用 git 进行版本控制 (with tags)
  • 目标文件夹使用 git 进行版本控制

进入目标文件夹, 确保 git status 是干净的, 然后运行:

bash 复制代码
copirt update

# 从指定分支、tag 或 引用 更新项目
copirt update --vcs-ref xx

# 重用之前的所有回答
copier update --defaults

# 只更改某个问题
copier update --defaults --data updated_question="my new answer"

若更新遇到冲突, 可通过如下参数控制冲突处理方式:

  • --conflict rej: 为每个有冲突的文件创建一个单独的 .rej 文件
  • --conflict inline: (default) 在冲突的文件中创建冲突标记, 与 git merge 标记类似

为避免发生损坏, 建议在更新前提交一次版本:

bash 复制代码
git status
git add -A
git commit -m "before copier update"

copier update
相关推荐
李妍.9 分钟前
02Numpy基础(上)
开发语言·python
TheBestRucy11 分钟前
Python 九阳神功之贰:面向对象(下)
开发语言·python
2601_9659584636 分钟前
口腔黏膜脱皮超2周未愈建议及时就医
人工智能·python
AI_小站1 小时前
刚面完百度的 Agent 开发岗,我才发现:世界就是个巨大的草台班子
java·开发语言·人工智能·spring·百度·langchain
微小冷2 小时前
在不同空间中展示数据(欧式、球面、庞加莱圆盘)
python·双曲空间·微分几何·geomstats·庞加莱圆盘·球面
felixking2 小时前
C++20 协程
开发语言·c++·协程
weixin_431600442 小时前
Agent Workflow 学习向:Code 节点,比模板更强的变量加工
后端·python·学习·ai·
讲温控就好了2 小时前
从医疗影像到能源存储——芯片冷却温控技术的跨行业赋能
人工智能·python·能源
DeepVisionary3 小时前
从 Qwen3.8-27B 把原生多模态、原生 FP8、桌面级 Agent 三件事一次集齐,看开源大模型的“工业化拐点“
python·自动化
Zane1994123 小时前
CAS 与原子类:Java 如何实现无锁编程
java·开发语言