Tests are boolean predicates used withisin conditionals.
Basic Test
from kida import Environment
env = Environment()
def is_positive(value):
return value > 0
env.add_test("positive", is_positive)
Template usage:
{% if count is positive %}
{{ count }} items
{% end %}
Decorator Syntax
@env.test()
def is_even(value):
return value % 2 == 0
@env.test("prime") # Custom name
def is_prime_number(n):
return n > 1 and all(n % i for i in range(2, int(n**0.5) + 1))
Template usage:
{% if number is even %}
{% if 17 is prime %}
Tests with Arguments
@env.test()
def divisible_by(value, divisor):
return value % divisor == 0
@env.test()
def between(value, min_val, max_val):
return min_val <= value <= max_val
Template usage:
{% if count is divisible_by(3) %}
{% if score is between(0, 100) %}
Negation
Useis notto negate tests:
{% if count is not even %}
{% if user is not defined %}
Built-in Tests
| Test | Description |
|---|---|
defined |
Value is not None |
undefined |
Value is None |
none |
Value is None |
even |
Integer is even |
odd |
Integer is odd |
number |
Value is int or float |
string |
Value is a string |
sequence |
Value is list/tuple/string |
mapping |
Value is a dict |
iterable |
Value supports iteration |
callable |
Value is callable |
Common Patterns
Type Tests
@env.test()
def is_list(value):
return isinstance(value, list)
@env.test()
def is_dict(value):
return isinstance(value, dict)
@env.test()
def is_empty(value):
if value is None:
return True
try:
return len(value) == 0
except TypeError:
return False
Value Tests
@env.test()
def is_blank(value):
"""Test if value is None, empty, or whitespace-only."""
if value is None:
return True
if isinstance(value, str):
return not value.strip()
try:
return len(value) == 0
except TypeError:
return False
@env.test()
def is_in_range(value, start, end):
return start <= value <= end
Object Tests
@env.test()
def is_admin(user):
return getattr(user, "role", None) == "admin"
@env.test()
def is_published(post):
return getattr(post, "status", None) == "published"
@env.test()
def has_children(page):
children = getattr(page, "children", None)
return bool(children)
String Tests
@env.test()
def is_email(value):
import re
pattern = r'^[\w.-]+@[\w.-]+\.\w+$'
return bool(re.match(pattern, str(value)))
@env.test()
def is_url(value):
return str(value).startswith(("http://", "https://"))
@env.test()
def contains(value, substring):
return substring in str(value)
Batch Registration
tests = {
"positive": lambda x: x > 0,
"negative": lambda x: x < 0,
"zero": lambda x: x == 0,
}
env.update_tests(tests)
Best Practices
Return Boolean
# ✅ Returns boolean
@env.test()
def is_valid(value):
return bool(validate(value))
# ❌ Returns non-boolean
@env.test()
def is_valid(value):
return validate(value) # Might return None
Handle None
@env.test()
def is_active(value):
if value is None:
return False
return getattr(value, "is_active", False)
Descriptive Names
# ✅ Clear purpose
@env.test()
def has_permission(user, permission):
return permission in getattr(user, "permissions", [])
# ❌ Vague
@env.test()
def check(value, x):
...
See Also
- Built-in Tests — All built-in tests
- Control Flow — Using tests in conditionals
- Custom Filters — Transform values