Previous Topic

Next Topic

Quick Search

The Context is the central object that is created when
a template is first executed, and is responsible for handling
all communication with the outside world. Within the template
environment, it is available via the reserved namecontext. The Context includes two
major components, one of which is the output buffer, which is a
file-like object such as Python’s StringIO or similar, and
the other a dictionary of variables that can be freely
referenced within a template; this dictionary is a combination
of the arguments sent to the render() function and
some built-in variables provided by Mako’s runtime environment.

The buffer is stored within the Context, and writing
to it is achieved by calling the write() method
– in a template this looks like context.write('somestring').
You usually don’t need to care about this, as all text within a template, as
well as all expressions provided by ${}, automatically send
everything to this method. The cases you might want to be aware
of its existence are if you are dealing with various
filtering/buffering scenarios, which are described in
Filtering and Buffering, or if you want to programmatically
send content to the output stream, such as within a <%%>
block.

<%context.write("some programmatic text")%>

The actual buffer may or may not be the original buffer sent to
the Context object, as various filtering/caching
scenarios may “push” a new buffer onto the context’s underlying
buffer stack. For this reason, just stick with
context.write() and content will always go to the topmost
buffer.

When your template is compiled into a Python module, the body
content is enclosed within a Python function called
render_body. Other top-level defs defined in the template are
defined within their own function bodies which are named after
the def’s name with the prefix render_ (i.e. render_mydef).
One of the first things that happens within these functions is
that all variable names that are referenced within the function
which are not defined in some other way (i.e. such as via
assignment, module level imports, etc.) are pulled from the
Context object’s dictionary of variables. This is how you’re
able to freely reference variable names in a template which
automatically correspond to what was passed into the current
Context.

What happens if I reference a variable name that is not in
the current context? - The value you get back is a special
value called UNDEFINED, or if the strict_undefined=True flag
is used a NameError is raised. UNDEFINED is just a simple global
variable with the class mako.runtime.Undefined. The
UNDEFINED object throws an error when you call str() on
it, which is what happens if you try to use it in an
expression.

UNDEFINED makes it hard for me to find what name is missing - An alternative
is to specify the option strict_undefined=True
to the Template or TemplateLookup. This will cause
any non-present variables to raise an immediate NameError
which includes the name of the variable in its message
when render() is called – UNDEFINED is not used.

New in version 0.3.6.

Why not just return None? Using UNDEFINED, or
raising a NameError is more
explicit and allows differentiation between a value of None
that was explicitly passed to the Context and a value that
wasn’t present at all.

Why raise an exception when you call str() on it ? Why not
just return a blank string? - Mako tries to stick to the
Python philosophy of “explicit is better than implicit”. In
this case, it’s decided that the template author should be made
to specifically handle a missing value rather than
experiencing what may be a silent failure. Since UNDEFINED
is a singleton object just like Python’s True or False,
you can use the is operator to check for it:

Another facet of the Context is that its dictionary of
variables is immutable. Whatever is set when
render() is called is what stays. Of course, since
its Python, you can hack around this and change values in the
context’s internal dictionary, but this will probably will not
work as well as you’d think. The reason for this is that Mako in
many cases creates copies of the Context object, which
get sent to various elements of the template and inheriting
templates used in an execution. So changing the value in your
local Context will not necessarily make that value
available in other parts of the template’s execution. Examples
of where Mako creates copies of the Context include
within top-level def calls from the main body of the template
(the context is used to propagate locally assigned variables
into the scope of defs; since in the template’s body they appear
as inlined functions, Mako tries to make them act that way), and
within an inheritance chain (each template in an inheritance
chain has a different notion of parent and next, which
are all stored in unique Context instances).

So what if I want to set values that are global to everyone
within a template request? - All you have to do is provide a
dictionary to your Context when the template first
runs, and everyone can just get/set variables from that. Lets
say its called attributes.

Running the template looks like:

output=template.render(attributes={})

Within a template, just reference the dictionary:

<%attributes['foo']='bar'%>'foo' attribute is: ${attributes['foo']}

Why can’t “attributes” be a built-in feature of the
Context? - This is an area where Mako is trying to make as
few decisions about your application as it possibly can.
Perhaps you don’t want your templates to use this technique of
assigning and sharing data, or perhaps you have a different
notion of the names and kinds of data structures that should
be passed around. Once again Mako would rather ask the user to
be explicit.

context[key] / context.get(key,default=None) -
dictionary-like accessors for the context. Normally, any
variable you use in your template is automatically pulled from
the context if it isn’t defined somewhere already. Use the
dictionary accessor and/or get method when you want a
variable that is already defined somewhere else, such as in
the local arguments sent to a %def call. If a key is not
present, like a dictionary it raises KeyError.

keys() - all the names defined within this context.

kwargs - this returns a copy of the context’s
dictionary of variables. This is useful when you want to
propagate the variables in the current context to a function
as keyword arguments, i.e.:

${next.body(**context.kwargs)}

write(text) - write some text to the current output
stream.

lookup - returns the TemplateLookup instance that is
used for all file-lookups within the current execution (even
though individual Template instances can conceivably have
different instances of a TemplateLookup, only the
TemplateLookup of the originally-called Template gets
used in a particular execution).

Regardless of the type of iterable you’re looping over, loop always tracks
the 0-indexed iteration count (available at loop.index), its parity
(through the loop.even and loop.odd bools), and loop.first, a bool
indicating whether the loop is on its first iteration. If your iterable
provides a __len__ method, loop also provides access to
a count of iterations remaining at loop.reverse_index and loop.last,
a bool indicating whether the loop is on its last iteration; accessing these
without __len__ will raise a TypeError.

Loop contexts can also be transparently nested, and the Mako runtime will do
the right thing and manage the scope for you. You can access the parent loop
context through loop.parent.

This allows you to reach all the way back up through the loop stack by
chaining parent attribute accesses, i.e. loop.parent.parent.... as
long as the stack depth isn’t exceeded. For example, you can use the parent
loop to make a checkered table:

Changed in version 0.7: The loop name is now reserved in Mako,
which means a template that refers to a variable named loop
won’t function correctly when used in Mako 0.7.

To ease the transition for such systems, the feature can be disabled across the board for
all templates, then re-enabled on a per-template basis for those templates which wish
to make use of the new system.

An individual template can make usage of the feature when enable_loop is set to
False by switching it back on within the <%page> tag:

<%pageenable_loop="True"/>%foriincollection:${i}${loop.index}% endfor

Using the above scheme, it’s safe to pass the name loop to the Template.render()
method as well as to freely make usage of a variable named loop within a template, provided
the <%page> tag doesn’t override it. New templates that want to use the loop context
can then set up <%pageenable_loop="True"/> to use the new feature without affecting
old templates.

A one-stop shop for all the names Mako defines. Most of these
names are instances of Namespace, which are described
in the next section, Namespaces. Also, most of
these names other than context, UNDEFINED, and loop are
also present within the Context itself. The names
context, loop and UNDEFINED themselves can’t be passed
to the context and can’t be substituted – see the section Reserved Names.

capture - a function that calls a given def and captures
its resulting content into a string, which is returned. Usage
is described in Filtering and Buffering.

UNDEFINED - a global singleton that is applied to all
otherwise uninitialized template variables that were not
located within the Context when rendering began,
unless the Template flag strict_undefined
is set to True. UNDEFINED is
an instance of Undefined, and raises an
exception when its __str__() method is called.

pageargs - this is a dictionary which is present in a
template which does not define any **kwargs section in its
<%page> tag. All keyword arguments sent to the body()
function of a template (when used via namespaces) go here by
default unless otherwise defined as a page argument. If this
makes no sense, it shouldn’t; read the section
The body() Method.

Mako has a few names that are considered to be “reserved” and can’t be used
as variable names.

Changed in version 0.7: Mako raises an error if these words are found passed to the template
as context arguments, whereas in previous versions they’d be silently
ignored or lead to other error messages.

Return the dictionary of top level keyword arguments associated
with this Context.

This dictionary only includes the top-level arguments passed to
Template.render(). It does not include names produced within
the template execution such as local variable names or special names
such as self, next, etc.

The purpose of this dictionary is primarily for the case that
a Template accepts arguments via its <%page> tag,
which are normally expected to be passed via Template.render(),
except the template is being called in an inheritance context,
using the body() method. Context.kwargs can then be
used to propagate these arguments to the inheriting template: