At work, I’ve been using both Golang and Ruby to render Nomad jobspec files in a consistent manner across environments.
But Python is my one true love and I wanted to learn how to do it in Python. Turns out I already knew how… you can do it in Jinja2!
I’ve used Jinja2 in the past a lot for Django and Ansible, so this was pretty easy to pick up. Here are some notes for future me when I want to inevitably do this again.
It’s really easy to store stuff in a YAML file:
# ./skaters.yaml
---
- name: Kevin
age: 47
years_skating: 4
- name: Angela
age: 31
years_skating: 1
- name: Kris
age: 30
years_skating: 0
- name: Martha
age: 27
years_skating: 0
- name: James
age: 36
years_skating: 1
Here’s the template file:
<!-- templates/skaters_page.html.j2 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Frequent Skaters</title>
</head>
<body>
<h1>Frequent Skaters</h1>
<ul>
{% for skater in skaters %}
<li>
{% if skater.years_skating > 80 %}🛼{% else %}💥{% endif %}
<em>{{ skater.name }}:</em> {{ skater.years_skating }} years skating
</li>
{% endfor %} </ul>
</body>
</html>
It’s then really easy to render this out to stuff:
# ./render_skaters.py
from jinja2 import Environment, FileSystemLoader, StrictUndefined
import yaml
with open("skaters.yaml", "r") as file:
students = yaml.safe_load(file)
environment = Environment(loader=FileSystemLoader("templates/"), undefined=StrictUndefined)
template = environment.get_template("skater_page.html.j2")
results_filename = "freq_skaters.html"
context = {
"skaters": students,
}
with open(results_filename, mode="w", encoding="utf-8") as file:
file.write(template.render(context))
print(f"wrote: {results_filename}")
That gives us this beautiful file shown below. 👨🍳💋 (We really need a chef’s kiss emoji!)
Tips
- Use
undefined=StrictUndefined
when callingjinja2.Environment()
so undefined variables will cause an exception to be raised (instead of Jinja’s default behavior of ignoring undefined variables 😔) - You can sort keys in your YAML files recursively like so:
yq sort_keys(..) filename.yaml
- Real Python has a great primer on this topic.