Copier
Copier is a versatile Python library and CLI tool designed for rendering project templates. It supports both local paths and Git URLs as template sources, allowing for dynamic replacement of values in various text files using Jinja2 templating. It handles project generation and updates, ensuring existing files are not overwritten unless explicitly instructed. The library is actively maintained with frequent updates, providing a robust solution for scaffolding and managing project lifecycles.
Warnings
- breaking Copier 9.x and newer requires Python 3.10 or higher. Older versions supported Python 3.6+.
- breaking The `_copier_conf.json()` method for accessing configuration data within templates has been removed.
- gotcha When updating a project, Copier handles merge conflicts by default using 'inline' markers, similar to Git merge conflicts. This can leave `<<<<<<<`, `=======`, `>>>>>>>` markers in your files.
- gotcha If your Copier template uses custom Jinja extensions or other Python packages for tasks, these dependencies must be installed in the same Python environment where Copier itself is installed. Copier does not automatically manage template-specific Python dependencies.
- gotcha When writing custom Python code for Copier templates (e.g., post-copy tasks, custom Jinja extensions), be mindful of mutable default arguments in function definitions. Changes to these mutable defaults (e.g., lists, dictionaries) will persist across multiple calls, leading to unexpected behavior.
Install
-
pip install copier
Imports
- run_copy
from copier import run_copy
Quickstart
import os
import shutil
from pathlib import Path
from copier import run_copy
# Define paths for demonstration
template_path = Path('./my_template')
dest_path = Path('./my_new_project')
# Clean up previous runs for idempotent quickstart
if dest_path.exists():
shutil.rmtree(dest_path)
if template_path.exists():
shutil.rmtree(template_path)
# 1. Create a dummy template structure
template_path.mkdir(exist_ok=True)
(template_path / 'copier.yml').write_text(
"""
# questions
project_name:
type: str
help: What is your project name?
author_name:
type: str
default: 'John Doe'
"""
)
(template_path / '{{ project_name }}').mkdir()
(template_path / '{{ project_name }}' / 'README.md.jinja').write_text(
"""
# {{ project_name }}
This project was generated by {{ author_name }}.
"""
)
print(f"Template created at: {template_path.resolve()}")
# 2. Programmatically copy the template
# In a real scenario, these answers might be interactively prompted or passed via CLI
answers = {
'project_name': 'MyAwesomeProject',
'author_name': 'AI Assistant'
}
run_copy(
str(template_path),
str(dest_path),
data=answers,
overwrite=True # Use with caution in real projects
)
print(f"Project generated at: {dest_path.resolve()}")
print("Generated README.md content:")
print((dest_path / 'MyAwesomeProject' / 'README.md').read_text())
# Clean up after quickstart
shutil.rmtree(template_path)
shutil.rmtree(dest_path)