Reference

The process of building a template into a function has the following steps:

  • The template is broken down into blocks (such as literal text and code execution) that are treated differently. This is handled by the block parser.
  • The resultant sequence of blocks is passed to the Parser to be turned into a parse tree.
  • The parse tree is processed by code generation to make Python bytecode.

Compiler

The compiler module contains the public interface to the library.

class margate.compiler.Compiler(template_locator=None)[source]

The Compiler takes a template in string form and returns bytecode that implements the template.

compile(source)[source]

Compile the template source code into a callable function.

Returns:A callable function that returns rendered content as a string when called.
class margate.compiler.TemplateLocator[source]

The template locator abstracts the details of locating templates when one template extends another (such as with the {% extends %} tag)self.

Code generation

This module contains the building blocks of the final template function, in the form of bytecode generators.

There are a series of classes in here that are used as nodes in the code generation tree, and each one implements a make_bytecode() method.

class margate.code_generation.Sequence[source]

A sequence of nodes that occur in a parse tree. Elements in the sequence can themselves be sequences (thus forming a tree).

class margate.code_generation.ForBlock(for_node)[source]
class margate.code_generation.IfBlock(condition)[source]

The IfBlock generates code for a conditional expression.

This currently only includes literal True and False as expressions, and doesn’t support an else branch.

class margate.code_generation.ExtendsBlock(template)[source]
class margate.code_generation.ReplaceableBlock(name)[source]
class margate.code_generation.VariableExpansion(variable_name)[source]

A variable expansion takes the value of an expression and includes it in the template output.

class margate.code_generation.Literal(contents)[source]
class margate.code_generation.Execution(expression)[source]

Todo

This doesn’t really belong in this module. It’s here because we’re combining two different types: block parser output and code generation.

Block parser

The block parser splits a template into the blocks that make it up. There are three different sorts of data in a template that get handled in different ways:

  • Literal text, which just gets embedded in the output (but may be skipped or repeated by executing code around it).
  • Executable code
  • Embedded variable expressions that get expanded into text output.

It’s implemented as a state machine, where the template starts out in literal text and transitions to a different state depending on whether it encounters {{, }}, {% or %}.

class margate.block_parser.LiteralState(text)[source]

The literal state is the state the block parser is in when it is processing anything that will be included in the template output as a literal. The template starts out in literal state and transitions back into it every time a block is closed.

class margate.block_parser.ExecutionState(text)[source]

Execution state is the state when any kind of code execution is occurring. This includes the start and ends of blocks.

class margate.block_parser.ExpressionState(text)[source]

Expression state occurs when processing a {{ ... }} expression that embeds the value of an expression into the output.

Parser

The parser converts the template language into a usable structured form.

There are two layers to the parsing: breaking the template down into blocks (which is done by the block_parser module), and parsing the expressions that appear in the execution blocks within the template.

The parser in this module uses a combination of ad hoc parsing, funcparserlib and ast.parse. The top-level rules in the language (if, for, endif etc.) are handled ad hoc since they are not recursive. However, the expression that is given as an argument to if is an arbitrary expression and parsed

class margate.parser.Parser(template_locator=None)[source]

The Parser is responsible for turning a template in “tokenised” form into a tree structure from which it is straightforward to generate bytecode.

The input is in the form of a flat list of atomic elements of the template, where literal text (of any length) is a single element, and a {% %} or {{ }} expression is a single element.

Figuring out nesting of starting and ending of loops happens within the parser.

parse(tokens)[source]

Parse a token sequence into a Sequence object.

margate.parser.parse_expression(expression)[source]

Parse an expression that appears in an execution node, i.e. a block delimited by {% %}.

This can be a compound expression like a for statement with several sub-expressions, or it can just be a single statement such as endif.

Parameters:expression (list) – Tokenised expression.