Skip to main content

templane-python

Python implementation of Templane — typed template contracts for Jinja2.

Templane adds compile-time schema validation to your templates. Define what data your template expects in a small .schema.yaml file next to your .jinja, and Templane catches missing fields, typos, and wrong types before Jinja renders, not at 2am in production.

  • Conformance: 40/40 fixtures across the Templane protocol · 75 unit tests
  • Engine binding: Jinja2 (jinja_templane)
  • Also ships: breaking-change detector, schema hash
  • Runtime: Python 3.12+
  • License: Apache 2.0

Install

pip install templane-python
# or with uv:
uv add templane-python

Quick start

Create email.jinja (plain Jinja2 — not modified by Templane):

Hi {{ user.name }}! Your order #{{ order_id }} total is ${{ amount }}.

Create email.schema.yaml next to it (declares the data contract):

body: ./email.jinja
engine: jinja

user:
  type: object
  required: true
  fields:
    name: { type: string, required: true }
order_id:
  type: string
  required: true
amount:
  type: number
  required: true

Use from Python:

from jinja_templane import TemplaneEnvironment, TemplaneTemplateError

env = TemplaneEnvironment("templates")
tmpl = env.get_template("email.schema.yaml")

try:
    output = tmpl.render(
        user={"name": "Alice"},
        order_id="INV-042",
        amount=99.00,
    )
    print(output)
    # → "Hi Alice! Your order #INV-042 total is $99.0."
except TemplaneTemplateError as exc:
    for err in exc.errors:
        print(f"[{err.code}] {err.field}: {err.message}")

Validation errors — caught before rendering

# Missing field + wrong type both trip at once
try:
    tmpl.render(
        # user missing entirely
        order_id=42,      # wrong type
        amount="free",    # wrong type
    )
except TemplaneTemplateError as exc:
    for err in exc.errors:
        print(f"[{err.code}] {err.field}")

# [missing_required_field] user
# [type_mismatch] order_id
# [type_mismatch] amount

All errors are collected — never short-circuits at the first.


Breaking-change detection

Detect schema evolution issues before they break downstream data:

from templane_core.schema_parser import parse as parse_schema
from templane_core.models import typed_schema_from_dict
from templane_core.breaking_change import detect

def load(yaml_str: str, name: str):
    result = parse_schema(yaml_str, name)
    return typed_schema_from_dict(result["schema"])

old = load(open("schema-v1.yaml").read(), "v1")
new = load(open("schema-v2.yaml").read(), "v2")

changes = detect(old, new)
for c in changes:
    print(f"[{c.category}] {c.field_path}: {c.old} → {c.new}")

# Four categories:
#   removed_field        — schema had the field; now doesn't
#   required_change      — optional → required
#   type_change          — field type changed
#   enum_value_removed   — an enum value was removed

Safe changes (new optional field, added enum value, required → optional) are NOT reported.


API

jinja_templane — the engine binding

from jinja_templane import (
    TemplaneEnvironment,
    TemplaneTemplate,
    TemplaneTemplateError,
)

# Like jinja2.Environment, but get_template returns a TemplaneTemplate
env = TemplaneEnvironment(search_path: str | Path)
env.get_template(name: str) -> TemplaneTemplate
    # Handles both .schema.yaml (with body: reference) and legacy inline-body .templane files

tmpl.render(**data) -> str  # raises TemplaneTemplateError on validation failure
tmpl.schema                  # the parsed TypedSchema

templane_core — the protocol primitives

from templane_core.schema_parser import parse, load_from_path
from templane_core.type_checker import check
from templane_core.ir_generator import generate
from templane_core.breaking_change import detect
from templane_core.hash import schema_hash

# parse(yaml_str, schema_id) → dict with {schema, body?, body_path?, engine?, error?}
# load_from_path(path) → same shape, with body resolved from disk when sidecar
# check(schema, data) → list[TypeCheckError]
# generate(ast, data, schema_id, template_id) → TIRResult
# detect(old_schema, new_schema) → list[BreakingChange]
# schema_hash(schema) → "sha256:..." stable across equivalent schemas

Why Templane

Templates are untyped contracts. They accept a bag of values, look up names by string, and render something — even when the data has a typo, a missing field, or a wrong type. The failure is silent: the render succeeds, the customer gets a broken email, and you find out four days later.

Templane fixes this at the boundary. A schema next to your template declares what the template expects; the binding refuses to render when the data doesn't match. See the main README for the full pitch.


Adoption pattern

You don't migrate templates. Your existing .jinja files stay as-is. You drop one .schema.yaml beside each one:

templates/
  welcome.jinja                 ← untouched
  welcome.schema.yaml           ← NEW
  invoice.jinja                 ← untouched
  invoice.schema.yaml           ← NEW

Your code switches from jinja2.Environment to jinja_templane.TemplaneEnvironment. That's the migration.


Examples

Six worked examples under the repo's templane-python/examples/: hello, validation errors, nested objects and lists, Jinja features (filters, if/for), breaking-change detection, and a full password-reset email demo.


Building from source

git clone https://github.com/ereshzealous/Templane.git
cd Templane/templane-python
uv sync --extra dev
.venv/bin/pytest   # 75 tests

Links

License

Apache License 2.0

Release files for templane-python 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for templane-python 0.2.0
File Size Uploaded
templane_python-0.2.0.tar.gz 36.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for templane-python 0.2.0
File Interpreter ABI Platform
templane_python-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.1 kB

Release files / templane_python-0.2.0.tar.gz

Download URL templane_python-0.2.0.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
767f2f102470e9fa0bbbbff9242348562dc1f3e2f3666839af1b314cb995b92f
BLAKE2b-256 checksum
How to use checksums
decd4034e8f7ecfa3f7738c0f37fb44d1d5b552694ba3173471d99ae46aa829c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release files / templane_python-0.2.0-py3-none-any.whl

Download URL templane_python-0.2.0-py3-none-any.whl
Size 18.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
855916c682db6b7c338c76d19846858004f76a37c838b6d1d25079416a92d5cd
BLAKE2b-256 checksum
How to use checksums
d38e8089c1a730f5b0cad6cbd7ff0b14a1d5007e67686ba2066ca611bb202dd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page