Python 项目生成器 Copier 详解
=======================================
Copier 是现代化的项目脚手架工具,基于 Jinja2 模板引擎,支持嵌套
模板、问答文件、任务系统等功能,比 Cookiecutter 更灵活强大。
一、安装与基本使用
------------------
# 安装 Copier
# pip install copier
# 验证安装
copier --version
# 从 Git 仓库模板创建项目
copier copy https://github.com/example/python-template.git myproject
# 从本地模板创建项目
copier copy ./my-template ./new-project
# 查看帮助
copier copy --help
# 使用已有答案文件跳过交互
copier copy -f ./my-template ./new-project -d project_name=MyApp
二、模板目录结构
----------------
# Copier 模板的标准目录结构
"""
my-template/
├── copier.yml # 模板配置与变量定义
├── {{project_name}}/ # 使用 {{变量名}} 语法
│ ├── src/
│ │ └── main.py.jinja # .jinja 后缀表示需要渲染
│ ├── tests/
│ │ └── test_app.py.jinja
│ ├── README.md.jinja
│ ├── pyproject.toml.jinja
│ └── .gitignore.jinja
├── tasks.py # 生成后任务
└── .copier-answers.yml # 自动生成的答案文件
"""
# 注意 Copier 使用 {{变量名}} 而不是 {{cookiecutter.变量名}}
# 不需要 cookiecutter. 前缀
三、copier.yml 配置
-------------------
# copier.yml 定义模板变量和配置
"""
# 变量定义和类型
project_name:
type: str
help: 项目名称
default: myproject
validator: >-
^[a-zA-Z][a-zA-Z0-9_-]+$
description:
type: str
help: 项目描述
default: 一个 Python 项目
author_name:
type: str
help: 作者姓名
default: 开发者
python_version:
type: float
help: Python 版本
choices:
- 3.9
- 3.10
- 3.11
default: 3.11
use_mypy:
type: bool
help: 是否使用 Mypy 类型检查?
default: yes
license:
type: str
help: 选择许可证
choices:
MIT: MIT 许可证
APACHE: Apache 2.0
GPL: GPL v3
default: MIT
# 排除的文件
_exclude:
- "*.pyc"
- "__pycache__"
# 模板后缀
_templates_suffix: ".jinja"
"""
四、Jinja2 模板渲染
-------------------
# 在模板文件中使用 Jinja2 语法
# pyproject.toml.jinja
"""
[project]
name = "{{ project_name }}"
version = "0.1.0"
description = "{{ description }}"
authors = [{name = "{{ author_name }}"}]
requires-python = ">= {{ python_version }}"
dependencies = [
"click>=8.1.0",
]
{% if use_mypy %}
[tool.mypy]
strict = true
{% endif %}
{% if license == "MIT" %}
[tool.poetry.license]
text = "MIT"
{% endif %}
"""
# src/main.py.jinja
"""
def main() -> None:
{{ greeting }}
print("{{ project_name }} 已启动!")
if __name__ == "__main__":
main()
"""
# README.md.jinja
"""
# {{ project_name }}
{{ description }}
## 安装
```bash
pip install {{ project_name }}
```
## 使用
```python
import {{ project_name }}
```
## 许可证
{{ license }}
"""
五、answers 文件
----------------
# .copier-answers.yml 记录用户的每次选择
"""
# 自动生成的文件,记录模板版本和用户选择
# 用于后续更新模板
_commit: v1.2.0
_src_path: gh:example/python-template
project_name: myproject
description: 一个 Web API 项目
author_name: 开发者
python_version: 3.11
use_mypy: true
license: MIT
"""
# 使用 answers 文件更新已有项目
copier update
# 基于 .copier-answers.yml 中的记录进行差异化更新
# 检查更新但不应用
copier update --pretend
# 强制使用 answers 文件
copier copy -f ./template ./project --trust
六、任务系统(tasks.py)
-----------------------
# tasks.py 定义生成后需要执行的任务
"""
import subprocess
from pathlib import Path
def setup_git(repo_path: Path, project_name: str) -> None:
# 初始化 Git 仓库
subprocess.run(["git", "init"], cwd=repo_path)
subprocess.run(["git", "add", "."], cwd=repo_path)
subprocess.run(
["git", "commit", "-m", f"初始化 {project_name}"],
cwd=repo_path,
)
def install_dependencies(repo_path: Path) -> None:
# 创建虚拟环境并安装依赖
subprocess.run(["python", "-m", "venv", ".venv"], cwd=repo_path)
pip_path = repo_path / ".venv" / "Scripts" / "pip"
subprocess.run([str(pip_path), "install", "-r", "requirements.txt"])
def print_success_message(repo_path: Path) -> None:
print(f"项目已创建: {repo_path}")
print("运行以下命令启动:")
print(" source .venv/bin/activate")
print(" python main.py")
"""
# 在 copier.yml 中注册任务
"""
_tasks:
- "python tasks.py setup_git {project_name}"
- "python tasks.py install_dependencies"
"""
七、版本迁移(Migration)
-------------------------
# Copier 的核心优势之一:模板更新迁移
# 更新模板后,更新已有项目
cd existing-project
copier update
# 查看差异但不应用
copier update --pretend
# 冲突处理
copier update --conflict rej
# 冲突时生成 .rej 文件,不会覆盖用户修改
# 强制覆盖
copier update --force
# 与 Cookiecutter 对比
"""
特性 Cookiecutter Copier
────── ──────────── ──────
变量语法 cookiecutter. 直接使用
模板更新 不支持 支持
任务系统 pre/post hooks tasks.py
答案记录 无 .copier-answers.yml
嵌套模板 有限 原生支持
冲突处理 无 .rej 文件
"""
# Copier 的模板更新能力是其最大优势,让项目可以持续
# 从模板改进中受益,而不必手动同步变更。
Python项目生成器copier
张小明
前端开发工程师
别再写for循环了!用Java 8 Stream优雅搞定List转Map/有序Map(附完整代码)
告别for循环:Java 8 Stream如何重塑集合操作范式当我们在处理集合数据时,传统for循环就像用螺丝刀组装家具——虽然最终能完成任务,但过程费时费力。Java 8引入的Stream API则像电动工具,让集合操作变得高效而优雅。本文将带你深入…
3D高斯泼溅SLAM加速技术与硬件优化实践
1. 3D高斯泼溅SLAM加速技术解析在计算机视觉和机器人领域,实时场景重建与定位技术(SLAM)一直是研究热点。3D高斯泼溅(3D Gaussian Splatting)作为新兴的辐射场渲染技术,通过动态高斯分布建模实现了前所未有…
华硕笔记本终极瘦身方案:告别臃肿,拥抱G-Helper轻量控制中心
华硕笔记本终极瘦身方案:告别臃肿,拥抱G-Helper轻量控制中心 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivo…
UE4材质进阶:别再直接调UV了!手把手教你用Append节点精准控制法线贴图强度
UE4材质进阶:别再直接调UV了!手把手教你用Append节点精准控制法线贴图强度在虚幻引擎4的材质编辑中,法线贴图的精细控制往往是区分新手与资深开发者的关键分水岭。许多人在调整表面质感时,会本能地想到直接修改UV参数——这种看似…
告别高功耗!手把手教你为NVMe SSD配置PCIe ASPM节能(附Linux/Windows实战代码)
深度优化NVMe SSD能耗:PCIe ASPM配置实战指南在数据中心与高性能计算环境中,NVMe固态硬盘已成为存储性能的标杆,但伴随而来的高功耗问题却常被忽视。一块全速运行的NVMe SSD在空闲时可能消耗10W以上的电力,当服务器集群规模扩大时…
UG二次开发避坑实录:用Python调用NXOpen,环境配置一次成功(Win10/NX2007实测)
UG二次开发避坑实录:Python调用NXOpen环境配置全攻略(Win10/NX2007实测)刚接触UG二次开发时,环境配置往往是第一个拦路虎。网上教程零散不全,照着操作却总遇到各种报错——路径不对、模块导入失败、脚本无法运行。本文…