Welcome to Lina¶
Lina is a minimal template system for Python, modelled after Google’s CTemplate library. It is designed to provide fast, safe template evaluation to generate code or other text documents.
enum DataTypes {
{{#types:list-separator=,NEWLINE}} {{name}}={{value:hex}}{{/types}}
}
evaluated with:
formats = [{'name':'Vector3i', 'value': 0x301}, {'name':'Vector3f', 'value': 0x302}]
will produce:
enum DataTypes {
Vector3i = 0x301,
Vector3f = 0x302
}
Overview¶
The base class in Lina is lina.Template which must be initialized with the template contents. It can be then evaluated to a string using lina.Template.Render() and lina.Template.RenderSimple().
Lina has two main directives, values and blocks. A value is something which is replaced directly by the provided value, while a block is used to iterate over collections. Both blocks and values can be optionally formatted using a formatter, which allows for example to turn a string into uppercase inside the template.
Values are escaped using double curly braces:
Hello {{name}}!
Blocks have an additional prefix before the variable, # for the block start and / for the block end:
{{#users}}Hello {{name}}!{{/users}}
This requires to pass an array of named objects:
template.Render ({'users':[{'name':'Alice'}, {'name':'Bob'}]})
In some cases, accessing members by names is unnecessary complicated. Lina provides a special syntax to access the current element, using a single dot. Using a self-reference, the template above can be simplified to:
{{#users}}Hello {{.}}!{{/users}}
and rendered with:
template.Render ({'users': ['Alice', 'Bob']})
or even simpler using lina.Template.RenderSimple():
template.RenderSimple (users = ['Alice', 'Bob'])
Both self-references as well as values can also access fields of an object. Assuming the User class has fields name, age, the follwing template will print the user name and age:
{{#users}}Hello {{.name}}, you are {{.age}} years old!{{/users}}
For an object, use {{item.field}}. The field accessor syntax works for both fields as well as associative containers, that is, for Lina, the following two objects are equivalent:
u = {'name':'Alice'}
and:
class User:
def __init__(self, name):
self.name = name
u = User ('Alice')
It is also possible to directly reference indexed items using [0], [1], etc. For instance, the following template:
{{#vectors}}X: {{.[0]}}, Y: {{.[1]}}, Z: {{.[2]}}\n{{/vectors}}
rendered with:
template.RenderSimple (vectors = [[0, 1, 2], [3, 4, 5]])
will produce:
X: 0, Y: 1, Z: 2
X: 3, Y: 4, Z: 5
For blocks, Lina provides additional modifiers to check whether the current block execution is the first, an intermediate or the last one:
{{#block}}{{variable}}{{#block#Separator}},{{/block#Separator}}{{/block}}
#First will be only expanded for the first iteration, #Separator will be expanded for every expansion which is neither first nor last and #Last will be expanded for the last iteration only. If there is only one element, it will considered both first and last item of the sequence.
Whitespace can be also part of a template. Use {{_NEWLINE}} to get a new line character inserted into the stream, and {{_SPACE}} to get a blank space.
If a block variable is not found, the block will be not expanded. It is possible to capture this case using ! blocks, which are only expanded if the variable is not present:
{{!users}}No users :({{/users}}
Rendered with template.Render (), this will yield No users :(. This can be used to emulate conditional statements.
Contents:
API reference¶
- class lina.CBooleanFormatter¶
Bases: lina.Formatter
For booleans, write true or false to the output. Otherwise, the input is just passed through.
- Format(value)¶
- class lina.DefaultFormatter(value)¶
Bases: lina.Formatter
Emit the default if the value is None, otherwise the value itself.
- Format(text)¶
- class lina.EscapeNewlineFormatter¶
Bases: lina.Formatter
Escape embedded newlines.
- Format(text)¶
- class lina.EscapeStringFormatter¶
Bases: lina.Formatter
Escape embedded newlines, tabs and quotes.
- Format(text)¶
- class lina.Formatter(formatterType)¶
Bases: builtins.object
Base class for all formatters.
A formatter can be used to transform blocks/values during expansion.
- Format(text)¶
Format a value or a complete block.
- IsBlockFormatter()¶
Check if this formatter is a block formatter.
- IsValueFormatter()¶
Check if this formatter is a value formatter.
- OnBlockBegin(isFirst)¶
Called before a block is expanded.
Parameters: isFirst – True if this is the first expansion of the block. Returns: String or None. If a string is returned, it is prepended before the current block expansion.
- OnBlockEnd(isLast)¶
Called after a block has been expanded.
Parameters: isLast – True if this is the last expansion of the block. Returns: String or None. If a string is returned, it is appended after the current block expansion.
- class lina.FormatterType¶
Bases: enum.Enum
The formatter type, either Block or Value.
- lina.GetFormatter(name, value=None, position=None)¶
Get a formatter.
If the formatter cannot be found, an exception is raised.
- class lina.HexFormatter¶
Bases: lina.Formatter
Write an integer as a hex literal (0x133F).
- Format(value)¶
- class lina.IndentFormatter(depth)¶
Bases: lina.Formatter
Indent a block using tabs.
- Format(block)¶
- OnBlockBegin(isFirst)¶
- exception lina.InvalidBlock(message, position)¶
Bases: lina.TemplateException
An invalid block was encountered.
- exception lina.InvalidFormatter(message, position)¶
Bases: lina.TemplateException
An invalid formatter was encountered.
This exception is raised when a formatter could not be found or instantiated.
- exception lina.InvalidToken(message, position)¶
Bases: lina.TemplateException
An invalid token was encountered.
- exception lina.InvalidWhitespaceToken(message, position)¶
Bases: lina.TemplateException
An invalid whitespace token was encountered.
- class lina.ListSeparatorFormatter(value)¶
Bases: lina.Formatter
Separate block entries.
This formatter will insert a value between block expansions.
- OnBlockEnd(isLast)¶
- class lina.PrefixFormatter(prefix)¶
Bases: lina.Formatter
Add a prefix to a value.
- Format(text)¶
- class lina.SuffixFormatter(suffix)¶
Bases: lina.Formatter
Add a suffix to a value.
- Format(text)¶
- class lina.Template(template, includeHandler=None)¶
Bases: builtins.object
The main template class.
- Render(context)¶
Render the template using the provided context.
- RenderSimple(**items)¶
Simple rendering function.
This is just a convenience function which creates the context from the passed items and forwards them to Template.Render().
- exception lina.TemplateException(message, position)¶
Bases: builtins.Exception
Base class for all exceptions thrown by Lina.
- GetPosition()¶
Get the position where the exception occured.
Returns: An object with two fields, line and column.
- class lina.TemplateRepository(templateDirectory, suffix='')¶
Bases: lina.IncludeHandler
A file template repository.
This template repository will load files from a specified folder.
- Get(name)¶
- class lina.TextStream(text)¶
Bases: builtins.object
A read-only text stream.
The text stream is used for input only and keeps track of the current read pointer position in terms of line/column numbers.
- Get()¶
Get a character.
If the end of the stream has been reached, None is returned.
- GetOffset()¶
Get the current read offset in characters from the beginning of the stream.
- GetPosition()¶
Get the current read position as a pair (line, column).
- IsAtEnd()¶
Check if the end of the stream has been reached.
- Peek()¶
Peek at the next character in the stream if possible. Returns None if the end of the stream has been reached.
- Reset()¶
Reset back to the beginning of the stream.
- Skip(length)¶
Skip a number of characters starting from the current position.
- Substring(start, end)¶
Get a substring of the stream.
- Unget()¶
Move one character back in the input stream.
- class lina.Token(name, start, end, position)¶
Bases: builtins.object
Represents a single token.
Each token may contain an optional list of flags, separated by colons. The grammar implemented here is:
[prefix]?[^:}]+(:[^:})+, for example: {{#Foo}} -> name = Foo, prefix = # {{Bar:width=8}} -> name = Bar, prefix = None, flags = {width:8}
- EvaluateWhiteSpaceToken(position)¶
Get the content of this token if this token is a whitespace token.
If the content is not a valid whitespace name, this function will raise InvalidWhitespaceToken.
- GetEnd()¶
Get the end offset.
- GetFormatters()¶
Get all active formatters for this token.
- GetName()¶
Get the name of this token.
- GetPosition()¶
Get the position as a (line, column) pair.
- GetStart()¶
Get the start offset.
- IsBlockClose()¶
Return true if this token is a block-close token.
- IsBlockStart()¶
Return true if this token is a block-start token.
- IsIncludeToken()¶
Return true if this token is an include directive.
- IsNegatedBlockStart()¶
Return true if this token is a negated block-start token.
- IsSelfReference()¶
Return true if this token is a self-reference.
- IsValue()¶
- IsWhiteSpaceToken()¶
Return true if this token is a whitespace directive.
- class lina.UppercaseFormatter¶
Bases: lina.Formatter
Format a value as uppercase.
- Format(text)¶
- class lina.WidthFormatter(width)¶
Bases: lina.Formatter
Align the value to a particular width.
Negative values align to the left (i.e., the padding is added on the left: ' 42'), positive values to the right ('42 ').
- Format(text)¶
- class lina.WrapStringFormatter¶
Bases: lina.Formatter
Wrap strings with quotation marks.
- Format(text)¶