Skip to main content

Tiny template engine

Project description

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 powerfull 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 be 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 ouputed as :

This text will be printed as it is

lines starting with '##' (or a user-configured prefix) are be 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 pratical 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 outputed as is each time the execution flow reaches it. Basically, you can imagine (btw, 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 cexpression is allowed.

Once again, you sould 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 kwnow 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, outputing 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 retrive names defined or modiied from the template), and None if no exception occured, 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

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

tempiny-1.0.tar.gz (6.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tempiny-1.0-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file tempiny-1.0.tar.gz.

File metadata

  • Download URL: tempiny-1.0.tar.gz
  • Upload date:
  • Size: 6.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.23.0 setuptools/47.1.1 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.3

File hashes

Hashes for tempiny-1.0.tar.gz
Algorithm Hash digest
SHA256 32266132e1e190b99b9f60bf7c671003ba9ae94588b4e1848105447c4251e2d8
MD5 4aca8f96471e896896ccae4c4f974d73
BLAKE2b-256 2beb89054bdd5cac3472417469b15112bcd794ae96dd63851bc34b44d1fe3342

See more details on using hashes here.

File details

Details for the file tempiny-1.0-py3-none-any.whl.

File metadata

  • Download URL: tempiny-1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.23.0 setuptools/47.1.1 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.3

File hashes

Hashes for tempiny-1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8a825484ba5ff375e5ec39ac9a3767a8ff8fe177adbee630613f32918a5f7f4a
MD5 75cfd4435e0631ee5262fe8311d2315b
BLAKE2b-256 677c3091a1755d9bb2e26aef592d699e9b0a4f7c700e5d5ed19d8435c709feb1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page