.. _runtime_toplevel: ============================ The Mako Runtime Environment ============================ This section describes a little bit about the objects and built-in functions that are available in templates. .. _context: Context ======= The :class:`.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 :ref:`reserved name ` ``context``. The :class:`.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 :meth:`~.Template.render` function and some built-in variables provided by Mako's runtime environment. The Buffer ---------- The buffer is stored within the :class:`.Context`, and writing to it is achieved by calling the :meth:`~.Context.write` method -- in a template this looks like ``context.write('some string')``. 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 :ref:`filtering_toplevel`, or if you want to programmatically send content to the output stream, such as within a ``<% %>`` block. .. sourcecode:: mako <% context.write("some programmatic text") %> The actual buffer may or may not be the original buffer sent to the :class:`.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. .. _context_vars: Context Variables ----------------- 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 :class:`.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 :class:`.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 :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 :class:`.Template` or :class:`.TemplateLookup`. This will cause any non-present variables to raise an immediate ``NameError`` which includes the name of the variable in its message when :meth:`~.Template.render` is called -- ``UNDEFINED`` is not used. .. versionadded:: 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 :class:`.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: .. sourcecode:: mako % if someval is UNDEFINED: someval is: no value % else: someval is: ${someval} % endif Another facet of the :class:`.Context` is that its dictionary of variables is **immutable**. Whatever is set when :meth:`~.Template.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 :class:`.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 :class:`.Context` will not necessarily make that value available in other parts of the template's execution. Examples of where Mako creates copies of the :class:`.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 :class:`.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 :class:`.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: .. sourcecode:: python output = template.render(attributes={}) Within a template, just reference the dictionary: .. sourcecode:: mako <% 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 Methods and Accessors ----------------------------- Significant members of :class:`.Context` include: * ``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.: .. sourcecode:: mako ${next.body(**context.kwargs)} * ``write(text)`` - write some text to the current output stream. * ``lookup`` - returns the :class:`.TemplateLookup` instance that is used for all file-lookups within the current execution (even though individual :class:`.Template` instances can conceivably have different instances of a :class:`.TemplateLookup`, only the :class:`.TemplateLookup` of the originally-called :class:`.Template` gets used in a particular execution). .. _loop_context: The Loop Context ================ Within ``% for`` blocks, the :ref:`reserved name` ``loop`` is available. ``loop`` tracks the progress of the ``for`` loop and makes it easy to use the iteration state to control template behavior: .. sourcecode:: mako .. versionadded:: 0.7 Iterations ---------- 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``. Cycling ------- Cycling is available regardless of whether the iterable you're using provides a ``__len__`` method. Prior to Mako 0.7, you might have generated a simple zebra striped list using ``enumerate``: .. sourcecode:: mako With ``loop.cycle``, you get the same results with cleaner code and less prep work: .. sourcecode:: mako Both approaches produce output like the following: .. sourcecode:: html Parent Loops ------------ 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: .. sourcecode:: mako % for consonant in 'pbj': % for vowel in 'iou': % endfor % endfor
${consonant + vowel}t
.. sourcecode:: html
pit pot put
bit bot but
jit jot jut
.. _migrating_loop: Migrating Legacy Templates that Use the Word "loop" --------------------------------------------------- .. versionchanged:: 0.7 The ``loop`` name is now :ref:`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. First, the ``enable_loop=False`` flag is passed to either the :class:`.TemplateLookup` or :class:`.Template` object in use: .. sourcecode:: python lookup = TemplateLookup(directories=['/docs'], enable_loop=False) or: .. sourcecode:: python template = Template("some template", enable_loop=False) 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: .. sourcecode:: mako <%page enable_loop="True"/> % for i in collection: ${i} ${loop.index} % endfor Using the above scheme, it's safe to pass the name ``loop`` to the :meth:`.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 ``<%page enable_loop="True"/>`` to use the new feature without affecting old templates. All the Built-in Names ====================== A one-stop shop for all the names Mako defines. Most of these names are instances of :class:`.Namespace`, which are described in the next section, :ref:`namespaces_toplevel`. Also, most of these names other than ``context``, ``UNDEFINED``, and ``loop`` are also present *within* the :class:`.Context` itself. The names ``context``, ``loop`` and ``UNDEFINED`` themselves can't be passed to the context and can't be substituted -- see the section :ref:`reserved_names`. * ``context`` - this is the :class:`.Context` object, introduced at :ref:`context`. * ``local`` - the namespace of the current template, described in :ref:`namespaces_builtin`. * ``self`` - the namespace of the topmost template in an inheritance chain (if any, otherwise the same as ``local``), mostly described in :ref:`inheritance_toplevel`. * ``parent`` - the namespace of the parent template in an inheritance chain (otherwise undefined); see :ref:`inheritance_toplevel`. * ``next`` - the namespace of the next template in an inheritance chain (otherwise undefined); see :ref:`inheritance_toplevel`. * ``caller`` - a "mini" namespace created when using the ``<%call>`` tag to define a "def call with content"; described in :ref:`defs_with_content`. * ``loop`` - this provides access to :class:`.LoopContext` objects when they are requested within ``% for`` loops, introduced at :ref:`loop_context`. * ``capture`` - a function that calls a given def and captures its resulting content into a string, which is returned. Usage is described in :ref:`filtering_toplevel`. * ``UNDEFINED`` - a global singleton that is applied to all otherwise uninitialized template variables that were not located within the :class:`.Context` when rendering began, unless the :class:`.Template` flag ``strict_undefined`` is set to ``True``. ``UNDEFINED`` is an instance of :class:`.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 :ref:`namespaces_body`. .. _reserved_names: Reserved Names -------------- Mako has a few names that are considered to be "reserved" and can't be used as variable names. .. versionchanged:: 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. * ``context`` - see :ref:`context`. * ``UNDEFINED`` - see :ref:`context_vars`. * ``loop`` - see :ref:`loop_context`. Note this can be disabled for legacy templates via the ``enable_loop=False`` argument; see :ref:`migrating_loop`. API Reference ============= .. autoclass:: mako.runtime.Context :show-inheritance: :members: .. autoclass:: mako.runtime.LoopContext :show-inheritance: :members: .. autoclass:: mako.runtime.Undefined :show-inheritance: