Piglet templates: fast, HTML aware templating engine
Project description
Piglet Templates
================
Piglet is a text and HTML templating language in the kid/genshi/kajiki family.
The Piglet template engine offers:
- Template inhertitance through py:extends/py:block (similar to Jinja2)
- Compiles templates to fast python byte code.
- HTML aware templating: output is well formed and content is
escaped, preventing XSS attacks.
- Reusable template functions, deep nesting of template inheritance,
flexible translations and embedded python expressions
`Documentation <http://ollycope.com/software/piglet/>`_
\| `Bitbucket repository <https://bitbucket.org/ollyc/piglet>`_
This is what a piglet template looks like:
.. code:: html
<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 templating mode too:
.. code::
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):
.. code:: sh
pip install piglet
To install the latest source:
.. code:: sh
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 to a template:
.. code:: python
from piglet import HTMLTemplate
template = HTMLTemplate('<p>$greeting</p)')
print(template.render({'greeting': 'Bonjour!'}))
Loading templates from disk:
.. code:: python
from piglet import TemplateLoader
loader = TemplateLoader(['./templates/'])
template = loader.load('mytemplate.html')
print(template.render({'greeting': 'Hello!'})
A fully loaded example:
.. code:: python
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:
.. code:: python
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:
.. code:: html
<!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:
.. code:: html
<!--! 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>
Template functions can be imported into other templates:
.. code:: html
<py:import href="widgets.html" alias="widgets"/>
<p>
${widgets.modal(content="Hello world!")}
</p>
Did you notice the ``${content() if callable content else content}``
interpolation in the function body? That's to support ``py:call``, which can
pass chunks of template code as keyword arguments:
.. code:: html
<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.4.3 (released 2016-11-29)
---------------------------
- Loader: an ``extension_map`` argument can be given, mapping file extensions
to template classes. By default ``.txt`` is mapped to
:class:`piglet.template.TextTemplate` and ``.html`` to
:class:`piglet.template.HTMLTemplate`.
- Bugfix: unicode symbols no longer cause an exception when used in template
expressions in Python 2.
- Bugfix: fixed multiple scoping issue with variable names used in
the argument lists of ``<py:def>`` template function directives.
0.4.2 (released 2016-11-08)
---------------------------
- Added <py:comment> directive
- Exceptions are now reraised, ensuring the originating traceback is shown.
- ``<py:call>`` Now passes its inner HTML as a positional argument, unless it
is whitespace.
- ``<py:call>`` is now an inner directive, meaning that
``<p py:call="foo()"></p>``
will now fill the ``<p>`` element rather than replacing it.
- The loader cache directory may be specified via the ``PIGLET_CACHE``
environment variable.
- Added i18n:comment directive
0.4.1 (released 2016-10-17)
---------------------------
- Added ``{% def %}`` and ``{% for %}`` text template directives
- Added ``allow_absolute_paths`` option to TemplateLoader
0.4 (released 2016-10-16)
-------------------------
- Bugfix: ensure ``<py:else>`` directives are always attached to the correct
``<py:if>``
- Added ``i18n:trans`` as an alias for i18n:translate
- ``i18n:name`` directives now have a shorter alias
(``i18n:s``, for substitution) and can take an optional expr attribute,
eg ``<i18n:s name="foo" expr="calculate_foo()"/>``
- Interpolations in translated strings are now extracted using the
interpolation text as a placeholder in the absence of a
``i18n:name`` directive
- ``py:whitespace="strip"`` no longer strips whitespace between tags
on the same line.
- Text template directives now include ``{% with %}``,
``{% extends %}`` and ``{% block %}``
- <py:extend> can now be used to load a template of the same name elsewhere
on the template search path.
- The search algorithm used by TemplateLoader is improved
- Bugfix: fix for duplicate rendering when super() is used in the middle of the
inheritance chain
- Generated code uses ``yield from`` where it supported by the python version.
- The caching code has been simplified, caching .py files to disk containing
the compiled python source.
- Bugfix: ``py:attrs`` no longer raises an exception
- Bugfix: interpolations can now contain entity references
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
================
Piglet is a text and HTML templating language in the kid/genshi/kajiki family.
The Piglet template engine offers:
- Template inhertitance through py:extends/py:block (similar to Jinja2)
- Compiles templates to fast python byte code.
- HTML aware templating: output is well formed and content is
escaped, preventing XSS attacks.
- Reusable template functions, deep nesting of template inheritance,
flexible translations and embedded python expressions
`Documentation <http://ollycope.com/software/piglet/>`_
\| `Bitbucket repository <https://bitbucket.org/ollyc/piglet>`_
This is what a piglet template looks like:
.. code:: html
<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 templating mode too:
.. code::
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):
.. code:: sh
pip install piglet
To install the latest source:
.. code:: sh
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 to a template:
.. code:: python
from piglet import HTMLTemplate
template = HTMLTemplate('<p>$greeting</p)')
print(template.render({'greeting': 'Bonjour!'}))
Loading templates from disk:
.. code:: python
from piglet import TemplateLoader
loader = TemplateLoader(['./templates/'])
template = loader.load('mytemplate.html')
print(template.render({'greeting': 'Hello!'})
A fully loaded example:
.. code:: python
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:
.. code:: python
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:
.. code:: html
<!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:
.. code:: html
<!--! 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>
Template functions can be imported into other templates:
.. code:: html
<py:import href="widgets.html" alias="widgets"/>
<p>
${widgets.modal(content="Hello world!")}
</p>
Did you notice the ``${content() if callable content else content}``
interpolation in the function body? That's to support ``py:call``, which can
pass chunks of template code as keyword arguments:
.. code:: html
<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.4.3 (released 2016-11-29)
---------------------------
- Loader: an ``extension_map`` argument can be given, mapping file extensions
to template classes. By default ``.txt`` is mapped to
:class:`piglet.template.TextTemplate` and ``.html`` to
:class:`piglet.template.HTMLTemplate`.
- Bugfix: unicode symbols no longer cause an exception when used in template
expressions in Python 2.
- Bugfix: fixed multiple scoping issue with variable names used in
the argument lists of ``<py:def>`` template function directives.
0.4.2 (released 2016-11-08)
---------------------------
- Added <py:comment> directive
- Exceptions are now reraised, ensuring the originating traceback is shown.
- ``<py:call>`` Now passes its inner HTML as a positional argument, unless it
is whitespace.
- ``<py:call>`` is now an inner directive, meaning that
``<p py:call="foo()"></p>``
will now fill the ``<p>`` element rather than replacing it.
- The loader cache directory may be specified via the ``PIGLET_CACHE``
environment variable.
- Added i18n:comment directive
0.4.1 (released 2016-10-17)
---------------------------
- Added ``{% def %}`` and ``{% for %}`` text template directives
- Added ``allow_absolute_paths`` option to TemplateLoader
0.4 (released 2016-10-16)
-------------------------
- Bugfix: ensure ``<py:else>`` directives are always attached to the correct
``<py:if>``
- Added ``i18n:trans`` as an alias for i18n:translate
- ``i18n:name`` directives now have a shorter alias
(``i18n:s``, for substitution) and can take an optional expr attribute,
eg ``<i18n:s name="foo" expr="calculate_foo()"/>``
- Interpolations in translated strings are now extracted using the
interpolation text as a placeholder in the absence of a
``i18n:name`` directive
- ``py:whitespace="strip"`` no longer strips whitespace between tags
on the same line.
- Text template directives now include ``{% with %}``,
``{% extends %}`` and ``{% block %}``
- <py:extend> can now be used to load a template of the same name elsewhere
on the template search path.
- The search algorithm used by TemplateLoader is improved
- Bugfix: fix for duplicate rendering when super() is used in the middle of the
inheritance chain
- Generated code uses ``yield from`` where it supported by the python version.
- The caching code has been simplified, caching .py files to disk containing
the compiled python source.
- Bugfix: ``py:attrs`` no longer raises an exception
- Bugfix: interpolations can now contain entity references
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.
Source Distribution
piglet-0.4.3.tar.gz
(51.1 kB
view hashes)