Skip to main content

Python template engine for HTML, terminal, and streaming — with framework integration

Project description

)彡 Kida

PyPI version Build Status Python 3.14+ License: MIT

A Python template engine for HTML, terminal, and streaming — with framework integration

from kida import Environment

env = Environment()
template = env.from_string("Hello, {{ name }}!")
print(template.render(name="World"))
# Output: Hello, World!

What is Kida?

Kida is a modern template engine for Python 3.14t. It works for static site generation (Bengal), dynamic web apps (Chirp), and anywhere you need templates — same syntax, same engine. It compiles templates to Python AST directly (no string generation), supports streaming and block rendering, and is built for free-threading.

Why people pick it:

  • AST-native — Compiles to Python AST directly. Structured code manipulation, compile-time optimization, precise error source mapping.
  • Free-threading ready — Safe for Python 3.14t concurrent execution (PEP 703). All public APIs are thread-safe.
  • Dual-mode renderingrender() uses StringBuilder for maximum throughput. render_stream() yields chunks for streaming HTTP and SSE.
  • Modern syntax — Pattern matching, pipeline operator, unified {% end %}, null coalescing, optional chaining.
  • Explicit block closers — Prefer {% endif %}, {% endcall %}, {% endfor %}, {% endblock %}, {% enddef %} over bare {% end %} when nesting depth is 3+ (both styles are valid; explicit tags match Jinja2 muscle memory and ease code review).
  • Zero dependencies — Pure Python, includes native Markup implementation.

Use Kida For

  • HTML template rendering — Pages, partials, emails, and reusable components
  • Terminal/CLI outputautoescape="terminal" with ANSI colors, tables, trees, panels, and live rendering
  • Jinja2-style migration paths — Familiar syntax with new features and different internals
  • Streaming interfaces — Chunked HTML, SSE, and progressive rendering
  • Framework integration — Drop-in adapters for Flask, Starlette/FastAPI, and Django
  • Python 3.14+ template stacks — Async rendering and free-threading-friendly execution

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) Full page (StringBuilder, fastest)
template.render_block(name, **ctx) Single block (fragments, HTMX)
template.render_stream(**ctx) Generator (chunked HTTP, SSE)
template.render_async(**ctx) Async buffered output
template.render_stream_async(**ctx) Async streaming (for {% async for %})
template.render_with_blocks(overrides, **ctx) Compose layout with pre-rendered blocks
template.list_blocks() Block names for validation
template.template_metadata() Full analysis (blocks, regions, dependencies)
validate_block_exists(env, template, block) Check block exists before render_block
RenderedTemplate(template, ctx) Lazy iterable wrapper for streaming

Features

Feature Description Docs
Jinja2 Migration Learn where syntax matches, what changes, and how to switch safely Migrate from Jinja2 →
Framework Integration Block rendering, metadata, and adapters for web frameworks Framework Integration →
Template Syntax Variables, filters, control flow, pattern matching Syntax →
Inheritance Template extends, blocks, includes Inheritance →
Filters & Tests 50+ built-in filters, custom filter registration Filters →
Streaming Statement-level generator rendering via render_stream() Streaming →
Async Support Native async for, await in templates Async →
Caching Fragment caching with TTL support Caching →
Components & Slots {% def %}, {% call %}, {% slot %}, {% yield %} Functions →
Regions {% region name(params) %}...{% end %} — parameterized blocks for render_block Functions →
Block Rendering render_block(), render_with_blocks() for fragments and layout composition Framework Integration →
Introspection template_metadata(), block_metadata(), validate_context() for frameworks Analysis →
Partial Evaluation Compile-time evaluation via static_context Advanced →
Block Recompilation Recompile only changed blocks in live templates Advanced →
Terminal Rendering autoescape="terminal" with 30+ filters, components, live rendering Terminal →
Framework Adapters Drop-in Flask, Starlette/FastAPI, and Django integration Contrib →
Sandbox SandboxedEnvironment for untrusted templates with security policies Security →
Coverage Template line coverage with LCOV/Cobertura export Coverage →
Extensibility Custom filters, tests, globals, loaders, extension plugins Extending →
T-Strings (PEP 750) k() auto-escaping, r() composable regex (Python 3.14+) T-Strings →
HTMX Helpers hx_request(), hx_target(), csrf_token() for partials Custom Globals →
Worker Auto-Tuning get_optimal_workers(), should_parallelize() for parallel render Workers →

📚 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 %}

You may close blocks with explicit end keywords instead of {% end %} — for example {% endif %}, {% endfor %}, {% endblock %}, {% endcall %}, {% enddef %}. Deeply nested templates (roughly three or more levels) are easier to read and review with explicit closers.

{% if user.is_admin %}
  <span class="badge">Admin</span>
{% endif %}

Run kida check <template_dir> to parse every *.html file under a directory (CI-friendly syntax and import resolution checks).

Components & Named Slots — Reusable UI composition
{% def card(title) %}
<article class="card">
  <h2>{{ title }}</h2>
  <div class="actions">{% slot header_actions %}</div>
  <div class="body">{% slot %}</div>
</article>
{% end %}

{% call card("Settings") %}
  {% slot header_actions %}<button>Save</button>{% end %}
  <p>Body content.</p>
{% end %}

{% slot %} is the default slot. Named slot blocks inside {% call %} map to matching placeholders in {% def %}.

Regions — Parameterized blocks for render_block
{% region sidebar(current_path="/") %}
  <nav>{{ current_path }}</nav>
{% end %}

{{ sidebar(current_path="/about") }}

Regions are both blocks (for render_block()) and callables (for {{ name(args) }}). They can read outer-context variables. Use for HTMX OOB, layout composition, and framework integration. See Functions → Regions.

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 }}
Streaming Rendering — Yield chunks as they're ready
from kida import Environment

env = Environment()
template = env.from_string("""
<ul>
{% for item in items %}
    <li>{{ item }}</li>
{% end %}
</ul>
""")

# Generator: yields each statement as a string chunk
for chunk in template.render_stream(items=["a", "b", "c"]):
    print(chunk, end="")

# RenderedTemplate: lazy iterable wrapper
from kida import RenderedTemplate
rendered = RenderedTemplate(template, {"items": ["a", "b", "c"]})
for chunk in rendered:
    send_to_client(chunk)

Works with inheritance ({% extends %}), includes, and all control flow. Blocks like {% capture %} and {% spaceless %} buffer internally and yield the processed result.

Async Templates — Await in templates
{% async for item in fetch_items() %}
    {{ item }}
{% end %}

{{ await get_user() }}
Terminal Rendering — CLI/TUI output with ANSI colors
from kida.environment.terminal import terminal_env

env = terminal_env()
template = env.from_string("""
{{ "Deploy Status" | fg("cyan") | bold }}
{{ "=" * 40 | fg("dim") }}
{% for svc in services %}
{{ svc.name | ljust(20) }}{{ svc.status | badge }}
{% end %}
""")
print(template.render(services=[
    {"name": "api", "status": "running"},
    {"name": "worker", "status": "stopped"},
]))

Built-in components for panels, tables, trees, and more. Use kida render template.txt --data ctx.json from the CLI.

Fragment Caching — Cache expensive blocks
{% cache "navigation" %}
    {% for item in nav_items %}
        <a href="{{ item.url }}">{{ item.title }}</a>
    {% end %}
{% end %}
Block Rendering — Fragments and layout composition
# Render a single block (HTMX partials, cached nav)
html = template.render_block("content", title="Hello")

# Compose layout with pre-rendered blocks
layout = env.get_template("_layout.html")
html = layout.render_with_blocks({"content": inner_html}, title="Page")

Use Cases

Use case Key APIs Example
Static sites render(), fragment cache, bytecode cache Bengal
Dynamic web render_block(), render_stream(), render_with_blocks() Chirp
Terminal / CLI terminal_env(), LiveRenderer, kida render Dashboards, deploy scripts, reports
Streaming / SSE render_stream(), render_stream_async() Chunked HTTP, LLM streaming
Framework integration template_metadata(), validate_block_exists(), get_structure() Build adapters, validate routes

Architecture

Compilation Pipeline — AST-native
Template Source → Lexer → Parser → Kida AST → Compiler → Python AST → exec()

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
Dual-Mode Rendering — StringBuilder + streaming generator
# render() — StringBuilder (fastest, default)
_out.append(...)
return "".join(_out)

# render_stream() — Generator (streaming, chunked HTTP)
yield ...

The compiler generates both modes from a single template. render() uses StringBuilder for maximum throughput. render_stream() uses Python generators for statement-level streaming — ideal for chunked HTTP responses and Server-Sent Events.

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

  • Minimal — ~4.0µs (file-based)
  • Small — ~6.8µs (loop + filter)
  • Medium — ~0.2ms (~100 vars)
  • Large — ~1.6ms (1000 loop items) — 2.5x faster than Jinja2
  • Complex — ~19µs (3-level inheritance) — 1.5x faster than Jinja2
  • Concurrent (2–4 workers) — scales with worker count under Python 3.14t free-threading

See benchmarks/README.md and benchmarks/RESULTS.md for full Kida vs Jinja2 comparison.


Documentation

📚 lbliii.github.io/kida

Section Description
Get Started Installation and quickstart
Syntax Template language reference
Usage Loading, rendering, escaping
Framework Integration Block rendering, introspection, adapters
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

The Bengal Ecosystem

A structured reactive stack — every layer written in pure Python for 3.14t free-threading.

ᓚᘏᗢ Bengal Static site generator Docs
∿∿ Purr Content runtime
⌁⌁ Chirp Web framework Docs
=^..^= Pounce ASGI server Docs
)彡 Kida Template engine ← You are here Docs
ฅᨐฅ Patitas Markdown parser Docs
⌾⌾⌾ Rosettes Syntax highlighter Docs

Python-native. Free-threading ready. No npm required.


License

MIT License — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kida_templates-0.3.0.tar.gz (432.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kida_templates-0.3.0-py3-none-any.whl (325.5 kB view details)

Uploaded Python 3

File details

Details for the file kida_templates-0.3.0.tar.gz.

File metadata

  • Download URL: kida_templates-0.3.0.tar.gz
  • Upload date:
  • Size: 432.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kida_templates-0.3.0.tar.gz
Algorithm Hash digest
SHA256 b55329bbacb897ec3edc24870e53ec357fe85968ddafffb0d449445b1bca1c2a
MD5 d83e4a12db18a9cd20ae5a9f5f33671e
BLAKE2b-256 585fdb79a39557baf6f7ae640a196d371f3236e6610907d585c933c836fd1080

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.3.0.tar.gz:

Publisher: python-publish.yml on lbliii/kida

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kida_templates-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: kida_templates-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 325.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for kida_templates-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 189ed69ff181876faa238875801a3704bbe60db49efff47828430d84008f3e6d
MD5 9a207e0b7d7ad4eca17ae3b595793574
BLAKE2b-256 1bbef7b5e3ea54e8218635ade989a833a70c15f48be159a17da6e1b4667ee967

See more details on using hashes here.

Provenance

The following attestation bundles were made for kida_templates-0.3.0-py3-none-any.whl:

Publisher: python-publish.yml on lbliii/kida

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page