Skip to main content

Introduction

Tempiny is a tiny and really simple template engine.

The main feature is to be able to execute arbitrary python code inside the template, which makes it really powerful for code generation for example.

See the skbs project to have a sense of what it can achieve !

Install

Simply pip install it :

pip install tempiny

Template syntax

First an example to demonstrate all its features :

This text will be printed as it is

Lines starting with '##' (or a user-configured prefix) are python code.

## a=5 # this won't be printed
## # this is a comment in the python script. Won't be printed.

if/else/for/while/with/try/except etc blocks don't need indentation. Instead, a line containing only '## -' marks the block end.

## for i in range(a) :
##   b = a + 1 # you may indent
## c = a +2 # or not, still in the for block.
This text will be printed 5 times (a = {{a}}) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
##   for j in range(3) :
You can also nest loops
##   -
## # ↑ end of inner loop
## -
## # end of outer loop

Expression can be as complex you want as long as they are valid python expression returning something that can be transformed to a string :
{{ ";".join( str(i) + f' - {a=},{b=},{c=}' for i in range(2)) }}

will be output as :

This text will be printed as it is

Lines starting with '##' (or a user-configured prefix) are python code.


if/else/for/while/with/try/except etc blocks don't need indentation. Instead, a line containing only '## -' marks the block end.

This text will be printed 5 times (a = 5) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
You can also nest loops
You can also nest loops
You can also nest loops
This text will be printed 5 times (a = 5) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
You can also nest loops
You can also nest loops
You can also nest loops
This text will be printed 5 times (a = 5) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
You can also nest loops
You can also nest loops
You can also nest loops
This text will be printed 5 times (a = 5) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
You can also nest loops
You can also nest loops
You can also nest loops
This text will be printed 5 times (a = 5) Btw, between a double brace (2 '{'), you can put expression that will be converted to str, and printed instead.
To escape it, The prefered way is to declare variables containing the tokens (as done in skbs)
You can also nest loops
You can also nest loops
You can also nest loops

Expression can be as complex you want as long as they are valid python expression returning something that can be transformed to a string : 0 - a=5,b=6,c=7;1 - a=5,b=6,c=7

Basically, there are 3 contexts :

Code context

Each line starting by the code prefix (specified in plugin.py, or '##' by default) is basically python code except for the block delimitation : in python, the indentation level delimits a block while with tempiny, for practical use, indentation doesn't matter, and a block is ended by a single dash ( "-" ).

Example :

## a = 5
## for i in range(a) :
##   b = 2 + i
##   # Do come stuff
## c=3 # this is still in the for
## -
## # end of the for

Any python code is allowed. This is the reason you should use templates only from trusted sources.

Text context

Any line that doesn't start with the code prefix is "text", and will be output as is each time the execution flow reaches it. Basically, you can imagine (by the way, this is actually how it is implemented...) each Text context is like a call to print

For example, the following :

This is a text
## for i in range(3):
To see
## -
how it works

Will output :

This is a test
To see
To see
To see
how it works

Expression context

Inside a Text context, you may want to print an expression (for example a variable value or the result of a python call etc.) You can do it by surrounding it with the expression delimiters (specified in plugin.py or '{{' and '}}' by default). It will be replaced by the expression value at the time of execution. Example:

## for i in range(3)
Item number {{i}}
## -

Will print :

Item number 0
Item number 1
Item number 2

Any python expression is allowed.

Once again, you should only execute trusted templates.

API

from tempiny import Tempiny # import tempiny

There are 3 built-in dialects:

Tempiny.C  = dict(stmt_line_start=r'//#', begin_expr='{{', end_expr='}}')
Tempiny.PY = dict(stmt_line_start=r'##', begin_expr='{{', end_expr='}}')
Tempiny.TEX = dict(stmt_line_start=r'%#', begin_expr='<<', end_expr='>>')

To configure a Tempiny instance :

T = Tempiny(
  stmt_line_start=PY['stmt_line_start'], # Code prefix. 
  begin_expr=PY['begin_expr'], # Expression delimiter (begin)
  end_expr=PY['end_expr'] # Expression delimiter (end)
)

Note that you can use any string for these tokens.

Tempiny.compile(self, f:Iterable[str], filename='<template>', default_globals={}, default_locals=None) -> Template: This method compiles a template. f should be an iterable of strings (an open file is ok). default_globals is a dict you can provide to have a default global scope when calling the template. You should probably leave default_locals to None except if you know what you are doing.

Example :

with open('test_template', 'r') as f:
  template = T.compile(f, 'test_template')

Template.__call__(self, out_stream, _globals={}, _locals=None) -> (dict, Exception) This method permits to call the template, outputting in out_stream (it should at least have a write(s:str) method. You can provide a global scope (it will be shallow-copied before entering the template) through _globals to pass values to the template. You can also provide a local scope through _locals, but it can lead to unexpected behaviour (not defined errors inside function or list-comprehension). Except if you know what to do, let it None, it will contain the same content as the globals. It returns the new locals (to retrieve names defined or modified from the template), and None if no exception occurred, or the exception if one raised.

Example:

with open('result', 'w') as f:
  template(f, {'author': 'Léo Flaventin Hauchecorne', 'date' : 2016})

License Notice

Tempiny is a tiny template engine Copyright © 2016-2020 Léo Flaventin Hauchecorne

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Release files for tempiny 1.5

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

Source distribution (sdist)

Source distribution for tempiny 1.5
File Size Uploaded
tempiny-1.5.tar.gz 14.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tempiny 1.5
File Interpreter ABI Platform
tempiny-1.5-py3-none-any.whl Python 3 none any Details

Total release size: 29.3 kB

Release files / tempiny-1.5.tar.gz

Download URL tempiny-1.5.tar.gz
Size 14.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2340a5093a41b87afd18b21c2fafd7de62e7675eedbf302bf15369a65f33f364
BLAKE2b-256 checksum
How to use checksums
4bad550612616ce2000df2ce5a8d829ec4b52f0541e920c9a569fbffa9a5ad53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / tempiny-1.5-py3-none-any.whl

Download URL tempiny-1.5-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
54951f8638be7271c3397b561a6e4105a10dd08be7403b130b0321883e3bf321
BLAKE2b-256 checksum
How to use checksums
c3eac7fb0a3625cdae278eef378f4232fde8d907b7be8f8367b47b6811e7f102
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

1.5 This release

2 release files

1.4

2 release files

1.3

2 release files

1.2

2 release files

1.1

2 release files

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