Skip to main content

Static type checking for Jinja templates

Project description

jinja-typed-template

Type-safe Jinja2 templates with compile-time validation — keep your Python code and Jinja templates in sync, fail fast on mismatches, and never ship a broken template again.

Installation

pip install jinja-typed-template

For Flask support:

pip install jinja-typed-template[flask]

Quick Start

1. Annotate your template

Add a header comment declaring every variable the template uses, along with its type:

{#
    name: str
    age: int
    items: list[str]
#}
<h1>Hello {{ name }}!</h1>
<p>You are {{ age }} years old.</p>
<ul>
  {% for item in items %}
    <li>{{ item }}</li>
  {% endfor %}
</ul>

2. Define a typed template class

Subclass TypedTemplate, set the template name, and declare fields with type hints:

from jinja_typed_template import TypedTemplate, env_context
from jinja2 import Environment, FileSystemLoader

class ProfileTemplate(TypedTemplate):
    __template_name__ = "profile.html"
    name: str
    age: int
    items: list[str]

3. Render safely

Wrap usage in env_context to bind a Jinja2 environment, then instantiate and render:

env = Environment(loader=FileSystemLoader("templates"))

with env_context(env):
    t = ProfileTemplate(name="Alice", age=30, items=["apples", "bananas"])
    print(t.render())

What Gets Validated

Every TypedTemplate instance is validated at construction time (__post_init__). Three checks run automatically:

Check Catches
Type checking T(name=123) when name: str — raises TypeError
Variable matching Missing or extra fields vs. what the template actually uses — raises ValueError
Header comment consistency Header declares name: int but class says name: str — raises TypeError

This means you catch mismatches the moment you create the object, not when a user hits the page.

API Reference

TypedTemplate

Base class. Subclass it, set __template_name__, and declare typed fields.

Member Description
render() Render the template to a string
context_dict Dict of all field names → values
copy_updating(**kwargs) Return a new instance with some fields replaced (instances are frozen/immutable)

env_context(env)

Context manager that binds a Jinja2 Environment for the current thread/context. Required before creating or rendering any TypedTemplate.

from jinja_typed_template import env_context

with env_context(env):
    t = MyTemplate(...)

TypedTemplateExtension (Flask)

Flask extension that automatically pushes the app's Jinja2 environment into the context on every request. Context-processor variables are also discovered and excluded from validation, so they can appear in templates without being declared in the header.

from flask import Flask
from jinja_typed_template.extension_flask import TypedTemplateExtension

app = Flask(__name__)
ext = TypedTemplateExtension()
ext.init_app(app)

# Context-processor variables are automatically recognised:
@app.context_processor
def inject_globals():
    return {"app_name": "MyApp"}

Now any TypedTemplate instantiated inside a request will just work — no manual env_context needed.

Header Comment Format

Place a Jinja2 comment at the very top of the template:

{#
    variable_name: TypeName
    another_var: list[str]
    optional_var: str = "default"
#}
  • variable_name must match a field on your TypedTemplate subclass.
  • TypeName uses a short-form representation (str, int, list[str], dict[str, int], etc.) and must match the Python type hint.
  • Default values after = are stripped — they're documentation only.

License

MIT

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

jinja_typed_template-0.1.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

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

jinja_typed_template-0.1.0-py3-none-any.whl (9.0 kB view details)

Uploaded Python 3

File details

Details for the file jinja_typed_template-0.1.0.tar.gz.

File metadata

  • Download URL: jinja_typed_template-0.1.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","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

Hashes for jinja_typed_template-0.1.0.tar.gz
Algorithm Hash digest
SHA256 472a9f56ae55f517d50cb5b20e45afacd72df8662f6ad4db2299a9272a265521
MD5 61a263f4a5cecfdcc330439633269615
BLAKE2b-256 fe55f2903cbef0584bc901ca890bedca57bf003e5ae6e7f5612c29cf31e4eb34

See more details on using hashes here.

File details

Details for the file jinja_typed_template-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jinja_typed_template-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","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

Hashes for jinja_typed_template-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 77190321953b1a5c61259e9c7210f7d1d0acce2895b6fc03af99ccdc7e23d733
MD5 5171c301c79ebc996ab177f1f694996c
BLAKE2b-256 e8eb763fde1dbc674b9e49af07d9ca6fa65fd4b2cba9937c7f7170737b1cce5f

See more details on using hashes here.

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