# What are Jinja2 tests?

# In this video... (TL;DR)

TIP

List of all code changes made in this lecture: https://diff-store.com/diff/section09__08_jinja2_tests (opens new window)

Jinja2 tests allow us to evaluate conditionals using the is keyword.

For example:

{% set number = 10 %}

{% if number is even %}
  <p>It's even!</p>
{% endif %}

Tests can sometimes take arguments, in which case they can be called using brackets:

{% set number = 10 %}

{% if number is divisibleby(2) %}
  <p>It's even!</p>
{% endif %}

However, as of Jinja2 v2.9, brackets are not necessary. I still like to use them though, I find it easier to read. That means this is fine:

{% set number = 10 %}

{% if number is divisibleby 2 %}
  <p>It's even!</p>
{% endif %}

# Code at the start of this lecture

Available in the start folder. We've written a document in there to explain the starting code.

# Code written in this lecture

Let's start with our template. We're going to solve the Fizzbuzz problem using Jinja2.

What we want to do is iterate over the first 100 numbers, and then print one thing or another depending on the value.

If the value is divisible by 3 and 5, we print FizzBuzz. If it's only divisible by 3, we print Fizz. If it's only divisible by 5, we print Buzz.

If it's not divisible by any of them, we print the number out.

Let's start with our loop:

<ul>
  {% for n in range(1, 101) %}
  <li>
    {{ n }}
  </li>
  {% endfor %}
</ul>

Here I've written an unordered list (with bullet points, so it's easier to see what numbers our code is creating). Using the range() function, which is available to us in Jinja2, we can iterate over the numbers from 1 to 100, both inclusive.

Then I'm creating li elements for each number.

Within the li we can use the divisibleby test in an if statement to check whether n % 3 == 0 and n % 5 == 0.

Note that if we do this, we will be creating a bunch of empty bullet points for those numbers that aren't divisible, since we're no longer displaying the numbers themselves.

<ul>
  {% for n in range(1, 101) %}
  <li>
    {% if n is divisibleby(3) and n is divisibleby(5) %}
      FizzBuzz
    {% endif %}
  </li>
  {% endfor %}
</ul>

We can fix that using an else statement so that we always display the number if the tests don't pass:

<ul>
  {% for n in range(1, 101) %}
  <li>
    {% if n is divisibleby(3) and n is divisibleby(5) %}
      FizzBuzz
    {% else %}
      {{ n }}
    {% endif %}
  </li>
  {% endfor %}
</ul>

Finally, we can then use elif branches for the other tests:

<ul>
  {% for n in range(1, 101) %}
  <li>
    {% if n is divisibleby(3) and n is divisibleby(5) %}
      FizzBuzz
    {% elif n is divisibleby(3) %}
      Fizz
    {% elif n is divisibleby(5) %}
      Buzz
    {% else %}
      {{ n }}
    {% endif %}
  </li>
  {% endfor %}
</ul>

# Writing our own tests

We can also very easily write our own tests. Let me show you how!

A test is a function that takes at least 1 argument: the value before is.

So let's say we want to define our own square test, that checks whether a number is a square--i.e. has an integer root.

We can do it like this:

def square(value):
    return (value ** 0.5).is_integer()


app.jinja_env.tests["square"] = square

If we do this, all templates will have access to a test called square that they can use like this:

{% if 10 is square %}
  <p>It's a square!</p>
{% endif %}

Note that we call this without brackets because the value argument gets it value from the 10 that comes before is.

If we want to be able to pass other values, such as in divisibleby, we can do it like this: Here's a re-implementation of the divisibleby test:

def divisibleby(value, other):
    return value % other == 0


app.jinja_env.tests["divisibleby"] = divisibleby

You can create your own tests for checks you do frequently in your code, and for domain-specific checks to make your Jinja code more readable.

# Final code at the end of this lecture

Available in the end folder.