Package: tempiny
IntroductionTempiny 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 !InstallSimply pip install it :pip install tempinyTemplate syntaxFirst 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 loopsExpression 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=7Basically, there are 3 contexts :Code contextEach line starting by the code prefix (specified inplugin.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 forAny python code is allowed. This is the reason you should use templatesonly from trusted sources.Text contextAny 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 toprintFor example, the following :This is a text
## for i in range(3):
To see
## -
how it worksWill output :This is a test
To see
To see
To see
how it worksExpression contextInside 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 inplugin.pyor '{{' 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 2Any python expression is allowed.Once again, you should only execute trusted templates.APIfrom tempiny import Tempiny # import tempinyThere 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.fshould be an iterable of strings (an open file is ok).default_globalsis a dict
you can provide to have a default global scope when calling the template. You should probably leavedefault_localsto 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 inout_stream(it should at least have awrite(s:str)method.
You can provide a global scope (it will be shallow-copied before entering the template) through_globalsto
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 NoticeTempiny is a tiny template engine
Copyright © 2016-2020 Léo Flaventin HauchecorneThis 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