From a9da8487c7da377c9378bd5c997cc96ce7079efa Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 12 Nov 2010 17:27:11 -0500 Subject: looks good --- doc/build/caching.rst | 120 +++++++++++++++ doc/build/filtering.rst | 339 ++++++++++++++++++++++++++++++++++++++++ doc/build/inheritance.rst | 320 ++++++++++++++++++++++++++++++++++++++ doc/build/namespaces.rst | 382 ++++++++++++++++++++++++++++++++++++++++++++++ doc/build/runtime.rst | 237 ++++++++++++++++++++++++++++ doc/build/syntax.rst | 5 +- doc/build/unicode.rst | 330 +++++++++++++++++++++++++++++++++++++++ doc/build/usage.rst | 10 +- mako/lookup.py | 4 +- mako/runtime.py | 83 ++++++++-- 10 files changed, 1810 insertions(+), 20 deletions(-) diff --git a/doc/build/caching.rst b/doc/build/caching.rst index 8b13789..3ad35ff 100644 --- a/doc/build/caching.rst +++ b/doc/build/caching.rst @@ -1 +1,121 @@ +.. _caching_toplevel: +======== +Caching +======== + +Any template or component can be cached using the ``cache`` +argument to the ``<%page>`` or ``<%def>`` directives: + +.. sourcecode:: mako + + <%page cached="True"/> + + template text + +The above template, after being executed the first time, will +store its content within a cache that by default is scoped +within memory. Subsequent calls to the template's :meth:`~.Template.render` +method will return content directly from the cache. When the +:class:`.Template` object itself falls out of scope, its corresponding +cache is garbage collected along with the template. + +Caching requires that the ``beaker`` package be installed on the +system. + +The caching flag and all its options can be used with the +``<%def>`` tag. + +.. sourcecode:: mako + + <%def name="mycomp" cached="True" cache_timeout="30" cache_type="memory"> + other text + + +Cache arguments +================ + +The various cache arguments are cascaded from their default +values, to the arguments specified programmatically to the +:class:`.Template` or its originating :class:`.TemplateLookup`, then to those +defined in the ``<%page>`` tag of an individual template, and +finally to an individual ``<%def>`` tag within the template. This +means you can define, for example, a cache type of ``dbm`` on your +:class:`.TemplateLookup`, a cache timeout of 60 seconds in a particular +template's ``<%page>`` tag, and within one of that template's +``<%def>`` tags ``cache=True``, and that one particular def will +then cache its data using a ``dbm`` cache and a data timeout of 60 +seconds. + +The options available are: + +* ``cached="False|True"`` - turn caching on +* ``cache_timeout`` - number of seconds in which to invalidate the + cached data. after this timeout, the content is re-generated + on the next call. +* ``cache_type`` - type of caching. ``memory``, ``file``, ``dbm``, or + ``memcached``. +* ``cache_url`` - (only used for ``memcached`` but required) a single + IP address or a semi-colon separated list of IP address of + memcache servers to use. +* ``cache_dir`` - In the case of the ``file`` and ``dbm`` cache types, + this is the filesystem directory with which to store data + files. If this option is not present, the value of + ``module_directory`` is used (i.e. the directory where compiled + template modules are stored). If neither option is available + an exception is thrown. + + In the case of the ``memcached`` type, this attribute is required + and it's used to store the lock files. +* ``cache_key`` - the "key" used to uniquely identify this content + in the cache. the total namespace of keys within the cache is + local to the current template, and the default value of "key" + is the name of the def which is storing its data. It is an + evaluable tag, so you can put a Python expression to calculate + the value of the key on the fly. For example, heres a page + that caches any page which inherits from it, based on the + filename of the calling template: + +.. sourcecode:: mako + + <%page cached="True" cache_key="${self.filename}"/> + + ${next.body()} + + ## rest of template + +Accessing the Cache +=================== + +The :class:`.Template`, as well as any template-derived namespace, has +an accessor called ``cache`` which returns the ``Cache`` object +for that template. This object is a facade on top of the Beaker +internal cache object, and provides some very rudimental +capabilities, such as the ability to get and put arbitrary +values: + +.. sourcecode:: mako + + <% + local.cache.put("somekey", type="memory", "somevalue") + %> + +Above, the cache associated with the ``local`` namespace is +accessed and a key is placed within a memory cache. + +More commonly the ``cache`` object is used to invalidate cached +sections programmatically: + +.. sourcecode:: python + + template = lookup.get_template('/sometemplate.html') + + # invalidate the "body" of the template + template.cache.invalidate_body() + + # invalidate an individual def + template.cache.invalidate_def('somedef') + + # invalidate an arbitrary key + template.cache.invalidate('somekey') + diff --git a/doc/build/filtering.rst b/doc/build/filtering.rst index 8b13789..0921176 100644 --- a/doc/build/filtering.rst +++ b/doc/build/filtering.rst @@ -1 +1,340 @@ +.. _filtering_toplevel: +======================= +Filtering and Buffering +======================= + +Expression Filtering +===================== + +As described in the chapter :ref:`syntax_toplevel`, the "``|``" operator can be +applied to a "``${}``" expression to apply escape filters to the +output: + +.. sourcecode:: mako + + ${"this is some text" | u} + +The above expression applies URL escaping to the expression, and +produces ``this+is+some+text``. + +The built-in escape flags are: + +* ``u`` : URL escaping, provided by + ``urllib.quote_plus(string.encode('utf-8'))`` +* ``h`` : HTML escaping, provided by + ``markupsafe.escape(string)`` (new as of 0.3.4 - prior + versions use ``cgi.escape(string, True)``) +* ``x`` : XML escaping +* ``trim`` : whitespace trimming, provided by ``string.strip()`` +* ``entity`` : produces HTML entity references for applicable + strings, derived from ``htmlentitydefs`` +* ``unicode`` (``str`` on Python 3): produces a Python unicode + string (this function is applied by default). +* ``decode.`` : decode input into a Python + unicode with the specified encoding +* ``n`` : disable all default filtering; only filters specified + in the local expression tag will be applied. + +To apply more than one filter, separate them by a comma: + +.. sourcecode:: mako + + ${" some value " | h,trim} + +The above produces ``<tag>some value</tag>``, with +no leading or trailing whitespace. The HTML escaping function is +applied first, the "trim" function second. + +Naturally, you can make your own filters too. A filter is just a +Python function that accepts a single string argument, and +returns the filtered result. The expressions after the ``|`` +operator draw upon the local namespace of the template in which +they appear, meaning you can define escaping functions locally: + +.. sourcecode:: mako + + <%! + def myescape(text): + return "" + text + "" + %> + + Heres some tagged text: ${"text" | myescape} + +Or from any Python module: + +.. sourcecode:: mako + + <%! + import myfilters + %> + + Heres some tagged text: ${"text" | myfilters.tagfilter} + +A page can apply a default set of filters to all expression tags +using the ``expression_filter`` argument to the ``%page`` tag: + +.. sourcecode:: mako + + <%page expression_filter="h"/> + + Escaped text: ${"some html"} + +Result: + +.. sourcecode:: html + + Escaped text: <html>some html</html> + +.. _filtering_default_filters: + +The default_filters Argument +---------------------------- + +In addition to the ``expression_filter`` argument, the +``default_filters`` argument to both ``Template`` and +``TemplateLookup`` can specify filtering for all expression tags +at the programmatic level. This array-based argument, when given +its default argument of ``None``, will be internally set to +``["unicode"]`` (or ``["str"]`` on Python 3), except when +``disable_unicode=True`` is set in which case it defaults to +``["str"]``: + +.. sourcecode:: python + + t = TemplateLookup(directories=['/tmp'], default_filters=['unicode']) + +To replace the usual ``unicode``/``str`` function with a +specific encoding, the ``decode`` filter can be substituted: + +.. sourcecode:: python + + t = TemplateLookup(directories=['/tmp'], default_filters=['decode.utf8']) + +To disable ``default_filters`` entirely, set it to an empty +list: + +.. sourcecode:: python + + t = TemplateLookup(directories=['/tmp'], default_filters=[]) + +Any string name can be added to ``default_filters`` where it +will be added to all expressions as a filter. The filters are +applied from left to right, meaning the leftmost filter is +applied first. + +.. sourcecode:: python + + t = Template(templatetext, default_filters=['unicode', 'myfilter']) + +To ease the usage of ``default_filters`` with custom filters, +you can also add imports (or other code) to all templates using +the ``imports`` argument: + +.. sourcecode:: python + + t = TemplateLookup(directories=['/tmp'], + default_filters=['unicode', 'myfilter'], + imports=['from mypackage import myfilter']) + +The above will generate templates something like this: + +.. sourcecode:: python + + # .... + from mypackage import myfilter + + def render_body(context): + context.write(myfilter(unicode("some text"))) + +Turning off Filtering with the "n" filter +------------------------------------------ + +In all cases the special ``n`` filter, used locally within an +expression, will **disable** all filters declared in the +``<%page>`` tag as well ``default_filters``. Such as: + +.. sourcecode:: mako + + ${'myexpression' | n} + +Will render ``myexpression`` with no filtering of any kind, and + +.. sourcecode:: mako + + ${'myexpression' | n, trim} + +will render ``myexpression`` using the ``trim`` filter only. + +Filtering Defs +================= + +The ``%def`` tag has a filter argument which will apply the +given list of filter functions to the output of the ``%def``: + +.. sourcecode:: mako + + <%def name="foo()" filter="h, trim"> + this is bold + + +When the filter attribute is applied to a def as above, the def +is automatically **buffered** as well. This is described next. + +Buffering +========== + +One of Mako's central design goals is speed. To this end, all of +the textual content within a template and its various callables +is by default piped directly to the single buffer that is stored +within the ``Context`` object. While this normally is easy to +miss, it has certain side effects. The main one is that when you +call a def using the normal expression syntax, i.e. +``${somedef()}``, it may appear that the return value of the +function is the content it produced, which is then delivered to +your template just like any other expression substitution, +except that normally, this is not the case; the return value of +``${somedef()}`` is simply the empty string ``''``. By the time +you receive this empty string, the output of ``somedef()`` has +been sent to the underlying buffer. + +You may not want this effect, if for example you are doing +something like this: + +.. sourcecode:: mako + + ${" results " + somedef() + " more results "} + +If the ``somedef()`` function produced the content "``somedef's +results``", the above template would produce this output: + +.. sourcecode:: html + + somedef's results results more results + +This is because ``somedef()`` fully executes before the +expression returns the results of its concatenation; the +concatenation in turn receives just the empty string as its +middle expression. + +Mako provides two ways to work around this. One is by applying +buffering to the ``%def`` itself: + +.. sourcecode:: mako + + <%def name="somedef()" buffered="True"> + somedef's results + + +The above definition will generate code similar to this: + +.. sourcecode:: python + + def somedef(): + context.push_buffer() + try: + context.write("somedef's results") + finally: + buf = context.pop_buffer() + return buf.getvalue() + +So that the content of ``somedef()`` is sent to a second buffer, +which is then popped off the stack and its value returned. The +speed hit inherent in buffering the output of a def is also +apparent. + +Note that the ``filter`` argument on %def also causes the def to +be buffered. This is so that the final content of the %def can +be delivered to the escaping function in one batch, which +reduces method calls and also produces more deterministic +behavior for the filtering function itself, which can possibly +be useful for a filtering function that wishes to apply a +transformation to the text as a whole. + +The other way to buffer the output of a def or any Mako callable +is by using the built-in ``capture`` function. This function +performs an operation similar to the above buffering operation +except it is specified by the caller. + +.. sourcecode:: mako + + ${" results " + capture(somedef) + " more results "} + +Note that the first argument to the ``capture`` function is +**the function itself**, not the result of calling it. This is +because the ``capture`` function takes over the job of actually +calling the target function, after setting up a buffered +environment. To send arguments to the function, just send them +to ``capture`` instead: + +.. sourcecode:: mako + + ${capture(somedef, 17, 'hi', use_paging=True)} + +The above call is equivalent to the unbuffered call: + +.. sourcecode:: mako + + ${somedef(17, 'hi', use_paging=True)} + +Decorating +=========== + +This is a feature that's new as of version 0.2.5. Somewhat like +a filter for a %def but more flexible, the ``decorator`` +argument to ``%def`` allows the creation of a function that will +work in a similar manner to a Python decorator. The function can +control whether or not the function executes. The original +intent of this function is to allow the creation of custom cache +logic, but there may be other uses as well. + +``decorator`` is intended to be used with a regular Python +function, such as one defined in a library module. Here we'll +illustrate the python function defined in the template for +simplicities' sake: + +.. sourcecode:: mako + + <%! + def bar(fn): + def decorate(context, *args, **kw): + context.write("BAR") + fn(*args, **kw) + context.write("BAR") + return '' + return decorate + %> + + <%def name="foo()" decorator="bar"> + this is foo + + + ${foo()} + +The above template will return, with more whitespace than this, +``"BAR this is foo BAR"``. The function is the render callable +itself (or possibly a wrapper around it), and by default will +write to the context. To capture its output, use the ``capture`` +callable in the ``mako.runtime`` module (available in templates +as just ``runtime``): + +.. sourcecode:: mako + + <%! + def bar(fn): + def decorate(context, *args, **kw): + return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR" + return decorate + %> + + <%def name="foo()" decorator="bar"> + this is foo + + + ${foo()} + +The decorator can be used with top-level defs as well as nested +defs. Note that when calling a top-level def from the +``Template`` api, i.e. ``template.get_def('somedef').render()``, +the decorator has to write the output to the ``context``, i.e. +as in the first example. The return value gets discarded. diff --git a/doc/build/inheritance.rst b/doc/build/inheritance.rst index 8b13789..c876864 100644 --- a/doc/build/inheritance.rst +++ b/doc/build/inheritance.rst @@ -1 +1,321 @@ +.. _inheritance_toplevel: +=========== +Inheritance +=========== + +Using template inheritance, two or more templates can organize +themselves into an **inheritance chain**, where content and +functions from all involved templates can be intermixed. The +general paradigm of template inheritance is this: if a template +``A`` inherits from template ``B``, then template ``A`` agrees +to send the executional control to template ``B`` at runtime +(``A`` is called the **inheriting** template). Template ``B``, +the **inherited** template, then makes decisions as to what +resources from ``A`` shall be executed. + +In practice, it looks like this. Heres a hypothetical inheriting +template, ``index.html``: + +.. sourcecode:: mako + + ## index.html + <%inherit file="base.html"/> + + <%def name="header()"> + this is some header content + + + this is the body content. + +And ``base.html``, the inherited template: + +.. sourcecode:: mako + + ## base.html + + +
+ ${self.header()} +
+ + ${self.body()} + + + + + + <%def name="footer()"> + this is the footer + + +Here is a breakdown of the execution: + +* When ``index.html`` is rendered, control immediately passes to + ``base.html``. +* ``base.html`` then renders the top part of an HTML document, + then calls the method ``header()`` off of a built in namespace + called ``self`` (this namespace was first introduced in the + Namespaces chapter in + :ref:`namespace_self`). Since + ``index.html`` is the topmost template and also defines a def + called ``header()``, its this ``header()`` def that gets + executed. +* Control comes back to ``base.html``. Some more HTML is + rendered. +* ``base.html`` executes ``self.body()``. The ``body()`` + function on all template-based namespaces refers to the main + body of the template, therefore the main body of + ``index.html`` is rendered. +* Control comes back to ``base.html``. More HTML is rendered, + then the ``self.footer()`` expression is invoked. +* The ``footer`` def is only defined in ``base.html``, so being + the topmost definition of ``footer``, its the one that + executes. If ``index.html`` also specified ``footer``, then + its version would **override** that of the base. +* ``base.html`` finishes up rendering its HTML and the template + is complete, producing: + +.. sourcecode:: html + + + +
+ this is some header content +
+ + this is the body content. + + + + + +...and that is template inheritance in a nutshell. The main idea +is that the methods that you call upon ``self`` always +correspond to the topmost definition of that method. Very much +the way ``self`` works in a Python class, even though Mako is +not actually using Python class inheritance to implement this +functionality. (Mako doesn't take the "inheritance" metaphor too +seriously; while useful to setup some commonly recognized +semantics, a textual template is not very much like an +object-oriented class construct in practice). + +Using the "next" namespace to produce content wrapping +======================================================= + +Sometimes you have an inheritance chain that spans more than two +templates. Or maybe you don't, but youd like to build your +system such that extra inherited templates can be inserted in +the middle of a chain where they would be smoothly integrated. +If each template wants to define its layout just within its main +body, you can't just call ``self.body()`` to get at the +inheriting template's body, since that is only the topmost body. +To get at the body of the *next* template, you call upon the +namespace ``next``, which is the namespace of the template +**immediately following** the current template. + +Lets change the line in ``base.html`` which calls upon +``self.body()`` to instead call upon ``next.body()``: + +.. sourcecode:: mako + + ## base.html + + +
+ ${self.header()} +
+ + ${next.body()} + + + + + + <%def name="footer()"> + this is the footer + + +Lets also add an intermediate template called ``layout.html``, +which inherits from ``base.html``: + +.. sourcecode:: mako + + ## layout.html + <%inherit file="base.html"/> + +
+ ${next.body()} +
+ + <%def name="toolbar()"> +
  • selection 1
  • +
  • selection 2
  • +
  • selection 3
  • + + +And finally change ``index.html`` to inherit from +``layout.html`` instead: + +.. sourcecode:: mako + + ## index.html + <%inherit file="layout.html"/> + + ## .. rest of template + +In this setup, each call to ``next.body()`` will render the body +of the next template in the inheritance chain (which can be +written as ``base.html -> layout.html -> index.html``). Control +is still first passed to the bottommost template ``base.html``, +and ``self`` still references the topmost definition of any +particular def. + +The output we get would be: + +.. sourcecode:: html + + + +
    + this is some header content +
    + + + +
    + this is the body content. +
    + + + + + +So above, we have the ````, ```` and +``header``/``footer`` layout of ``base.html``, we have the +``