Modern template engine for Python 3.14t — AST-native, free-threading ready
Project description
)彡 Kida
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!
Why Kida?
- 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
Installation
pip install kida-templates
Requires Python 3.14+
Quick Start
| 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 |
Features
| 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
Usage
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 %}
Jinja2 Comparison
| 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 |
Architecture
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).
Performance
| 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 |
Documentation
| 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 |
Development
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 pytest
License
MIT License — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kida_templates-0.1.0.tar.gz.
File metadata
- Download URL: kida_templates-0.1.0.tar.gz
- Upload date:
- Size: 238.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4110ce5713e3e3c05fa79ffff4602045e1a602a28f5be664a37eb16b48a29717
|
|
| MD5 |
d6cc2ba9c789498a4cf9e7342f47fe87
|
|
| BLAKE2b-256 |
732f3c86133bce6128b2b8cad898f52cd527a5019d7e59c8329b53955886dadc
|
File details
Details for the file kida_templates-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kida_templates-0.1.0-py3-none-any.whl
- Upload date:
- Size: 170.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5aa81ac300c9dd0a609be0f85b0b61f8cf4be94e5d2c105500a5d50d252c9f9
|
|
| MD5 |
0ee65685e57e2c626715d6b0a9bc19ca
|
|
| BLAKE2b-256 |
d347a6d7b39d5fbcd4e02c8375d53340c350e4719f0ad1e69279d3431e833293
|