Modern template engine for Python 3.14t
from kida import Environment
env = Environment()
template = env.from_string("Hello, {{ name }}!")
print(template.render(name="World"))
# Output: Hello, World!- AST-native — Compiles to Python AST directly, no string generation
- Free-threading ready — Safe for Python 3.14t concurrent execution (PEP 703)
- Fast — Benchmarks on 3.14t: 3.6x (minimal), 1.7x (small), 1.1x (medium), ~1.0x (large), 1.2x (complex); cold-start +7-8% with bytecode cache (details in performance docs)
- Modern syntax — Pattern matching, pipeline operator, unified
{% end %} - Zero dependencies — Pure Python, includes native
Markupimplementation
pip install kida-templatesRequires Python 3.14+
| Function | Description |
|---|---|
Environment() |
Create a template environment |
env.from_string(src) |
Compile template from string |
env.get_template(name) |
Load template from filesystem |
template.render(**ctx) |
Render with context variables |
| Feature | Description | Docs |
|---|---|---|
| Template Syntax | Variables, filters, control flow, pattern matching | Syntax → |
| Inheritance | Template extends, blocks, includes | Inheritance → |
| Filters & Tests | 40+ built-in filters, custom filter registration | Filters → |
| Async Support | Native async for, await in templates |
Async → |
| Caching | Fragment caching with TTL support | Caching → |
| Extensibility | Custom filters, tests, globals, loaders | Extending → |
📚 Full documentation: lbliii.github.io/kida
File-based Templates — Load from filesystem
from kida import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader("templates/"))
template = env.get_template("page.html")
print(template.render(title="Hello", content="World"))Template Inheritance — Extend base templates
base.html:
<!DOCTYPE html>
<html>
<body>
{% block content %}{% end %}
</body>
</html>
page.html:
{% extends "base.html" %}
{% block content %}
<h1>{{ title }}</h1>
<p>{{ content }}</p>
{% end %}
Control Flow — Conditionals, loops, pattern matching
{% if user.is_active %}
<p>Welcome, {{ user.name }}!</p>
{% end %}
{% for item in items %}
<li>{{ item.name }}</li>
{% end %}
{% match status %}
{% case "active" %}
Active user
{% case "pending" %}
Pending verification
{% case _ %}
Unknown status
{% end %}
Filters & Pipelines — Transform values
{# Traditional syntax #}
{{ title | escape | capitalize | truncate(50) }}
{# Pipeline operator #}
{{ title |> escape |> capitalize |> truncate(50) }}
{# Custom filters #}
{{ items | sort(attribute="name") | first }}
Async Templates — Await in templates
{% async for item in fetch_items() %}
{{ item }}
{% end %}
{{ await get_user() }}Fragment Caching — Cache expensive blocks
{% cache "navigation" %}
{% for item in nav_items %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% end %}
{% end %}
| Feature | Kida | Jinja2 |
|---|---|---|
| Compilation | AST → AST | String generation |
| Rendering | StringBuilder | Generator yields |
| Block endings | Unified {% end %} |
{% endif %}, {% endfor %} |
| Scoping | Explicit let/set/export |
Implicit |
| Async | Native async for, await |
auto_await() wrapper |
| Pattern matching | {% match %}...{% case %} |
N/A |
| Null coalescing | {{ a ?? b }} |
{{ a | default(b) }} |
| Optional chaining | {{ obj?.attr }} |
N/A |
| Pipeline syntax | {{ value |> filter }} |
{{ value | filter }} |
| Caching | {% cache key %}...{% end %} |
N/A (extension required) |
| Free-threading | Native (PEP 703) | N/A |
Compilation Pipeline — AST-native
Template Source → Lexer → Parser → Kida AST → Compiler → Python AST → exec()
Unlike Jinja2 which generates Python source strings, Kida generates ast.Module objects directly. This enables:
- Structured code manipulation — Transform and optimize AST nodes
- Compile-time optimization — Dead code elimination, constant folding
- Precise error source mapping — Exact line/column in template source
StringBuilder Rendering — O(n) output
# Kida's approach (O(n))
_out.append(...)
return "".join(_out)
# vs Jinja2's approach (higher overhead)
yield ...25-40% faster than Jinja2's generator yield pattern for typical templates.
Thread Safety — Free-threading ready
All public APIs are thread-safe by design:
- Template compilation — Idempotent (same input → same output)
- Rendering — Uses only local state (StringBuilder pattern)
- Environment — Copy-on-write for filters/tests/globals
- LRU caches — Atomic operations
Module declares itself GIL-independent via _Py_mod_gil = 0 (PEP 703).
| Metric | Kida | Jinja2 | Improvement |
|---|---|---|---|
| Simple render | 0.12ms | 0.18ms | 33% faster |
| Complex template | 2.1ms | 3.2ms | 34% faster |
| Concurrent (8 threads) | 0.15ms avg | GIL contention | Free-threading |
| Section | Description |
|---|---|
| Get Started | Installation and quickstart |
| Syntax | Template language reference |
| Usage | Loading, rendering, escaping |
| Extending | Custom filters, tests, loaders |
| Reference | Complete API documentation |
| Tutorials | Jinja2 migration, Flask integration |
git clone https://github.com/lbliii/kida.git
cd kida
# Uses Python 3.14t by default (.python-version)
uv sync --group dev --python 3.14t
PYTHON_GIL=0 uv run --python 3.14t pytestMIT License — see LICENSE for details.