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!)

Frequent Skaters

Tips

  • Use undefined=StrictUndefined when calling jinja2.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.