Python library for the handlebars templating language. It is a small wrapper around the handlebars-rust library.
Pyhandlebars is listed on PyPi:
pip install pyhandlebarsfrom pyhandlebars import Template
t: Template = Template("Hallo {{name}}")
rendered_text = t.format({"name": "world"})"
# Returns "Hello world"def test_simple_pydantic_support():
from pyhandlebars import Template
from pydantic import BaseModel
class Person(BaseModel):
name: str
t: Template[Person] = Template("This is {{name}}!")
rendered_text = t.format(Person(name="Alice"))
assert rendered_text == "This is Alice!"Every Template created without an explicit client= argument shares a single process-wide global client. This means partials and helpers registered on one template are immediately available to all other templates that use the default client.
from pyhandlebars import Template
# Both templates share the global client — the partial is visible to t2.
_ = Template("Hi {{name}}", name="greeting")
t = Template("{{> greeting}}")
print(t.format({"name": "Bob"})) # Hi BobPyHandlebars allows you to register your own helper functions. However, keep in mind that these are not as fast and performant as built-in helpers.
Each helper receives two arguments: params (a list of positional arguments from the template call) and context (the full data object passed to format).
Option A — PyHandlebars.helper on the global client
Access helper on the class (not an instance) to register directly on the global client — no explicit PyHandlebars() needed.
from pyhandlebars import PyHandlebars, Template
@PyHandlebars.helper
def shout(params: list, context: dict):
return f"{params[0].upper()} from {context['location']}"
# Supply a custom template name with name=
@PyHandlebars.helper(name="whisper")
def my_whisper_fn(params: list, context: dict):
return params[0].lower()
t = Template("{{shout name}} / {{whisper name}}")
assert t.format({"name": "Alice", "location": "Wonderland"}) == "ALICE from Wonderland / alice"Option B — register_helper / @client.helper() on a dedicated client
Use an explicit PyHandlebars() instance when you want helpers isolated from the global client.
from pyhandlebars import PyHandlebars, Template
def shout(params: list, context: dict):
return f"{params[0].upper()} from {context['location']}"
client = PyHandlebars()
client.register_helper("shout", shout)
# Decorator style:
@client.helper()
def whisper(params: list, context: dict):
return params[0].lower()
t = Template("{{shout name}} / {{whisper name}}", client=client)
assert t.format({"name": "Alice", "location": "Wonderland"}) == "ALICE from Wonderland / alice"More examples can be found in the tests/test_examples.py file.
The original HandlebarsJS supports different Built-in Helpers. PyHandlebars supports the following subset (given by handlebars-rust):
We benchmarked PyHandlebars against 13 other Python template engines across 4 examples, running 1,000 iterations each. Each benchmark measures two phases:
- Prepare — compiling / registering the template (done once per request cycle in a real app)
- Render — filling data into the compiled template (the hot path)
| Example | What it tests |
|---|---|
| Invoice | Simple variable substitution and list iteration over line items with a nested address |
| User profile | A boolean conditional (verified badge) combined with iteration over social links |
| Deployment report | Nested object access and dictionary lookups — status labels and region info keyed by name |
| Release report | Deep nesting — components each containing a test suite and a dependency list, plus environment conditionals |
Each box shows the render-time distribution across 1,000 runs. Tools are sorted fastest → slowest by average render time. The top chart uses a linear scale; the bottom uses a log scale to make differences between fast engines visible.
Any contribution to this library is welcomed. To get started into development! When you run into any problems, feel free to reach out to me.
I mainly setup the library for the use case of prompt templating. If you miss something, just send me a DM or feel free to jump in with a PR 💫
This library (PyHandlebars) is open sourced under the MIT License.
