summaryrefslogtreecommitdiff
path: root/doc/build/runtime.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/build/runtime.rst')
-rw-r--r--doc/build/runtime.rst448
1 files changed, 448 insertions, 0 deletions
diff --git a/doc/build/runtime.rst b/doc/build/runtime.rst
new file mode 100644
index 0000000..17c9b99
--- /dev/null
+++ b/doc/build/runtime.rst
@@ -0,0 +1,448 @@
+.. _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 <reserved_names>`
+``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<reserved_names>` ``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
+
+ <ul>
+ % for a in ("one", "two", "three"):
+ <li>Item ${loop.index}: ${a}</li>
+ % endfor
+ </ul>
+
+.. 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
+
+ <ul>
+ % for i, item in enumerate(('spam', 'ham', 'eggs')):
+ <li class="${'odd' if i % 2 else 'even'}">${item}</li>
+ % endfor
+ </ul>
+
+With ``loop.cycle``, you get the same results with cleaner code and less prep work:
+
+.. sourcecode:: mako
+
+ <ul>
+ % for item in ('spam', 'ham', 'eggs'):
+ <li class="${loop.cycle('even', 'odd')}">${item}</li>
+ % endfor
+ </ul>
+
+Both approaches produce output like the following:
+
+.. sourcecode:: html
+
+ <ul>
+ <li class="even">spam</li>
+ <li class="odd">ham</li>
+ <li class="even">eggs</li>
+ </ul>
+
+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
+
+ <table>
+ % for consonant in 'pbj':
+ <tr>
+ % for vowel in 'iou':
+ <td class="${'black' if (loop.parent.even == loop.even) else 'red'}">
+ ${consonant + vowel}t
+ </td>
+ % endfor
+ </tr>
+ % endfor
+ </table>
+
+.. sourcecode:: html
+
+ <table>
+ <tr>
+ <td class="black">
+ pit
+ </td>
+ <td class="red">
+ pot
+ </td>
+ <td class="black">
+ put
+ </td>
+ </tr>
+ <tr>
+ <td class="red">
+ bit
+ </td>
+ <td class="black">
+ bot
+ </td>
+ <td class="red">
+ but
+ </td>
+ </tr>
+ <tr>
+ <td class="black">
+ jit
+ </td>
+ <td class="red">
+ jot
+ </td>
+ <td class="black">
+ jut
+ </td>
+ </tr>
+ </table>
+
+.. _migrating_loop:
+
+Migrating Legacy Templates that Use the Word "loop"
+---------------------------------------------------
+
+.. versionchanged:: 0.7
+ The ``loop`` name is now :ref:`reserved <reserved_names>` 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:
+