Fast, HTML aware template engine
Project description
Piglet is a text and HTML templating language in the kid/genshi/kajiki family.
Key features:
Inhertitance through py:extends/py:block (similar to Jinja2)
Compiles templates to fast python byte code.
HTML aware. Output is always well formed by default and content is always escaped unless explicitly marked otherwise.
Supports reusable template functions, deep nesting of template inheritance, translations, embedded python expressions
This is what a piglet template looks like:
<py:extends href="layout.html">
<py:block name="content">
<h1>This is the content block.</h1>
<p>
Hello $user.firstnames $user.lastname!
</p>
<!--!
The following paragraph is marked for translation.
The i18n:name attribute substitues the python code interpolation
with a simple placeholder, so translators see this message:
'Today is ${day}'
-->
<p i18n:message="">
Today is <span i18n:name="day">${date.strftime('%a')}</span>.
</p>
<p py:choose="today.weekday()">
<py:when test="0">
I don't like Mondays
</py:when>
<py:when test="day == 4">
I never could get the hang of Thursdays
</py:when>
<py:otherwise>Is it the weekend yet?</py:otherwise>
</p>
<p py:for="verse in in poem">
<py:for each="line in verse">$line<br/></py:for>
</p>
</py:block>
There’s a text mode too:
Hello $user.firstnames $user.lastname!
{% trans %}
Today is {% transname "day" %}${date.strftime('%a')}{% end %}
{% end %}.
{% for verse in poem %}
{% for line in verse %}$line
{% end %}
{% end %}
Installation
To install the latest release using pip (recommended):
pip install piglet
To install the latest source:
hg clone https://bitbucket.org/ollyc/piglet cd piglet python setup.py install
Using Piglet templates from the Python API
A simple example of rendering a python string as a template:
from piglet import HTMLTemplate
template = HTMLTemplate('<p>$greeting</p)')
print(template.render({'greeting': 'Bonjour!'}))
Loading templates from disk:
from piglet import TemplateLoader
loader = TemplateLoader(['./templates/'])
template = loader.load('mytemplate.html')
print(template.render({'greeting': 'Hello!'})
A fully loaded example:
from piglet import TemplateLoader
import gettext
loader = TemplateLoader(
# List of directories to search for template files
['./templates/'],
# Auto reload templates when files are modified? Defaults to False,
# use True for development
auto_reload=True,
# The template class to use - either HTMLTemplate or TextTemplate
template_cls=HTMLTemplate,
# File encoding to use by default
default_encoding='UTF-8',
# A persistent on disk cache for piglet templates
cache_dir='.cache/piglet'
# A factory function returning a gettext Translations instance
# or compatible object. For example Django users could plug in
# `lambda: django.utils.translation`. If your app isn't translated
# omit this argument.
translations_factory=lambda: gettext.translation(...),
)
template = loader.load('mytemplate.html', encoding='UTF-8')
Templates can also be rendered as a stream. This might be useful for generating long documents that you don’t want to hold in memory all at once:
template = loader.load('huge.html', encoding='UTF-8')
for s in template({'data': load_massive_dataset()}):
sys.stdout.write(s)
Inheritance
The layout template should be marked up with <py:block> tags to indicate customization points:
<!DOCTYPE html>
<html>
<head>
<title py:block="title">Default title</title>
</head>
<body>
<py:block name="content">
Content goes here
</py:block>
</body>
</html>
Child templates then use <py:extends href="..."> to pull in the parent’s layout.
You can also define template functions:
<!--! File: widgets.html
-->
<py:def function="modal(content, title='hello')">
<div class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" data-dismiss="modal">X</button>
<h4 class="modal-title">$title</h4>
</div>
<div class="modal-body">
${content() if callable content else content}
</div>
<div class="modal-footer">
<button type="button">Close</button>
<button type="button">Save changes</button>
</div>
</div>
</div>
</div>
</py:def>
And use them in other templates:
<py:import href="widgets.html" alias="widgets"/>
<p>
${widgets.modal(content="Hello world!")}
</p>
Did you notice the funny ${content() if callable content else content} interpolation in the function body? That’s to support py:call, which can pass chunks of template as keyword arguments:
<py:call function="widgets.modal(fullpage=True)">
<py:keyword name="content">
This is the modal content. You can include
<a href="#">markup here</a> too!
</py:keyword>
</py:call>
License
Piglet is licensed under the Apache license version 2.0.
0.3 (released 2016-10-03)
The translation code now normalizes whitespace in i18n:messages
Bugfix: fixed extraction of translations within <py:else> blocks
Added translation support in text templates
0.2 (released 2016-10-02)
Bugfix: ensure that grammar files are included in binary distributions
Bugfix: fix for undefined variable error when using py:with to reassign a variable
0.1 (released 2016-10-01)
initial release
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.