How to Create Angreal Templates
Learn how to create reusable project templates with Angreal’s Tera templating engine.
Prerequisites
Section titled “Prerequisites”- Angreal installed and working
- Basic understanding of file structures
- Familiarity with TOML format
Template Structure
Section titled “Template Structure”Every Angreal template follows this structure:
my-template/├── angreal.toml # Template configuration├── {{ variable_name }}/ # Templated directories├── static_file.txt # Static files (copied as-is)├── templated_file.md.tera # Templated files└── .angreal/ # Optional: template tasks ├── init.py # Post-initialization script └── task_*.py # Template-specific tasksBasic Template Configuration
Section titled “Basic Template Configuration”Create angreal.toml
Section titled “Create angreal.toml”The angreal.toml file defines variables that users will provide:
# Required template metadata[template]name = "my-awesome-template"description = "A template for awesome projects"version = "1.0.0"
# Template variables with defaultsproject_name = "my-project"author_name = "Anonymous"license = "MIT"use_docker = falseVariable Types
Section titled “Variable Types”Angreal supports several variable types:
# String variablesproject_name = "default-name"description = "Default description"
# Boolean variablesuse_docker = falseinclude_tests = true
# Numeric variablesport = 8080timeout = 30
# Choice variables (user selects from options)license = "MIT" # Could be MIT, Apache-2.0, GPL-3.0, etc.File and Directory Templating
Section titled “File and Directory Templating”Templated Directory Names
Section titled “Templated Directory Names”Use Tera syntax in directory names:
mkdir "{{ project_name }}"mkdir "{{ project_name }}/src"mkdir "{{ project_name }}/tests"When initialized with project_name = "my-app", creates:
my-app/my-app/src/my-app/tests/
Templated File Names
Section titled “Templated File Names”Files can also use template variables:
touch "{{ project_name }}.py"touch "test_{{ project_name }}.py"File Content Templating
Section titled “File Content Templating”Simple Variable Substitution
Section titled “Simple Variable Substitution”Create README.md:
# {{ project_name }}
{{ description }}
## Author
Created by {{ author_name }}
## License
This project is licensed under the {{ license }} license.Conditional Content
Section titled “Conditional Content”Use Tera’s conditional syntax:
{{ project_name }}
{{ description }}
{% if use_docker %}
## Docker
This project includes Docker support.
```bash
docker build -t {{ project_name }} .
docker run {{ project_name }}
```
{% endif %}
{% if include_tests %}
## Testing
Run tests with:
```bash
python -m pytest tests/
```
{% endif %}
Loops and Lists
Section titled “Loops and Lists”Define lists in angreal.toml:
dependencies = ["requests", "click", "pydantic"]Use in templates:
# requirements.txt{% for dep in dependencies %}{{ dep }}{% endfor %}Or for more complex structures:
# setup.pyinstall_requires = [{% for dep in dependencies %} "{{ dep }}",{% endfor %}]Filters
Section titled “Filters”Tera provides useful filters:
# {{ project_name | title }}
Package name: {{ project_name | lower | replace(from=" ", to="-") }}Class name: {{ project_name | title | replace(from=" ", to="") }}Common filters:
upper/lower- Change casetitle- Title casereplace(from="x", to="y")- Replace texttrim- Remove whitespacelength- Get length
File Extension Handling
Section titled “File Extension Handling”For files that contain Tera-like syntax that you don’t want to be processed, use the {% raw %} tag:
# Template file: package.json{% raw %}{ "name": "{{ project_name }}", "version": "1.0.0", "scripts": { {% if include_tests %} "test": "jest" {% endif %} }}{% endraw %}The {% raw %} tag tells Tera to treat everything between the tags as literal text, preventing any template processing within that block. This is particularly useful for:
- JSON files that might contain curly braces
- Template files you keep as part of a task
- Configuration files with Tera-like syntax
- Documentation files that need to show template examples
- Any file where you want to preserve the exact syntax
Template Tasks and Initialization
Section titled “Template Tasks and Initialization”Post-Initialization Script
Section titled “Post-Initialization Script”Create .angreal/init.py to run code after template processing:
"""Post-initialization script."""import osimport subprocess
def init(): """Run after template is rendered."""
# Get template variables context = angreal.get_context() project_name = context.get('project_name', 'project')
print(f"Initializing {project_name}...")
# Initialize git repository subprocess.run(['git', 'init'], cwd=project_name)
# Install dependencies if specified if context.get('install_dependencies', False): print("Installing dependencies...") subprocess.run(['pip', 'install', '-r', 'requirements.txt'], cwd=project_name)
print("Template initialization complete!") print(f"Next steps:") print(f" cd {project_name}") print(f" # Start developing!")Template-Specific Tasks
Section titled “Template-Specific Tasks”Add tasks that are useful for projects created from your template:
# .angreal/task_setup.pyimport angrealimport subprocess
@angreal.command(name="setup", about="Set up development environment")@angreal.argument(name="install_deps", long="install-deps", is_flag=True, help="Install Python dependencies")def setup_project(install_deps=False): """Set up the development environment."""
if install_deps: print("Installing dependencies...") subprocess.run(['pip', 'install', '-r', 'requirements.txt'])
print("Creating virtual environment...") subprocess.run(['python', '-m', 'venv', '.venv'])
print("Setup complete!")