diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-11-12 17:27:11 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-11-12 17:27:11 -0500 |
commit | a9da8487c7da377c9378bd5c997cc96ce7079efa (patch) | |
tree | 8cba4a1248ff10feff9e26caf40ca9a10f4ed5c0 | |
parent | 4ce916525fd94116e696f4d8cde19333e9ed946c (diff) | |
download | mako-a9da8487c7da377c9378bd5c997cc96ce7079efa.tar.gz |
looks good
-rw-r--r-- | doc/build/caching.rst | 120 | ||||
-rw-r--r-- | doc/build/filtering.rst | 339 | ||||
-rw-r--r-- | doc/build/inheritance.rst | 320 | ||||
-rw-r--r-- | doc/build/namespaces.rst | 382 | ||||
-rw-r--r-- | doc/build/runtime.rst | 237 | ||||
-rw-r--r-- | doc/build/syntax.rst | 5 | ||||
-rw-r--r-- | doc/build/unicode.rst | 330 | ||||
-rw-r--r-- | doc/build/usage.rst | 10 | ||||
-rw-r--r-- | mako/lookup.py | 4 | ||||
-rw-r--r-- | 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 + </%def> + +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.<some encoding>`` : 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 + + ${" <tag>some value</tag> " | 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 "<TAG>" + text + "</TAG>" + %> + + 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: ${"<html>some html</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"> + <b>this is bold</b> + </%def> + +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 + </%def> + +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 + </%def> + + ${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 + </%def> + + ${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 + </%def> + + this is the body content. + +And ``base.html``, the inherited template: + +.. sourcecode:: mako + + ## base.html + <html> + <body> + <div class="header"> + ${self.header()} + </div> + + ${self.body()} + + <div class="footer"> + ${self.footer()} + </div> + </body> + </html> + + <%def name="footer()"> + this is the footer + </%def> + +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 + + <html> + <body> + <div class="header"> + this is some header content + </div> + + this is the body content. + + <div class="footer"> + this is the footer + </div> + </body> + </html> + +...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 + <html> + <body> + <div class="header"> + ${self.header()} + </div> + + ${next.body()} + + <div class="footer"> + ${self.footer()} + </div> + </body> + </html> + + <%def name="footer()"> + this is the footer + </%def> + +Lets also add an intermediate template called ``layout.html``, +which inherits from ``base.html``: + +.. sourcecode:: mako + + ## layout.html + <%inherit file="base.html"/> + <ul> + ${self.toolbar()} + </ul> + <div class="mainlayout"> + ${next.body()} + </div> + + <%def name="toolbar()"> + <li>selection 1</li> + <li>selection 2</li> + <li>selection 3</li> + </%def> + +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 + + <html> + <body> + <div class="header"> + this is some header content + </div> + + <ul> + <li>selection 1</li> + <li>selection 2</li> + <li>selection 3</li> + </ul> + + <div class="mainlayout"> + this is the body content. + </div> + + <div class="footer"> + this is the footer + </div> + </body> + </html> + +So above, we have the ``<html>``, ``<body>`` and +``header``/``footer`` layout of ``base.html``, we have the +``<ul>`` and ``mainlayout`` section of ``layout.html``, and the +main body of ``index.html`` as well as its overridden ``header`` +def. The ``layout.html`` template is inserted into the middle of +the chain without ``base.html`` having to change anything. +Without the ``next`` namespace, only the main body of +``index.html`` could be used; there would be no way to call +``layout.html``'s body content. + +Using the "parent" namespace to augment defs +============================================= + +Lets now look at the other inheritance-specific namespace, the +opposite of ``next`` called ``parent``. ``parent`` is the +namespace of the template **immediately preceding** the current +template. What is most useful about this namespace is the +methods within it which can be accessed within overridden +versions of those methods. This is not as hard as it sounds and +is very much like using the ``super`` keyword in Python. Lets +modify ``index.html`` to augment the list of selections provided +by the ``toolbar`` function in ``layout.html``: + +.. sourcecode:: mako + + ## index.html + <%inherit file="layout.html"/> + + <%def name="header()"> + this is some header content + </%def> + + <%def name="toolbar()"> + ## call the parent's toolbar first + ${parent.toolbar()} + <li>selection 4</li> + <li>selection 5</li> + </%def> + + this is the body content. + +Above, we implemented a ``toolbar()`` function, which is meant +to override the definition of ``toolbar`` within the inherited +template ``layout.html``. However, since we want the content +from that of ``layout.html`` as well, we call it via the +``parent`` namespace whenever we want it's content, in this case +before we add our own selections. So the output for the whole +thing is now: + +.. sourcecode:: html + + <html> + <body> + <div class="header"> + this is some header content + </div> + + <ul> + <li>selection 1</li> + <li>selection 2</li> + <li>selection 3</li> + <li>selection 4</li> + <li>selection 5</li> + </ul> + + <div class="mainlayout"> + this is the body content. + </div> + + <div class="footer"> + this is the footer + </div> + </body> + </html> + +and you're now a template inheritance ninja ! + +Inheritable Attributes +====================== + +The ``attr`` accessor of the :class:`.Namespace` object allows access +to module level variables declared in a template. By accessing +``self.attr``, you can access regular attributes from the +inheritance chain as declared in ``<%! %>`` sections. Such as: + +.. sourcecode:: mako + + <%! + class_ = "grey" + %> + + <div class="${self.attr.class_}"> + ${self.body()} + </div> + +If a an inheriting template overrides ``class_`` to be +``white``, as in: + +.. sourcecode:: mako + + <%! + class_ = "white" + %> + <%inherit file="parent.html"/> + + This is the body + +You'll get output like: + +.. sourcecode:: html + + <div class="white"> + This is the body + </div> diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst index 8b13789..5939020 100644 --- a/doc/build/namespaces.rst +++ b/doc/build/namespaces.rst @@ -1 +1,383 @@ +.. _namespaces_toplevel: + +========== +Namespaces +========== + +Namespaces are used to organize groups of components into +categories, and also to "import" components from other files. + +If the file ``components.html`` defines these two components: + +.. sourcecode:: mako + + ## components.html + <%def name="comp1()"> + this is comp1 + </%def> + + <%def name="comp2(x)"> + this is comp2, x is ${x} + </%def> + +You can make another file, for example ``index.html``, that +pulls those two components into a namespace called ``comp``: + +.. sourcecode:: mako + + ## index.html + <%namespace name="comp" file="components.html"/> + + Heres comp1: ${comp.comp1()} + Heres comp2: ${comp.comp2(x=5)} + +The ``comp`` variable above is an instance of +:class:`.Namespace`, a **proxy object** which delivers +method calls to the underlying template callable using the +current context. + +``<%namespace>`` also provides an ``import`` attribute which can +be used to pull the names into the local namespace, removing the +need to call it via the ".". When ``import`` is used, the +``name`` attribute is optional. + +.. sourcecode:: mako + + <%namespace file="components.html" import="comp1, comp2"/> + + Heres comp1: ${comp1()} + Heres comp2: ${comp2(x=5)} + +``import`` also supports the "*" operator: + +.. sourcecode:: mako + + <%namespace file="components.html" import="*"/> + + Heres comp1: ${comp1()} + Heres comp2: ${comp2(x=5)} + +The names imported by the ``import`` attribute take precedence +over any names that exist within the current context. + +.. note:: in current versions of Mako, usage of ``import='*'`` is + known to decrease performance of the template. This will be + fixed in a future release. + +The ``file`` argument allows expressions - if looking for +context variables, the ``context`` must be named explicitly: + +.. sourcecode:: mako + + <%namespace name="dyn" file="${context['namespace_name']}"/> + +Ways to Call Namespaces +======================== + +There are essentially four ways to call a function from a +namespace. + +The "expression" format, as described previously. Namespaces are +just Python objects with functions on them, and can be used in +expressions like any other function: + +.. sourcecode:: mako + + ${mynamespace.somefunction('some arg1', 'some arg2', arg3='some arg3', arg4='some arg4')} + +Synonymous with the "expression" format is the "custom tag" +format, when a "closed" tag is used. This format, introduced in +Mako 0.2.3, allows the usage of a "custom" Mako tag, with the +function arguments passed in using named attributes: + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="some arg1" arg2="some arg2" arg3="some arg3" arg4="some arg4"/> + +When using tags, the values of the arguments are taken as +literal strings by default. To embed Python expressions as +arguments, use the embedded expression format: + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="${someobject.format()}" arg2="${somedef(5, 12)}"/> + +The "custom tag" format is intended mainly for namespace +functions which recognize body content, which in Mako is known +as a "def with embedded content": + +.. sourcecode:: mako + + <%mynamespace:somefunction arg1="some argument" args="x, y"> + Some record: ${x}, ${y} + </%mynamespace:somefunction> + +The "classic" way to call defs with embedded content is the ``<%call>`` tag: + +.. sourcecode:: mako + + <%call expr="mynamespace.somefunction(arg1='some argument')" args="x, y"> + Some record: ${x}, ${y} + </%call> + +For information on how to construct defs that embed content from +the caller, see :ref:`defs_with_content`. + +.. _namespaces_python_modules: + +Namespaces from Regular Python Modules +======================================== + +Namespaces can also import regular Python functions from +modules. These callables need to take at least one argument, +``context``, an instance of :class:`.Context`. A module file +``some/module.py`` might contain the callable: + +.. sourcecode:: python + + def my_tag(context): + context.write("hello world") + return '' + +A template can use this module via: + +.. sourcecode:: mako + + <%namespace name="hw" module="some.module"/> + + ${hw.my_tag()} + +Note that the ``context`` argument is not needed in the call; +the :class:`.Namespace` tag creates a locally-scoped callable which +takes care of it. The ``return ''`` is so that the def does not +dump a ``None`` into the output stream - the return value of any +def is rendered after the def completes, in addition to whatever +was passed to :meth:`.Context.write` within its body. + +If your def is to be called in an "embedded content" context, +that is as described in :ref:`defs_with_content`, you should use +the :func:`.supports_caller` decorator, which will ensure that Mako +will ensure the correct "caller" variable is available when your +def is called, supporting embedded content: + +.. sourcecode:: python + + from mako.runtime import supports_caller + + @supports_caller + def my_tag(context): + context.write("<div>") + context['caller'].body() + context.write("</div>") + return '' + +Capturing of output is available as well, using the +outside-of-templates version of the :func:`.capture` function, +which accepts the "context" as its first argument: + +.. sourcecode:: python + + from mako.runtime import supports_caller, capture + + @supports_caller + def my_tag(context): + return "<div>%s</div>" % \ + capture(context, context['caller'].body, x="foo", y="bar") + +Declaring defs in namespaces +============================= + +The ``<%namespace>`` tag supports the definition of ``<%defs>`` +directly inside the tag. These defs become part of the namespace +like any other function, and will override the definitions +pulled in from a remote template or module: + +.. sourcecode:: mako + + ## define a namespace + <%namespace name="stuff"> + <%def name="comp1()"> + comp1 + </%def> + </%namespace> + + ## then call it + ${stuff.comp1()} + +.. _namespaces_body: + +The "body()" method +===================== + +Every namespace that is generated from a template contains a +method called ``body()``. This method corresponds to the main +body of the template, and plays its most important roles when +using inheritance relationships as well as +def-calls-with-content. + +Since the ``body()`` method is available from a namespace just +like all the other defs defined in a template, what happens if +you send arguments to it ? By default, the ``body()`` method +accepts no positional arguments, and for usefulness in +inheritance scenarios will by default dump all keyword arguments +into a dictionary called ``pageargs``. But if you actually want +to get at the keyword arguments, Mako recommends you define your +own argument signature explicitly. You do this via using the +``<%page>`` tag: + +.. sourcecode:: mako + + <%page args="x, y, someval=8, scope='foo', **kwargs"/> + +A template which defines the above signature requires that the +variables ``x`` and ``y`` are defined, defines default values +for ``someval`` and ``scope``, and sets up ``**kwargs`` to +receive all other keyword arguments. If ``**kwargs`` or similar +is not present, the argument ``**pageargs`` gets tacked on by +Mako. When the template is called as a top-level template (i.e. +via :meth:`~.Template.render`) or via the ``<%include>`` tag, the +values for these arguments will be pulled from the ``Context``. +In all other cases, i.e. via calling the ``body()`` method, the +arguments are taken as ordinary arguments from the method call. +So above, the body might be called as: + +.. sourcecode:: mako + + ${self.body(5, y=10, someval=15, delta=7)} + +The :class:`.Context` object also supplies a :attr:`~.Context.kwargs` accessor, for +cases when youd like to pass along whatever is in the context to +a ``body()`` callable: + +.. sourcecode:: mako + + ${next.body(**context.kwargs)} + +The usefulness of calls like the above become more apparent when +one works with inheriting templates. For more information on +this, as well as the meanings of the names ``self`` and +``next``, see :ref:`inheritance_toplevel`. + +.. _namespaces_builtin: + +Built-in Namespaces +==================== + +The namespace is so great that Mako gives your template one (or +two) for free. The names of these namespaces are ``local`` and +``self``. Other built-in namespaces include ``parent`` and +``next``, which are optional and are described in +:ref:`inheritance_toplevel`. + +.. _namespace_local: + +local +----- + +The ``local`` namespace is basically the namespace for the +currently executing template. This means that all of the top +level defs defined in your template, as well as your template's +``body()`` function, are also available off of the ``local`` +namespace. + +The ``local`` namespace is also where properties like ``uri``, +``filename``, and ``module`` and the ``get_namespace`` method +can be particularly useful. + +.. _namespace_self: + +self +----- + +The ``self`` namespace, in the case of a template that does not +use inheritance, is synonomous with ``local``. If inheritance is +used, then ``self`` references the topmost template in the +inheritance chain, where it is most useful for providing the +ultimate form of various "method" calls which may have been +overridden at various points in an inheritance chain. See +:ref:`inheritance_toplevel`. + +Inheritable Namespaces +======================== + +The ``<%namespace>`` tag includes an optional attribute +``inheritable="True"``, which will cause the namespace to be +attached to the ``self`` namespace. Since ``self`` is globally +available throughout an inheritance chain (described in the next +section), all the templates in an inheritance chain can get at +the namespace imported in a super-template via ``self``. + +.. sourcecode:: mako + + ## base.html + <%namespace name="foo" file="foo.html" inheritable="True"/> + + ${next.body()} + + ## somefile.html + <%inherit file="base.html"/> + + ${self.foo.bar()} + +This allows a super-template to load a whole bunch of namespaces +that its inheriting templates can get to, without them having to +explicitly load those namespaces themselves. + +The ``import="*"`` part of the ``<%namespace>`` tag doesn't yet +interact with the ``inheritable`` flag, so currently you have to +use the explicit namespace name off of ``self``, followed by the +desired function name. But more on this in a future release. + +API Reference +============== + +.. autoclass:: mako.runtime.Namespace + :show-inheritance: + :members: + + .. py:attribute:: attr + + allows access module level attributes by name. This + accessor allows templates to supply "scalar" attributes which + are particularly handy in inheritance relationships. See the + example in :ref:`inheritance_toplevel`. + + .. py:attribute:: module + + the Python module referenced by this Namespace. + If the namespace references a :class:`.Template`, then this module + is the equivalent of ``template.module``, i.e. the generated + module for the template. + + .. py:attribute:: filename + + the path of the filesystem file used for this + Namespace's module or template. If this is a pure module-based + Namespace, this evaluates to ``module.__file__``. If a + template-based namespace, it evaluates to the original + template file location. + + .. py:attribute:: template + + the :class:`.Template` object referenced by this + :class:`.Namespace`, if any. + + .. py:attribute:: uri + + the uri for this Namespace's template (i.e. whatever + was sent to :meth:`.TemplateLookup.get_template()`). This is the equivalent + of :attr:`Template.uri`. + + .. py:attribute:: context + + The :class:`.Context` object for this namespace. + Namespaces are often created with copies of contexts that + contain slightly different data, particularly in inheritance + scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one + can traverse an entire chain of templates that inherit from + one-another. + +.. autofunction:: mako.runtime.supports_caller + +.. autofunction:: mako.runtime.capture diff --git a/doc/build/runtime.rst b/doc/build/runtime.rst index 8b13789..8db081a 100644 --- a/doc/build/runtime.rst +++ b/doc/build/runtime.rst @@ -1 +1,238 @@ +.. _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 +======= + +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. This 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 :meth:`.Context.write`. 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 +:meth:`.Context.write` and content will always go to the topmost +buffer. + +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 ``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 + introduced in version 0.3.6 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. +* **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, its 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 off 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 isnt 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). + +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 :class:`.Context` and ``UNDEFINED`` are +also present *within* the :class:`.Context` itself. + +* ``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`. +* ``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`. + +API Reference +============== + +.. autoclass:: mako.runtime.Context + :show-inheritance: + :members: + +.. autoclass:: mako.runtime.Undefined + :show-inheritance: + + diff --git a/doc/build/syntax.rst b/doc/build/syntax.rst index 4207570..1e5ecfb 100644 --- a/doc/build/syntax.rst +++ b/doc/build/syntax.rst @@ -193,8 +193,9 @@ pure-Python functions you might want to declare: %> Any number of ``<%! %>`` blocks can be declared anywhere in a -template; they will be rendered in the resulting module in the -order that they appear. +template; they will be rendered in the resulting module +in a single contiguous block above all render callables, +in the order in which they appear in the source template. Tags ==== diff --git a/doc/build/unicode.rst b/doc/build/unicode.rst index 1615e7c..771ca4b 100644 --- a/doc/build/unicode.rst +++ b/doc/build/unicode.rst @@ -3,3 +3,333 @@ =================== The Unicode Chapter =================== + +The Python language supports two ways of representing what we +know as "strings", i.e. series of characters. In Python 2, the +two types are ``string`` and ``unicode``, and in Python 3 they are +``bytes`` and ``string``. A key aspect of the Python 2 ``string`` and +Python 3 ``bytes`` types are that they contain no information +regarding what **encoding** the data is stored in. For this +reason they were commonly referred to as **byte strings** on +Python 2, and Python 3 makes this name more explicit. The +origins of this come from Python's background of being developed +before the Unicode standard was even available, back when +strings were C-style strings and were just that, a series of +bytes. Strings that had only values below 128 just happened to +be **ascii** strings and were printable on the console, whereas +strings with values above 128 would produce all kinds of +graphical characters and bells. + +Contrast the "bytestring" types with the "unicode/string" type. +Objects of this type are created whenever you say something like +``u"hello world"`` (or in Python 3, just ``"hello world"``). In this +case, Python represents each character in the string internally +using multiple bytes per character (something similar to +UTF-16). Whats important is that when using the +``unicode``/``string`` type to store strings, Python knows the +data's encoding; its in its own internal format. Whereas when +using the ``string``/``bytes`` type, it does not. + +When Python 2 attempts to treat a byte-string as a string, which +means its attempting to compare/parse its characters, to coerce +it into another encoding, or to decode it to a unicode object, +it has to guess what the encoding is. In this case, it will +pretty much always guess the encoding as ``ascii``...and if the +bytestring contains bytes above value 128, you'll get an error. +Python 3 eliminates much of this confusion by just raising an +error unconditionally if a bytestring is used in a +character-aware context. + +There is one operation that Python *can* do with a non-ascii +bytestring, and its a great source of confusion: it can dump the +bytestring straight out to a stream or a file, with nary a care +what the encoding is. To Python, this is pretty much like +dumping any other kind of binary data (like an image) to a +stream somewhere. In Python 2, it is common to see programs that +embed all kinds of international characters and encodings into +plain byte-strings (i.e. using ``"hello world"`` style literals) +can fly right through their run, sending reams of strings out to +whereever they are going, and the programmer, seeing the same +output as was expressed in the input, is now under the illusion +that his or her program is Unicode-compliant. In fact, their +program has no unicode awareness whatsoever, and similarly has +no ability to interact with libraries that *are* unicode aware. +Python 3 makes this much less likely by defaulting to unicode as +the storage format for strings. + +The "pass through encoded data" scheme is what template +languages like Cheetah and earlier versions of Myghty do by +default. Mako as of version 0.2 also supports this mode of +operation when using Python 2, using the "disable_unicode=True" +flag. However, when using Mako in its default mode of +unicode-aware, it requires explicitness when dealing with +non-ascii encodings. Additionally, if you ever need to handle +unicode strings and other kinds of encoding conversions more +intelligently, the usage of raw bytestrings quickly becomes a +nightmare, since you are sending the Python interpreter +collections of bytes for which it can make no intelligent +decisions with regards to encoding. In Python 3 Mako only allows +usage of native, unicode strings. + +In normal Mako operation, all parsed template constructs and +output streams are handled internally as Python ``unicode`` +objects. Its only at the point of :meth:`~.Template.render` that this unicode +stream may be rendered into whatever the desired output encoding +is. The implication here is that the template developer must +ensure that the encoding of all non-ascii templates is explicit +(still required in Python 3), that all non-ascii-encoded +expressions are in one way or another converted to unicode (not +much of a burden in Python 3), and that the output stream of the +template is handled as a unicode stream being encoded to some +encoding (still required in Python 3). + +Specifying the Encoding of a Template File +=========================================== + +This is the most basic encoding-related setting, and it is +equivalent to Python's "magic encoding comment", as described in +`pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_. Any +template that contains non-ascii characters requires that this +comment be present so that Mako can decode to unicode (and also +make usage of Python's AST parsing services). Mako's lexer will +use this encoding in order to convert the template source into a +``unicode`` object before continuing its parsing: + +.. sourcecode:: mako + + ## -*- coding: utf-8 -*- + + Alors vous imaginez ma surprise, au lever du jour, quand + une drôle de petite voix m’a réveillé. Elle disait: + « S’il vous plaît… dessine-moi un mouton! » + +For the picky, the regular expression used is derived from that +of the abovementioned pep: + +.. sourcecode:: python + + #.*coding[:=]\s*([-\w.]+).*\n + +The lexer will convert to unicode in all cases, so that if any +characters exist in the template that are outside of the +specified encoding (or the default of ``ascii``), the error will +be immediate. + +As an alternative, the template encoding can be specified +programmatically to either :class:`.Template` or :class:`.TemplateLookup` via +the ``input_encoding`` parameter: + +.. sourcecode:: python + + t = TemplateLookup(directories=['./'], input_encoding='utf-8') + +The above will assume all located templates specify ``utf-8`` +encoding, unless the template itself contains its own magic +encoding comment, which takes precedence. + +Handling Expressions +===================== + +The next area that encoding comes into play is in expression +constructs. By default, Mako's treatment of an expression like +this: + +.. sourcecode:: mako + + ${"hello world"} + +looks something like this: + +.. sourcecode:: python + + context.write(unicode("hello world")) + +In Python 3, its just: + +.. sourcecode:: python + + context.write(str("hello world")) + +That is, **the output of all expressions is run through the +``unicode`` builtin**. This is the default setting, and can be +modified to expect various encodings. The ``unicode`` step serves +both the purpose of rendering non-string expressions into +strings (such as integers or objects which contain ``__str()__`` +methods), and to ensure that the final output stream is +constructed as a unicode object. The main implication of this is +that **any raw bytestrings that contain an encoding other than +ascii must first be decoded to a Python unicode object**. It +means you can't say this in Python 2: + +.. sourcecode:: mako + + ${"voix m’a réveillé."} ## error in Python 2! + +You must instead say this: + +.. sourcecode:: mako + + ${u"voix m’a réveillé."} ## OK ! + +Similarly, if you are reading data from a file that is streaming +bytes, or returning data from some object that is returning a +Python bytestring containing a non-ascii encoding, you have to +explcitly decode to unicode first, such as: + +.. sourcecode:: mako + + ${call_my_object().decode('utf-8')} + +Note that filehandles acquired by ``open()`` in Python 3 default +to returning "text", that is the decoding is done for you. See +Python 3's documentation for the ``open()`` builtin for details on +this. + +If you want a certain encoding applied to *all* expressions, +override the ``unicode`` builtin with the ``decode`` builtin at the +:class:`.Template` or :class:`.TemplateLookup` level: + +.. sourcecode:: python + + t = Template(templatetext, default_filters=['decode.utf8']) + +Note that the built-in ``decode`` object is slower than the +``unicode`` function, since unlike ``unicode`` its not a Python +builtin, and it also checks the type of the incoming data to +determine if string conversion is needed first. + +The ``default_filters`` argument can be used to entirely customize +the filtering process of expressions. This argument is described +in :ref:`filtering_default_filters`. + +Defining Output Encoding +========================= + +Now that we have a template which produces a pure unicode output +stream, all the hard work is done. We can take the output and do +anything with it. + +As stated in the "Usage" chapter, both :class:`.Template` and +:class:`.TemplateLookup` accept ``output_encoding`` and ``encoding_errors`` +parameters which can be used to encode the output in any Python +supported codec: + +.. sourcecode:: python + + from mako.template import Template + from mako.lookup import TemplateLookup + + mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace') + + mytemplate = mylookup.get_template("foo.txt") + print mytemplate.render() + +:meth:`~.Template.render` will return a ``bytes`` object in Python 3 if an output +encoding is specified. By default it performs no encoding and +returns a native string. + +:meth:`~.Template.render_unicode` will return the template output as a Python +``unicode`` object (or ``string`` in Python 3): + +.. sourcecode:: python + + print mytemplate.render_unicode() + +The above method disgards the output encoding keyword argument; +you can encode yourself by saying: + +.. sourcecode:: python + + print mytemplate.render_unicode().encode('utf-8', 'replace') + +Buffer Selection +----------------- + +Mako does play some games with the style of buffering used +internally, to maximize performance. Since the buffer is by far +the most heavily used object in a render operation, its +important! + +When calling :meth:`~.Template.render` on a template that does not specify any +output encoding (i.e. its ``ascii``), Python's ``cStringIO`` module, +which cannot handle encoding of non-ascii ``unicode`` objects +(even though it can send raw bytestrings through), is used for +buffering. Otherwise, a custom Mako class called +``FastEncodingBuffer`` is used, which essentially is a super +dumbed-down version of ``StringIO`` that gathers all strings into +a list and uses ``u''.join(elements)`` to produce the final output +- its markedly faster than ``StringIO``. + +Saying to Heck with it: Disabling the usage of Unicode entirely +================================================================ + +Some segements of Mako's userbase choose to make no usage of +Unicode whatsoever, and instead would prefer the "passthru" +approach; all string expressions in their templates return +encoded bytestrings, and they would like these strings to pass +right through. The only advantage to this approach is that +templates need not use ``u""`` for literal strings; there's an +arguable speed improvement as well since raw bytestrings +generally perform slightly faster than unicode objects in +Python. For these users, assuming they're sticking with Python +2, they can hit the ``disable_unicode=True`` flag as so: + +.. sourcecode:: python + + # -*- encoding:utf-8 -*- + from mako.template import Template + + t = Template("drôle de petite voix m’a réveillé.", disable_unicode=True, input_encoding='utf-8') + print t.code + +The ``disable_unicode`` mode is strictly a Python 2 thing. It is +not supported at all in Python 3. + +The generated module source code will contain elements like +these: + +.. sourcecode:: python + + # -*- encoding:utf-8 -*- + # ...more generated code ... + + def render_body(context,**pageargs): + context.caller_stack.push_frame() + try: + __M_locals = dict(pageargs=pageargs) + # SOURCE LINE 1 + context.write('dr\xc3\xb4le de petite voix m\xe2\x80\x99a r\xc3\xa9veill\xc3\xa9.') + return '' + finally: + context.caller_stack.pop_frame() + +Where above that the string literal used within :meth:`.Context.write` +is a regular bytestring. + +When ``disable_unicode=True`` is turned on, the ``default_filters`` +argument which normally defaults to ``["unicode"]`` now defaults +to ``["str"]`` instead. Setting default_filters to the empty list +``[]`` can remove the overhead of the ``str`` call. Also, in this +mode you **cannot** safely call :meth:`~.Template.render_unicode` - you'll get +unicode/decode errors. + +The ``h`` filter (html escape) uses a less performant pure Python +escape function in non-unicode mode (note that in versions prior +to 0.3.4, it used cgi.escape(), which has been replaced with a +function that also escapes single quotes). This because +MarkupSafe only supports Python unicode objects for non-ascii +strings. + +**Rules for using disable_unicode=True** + +* don't use this mode unless you really, really want to and you + absolutely understand what you're doing +* don't use this option just because you don't want to learn to + use Unicode properly; we aren't supporting user issues in this + mode of operation. We will however offer generous help for the + vast majority of users who stick to the Unicode program. +* Python 3 is unicode by default, and the flag is not available + when running on Python 3. + + + diff --git a/doc/build/usage.rst b/doc/build/usage.rst index 6c2dd90..4309c8c 100644 --- a/doc/build/usage.rst +++ b/doc/build/usage.rst @@ -22,10 +22,10 @@ the :class:`.Template` class:: Above, the text argument to :class:`.Template` is **compiled** into a Python module representation. This module contains a function -called :meth:`~.Template.render_body()`, which produces the output of the +called ``render_body()``, which produces the output of the template. When ``mytemplate.render()`` is called, Mako sets up a runtime environment for the template and calls the -:meth:`~.Template.render_body()` function, capturing the output into a buffer and +``render_body()`` function, capturing the output into a buffer and returning its string contents. @@ -415,18 +415,23 @@ API Documentation ================= .. autoclass:: mako.template.Template + :show-inheritance: :members: .. autoclass:: mako.template.DefTemplate + :show-inheritance: :members: .. autoclass:: mako.lookup.TemplateCollection + :show-inheritance: :members: .. autoclass:: mako.lookup.TemplateLookup + :show-inheritance: :members: .. autoclass:: mako.exceptions.RichTraceback + :show-inheritance: .. py:attribute:: error @@ -466,7 +471,6 @@ API Documentation .. py:attribute:: reverse_traceback the traceback list in reverse - .. autofunction:: mako.exceptions.html_error_template diff --git a/mako/lookup.py b/mako/lookup.py index 15793b7..15848d8 100644 --- a/mako/lookup.py +++ b/mako/lookup.py @@ -87,7 +87,7 @@ class TemplateLookup(TemplateCollection): some_template = lookup.get_template("/index.html") The :class:`.TemplateLookup` can also be given :class:`.Template` objects - programattically using :meth:`put_string` or :meth:`put_template`:: + programatically using :meth:`.put_string` or :meth:`.put_template`:: lookup = TemplateLookup() lookup.put_string("base.html", ''' @@ -111,7 +111,7 @@ class TemplateLookup(TemplateCollection): will maintain the size of the collection approximately to the number given. :param filesystem_checks: When at its default value of ``True``, each - call to :meth:`get_template()` will compare the filesystem last modified + call to :meth:`TemplateLookup.get_template()` will compare the filesystem last modified time to the time in which an existing :class:`.Template` object was created. This allows the :class:`.TemplateLookup` to regenerate a new :class:`.Template` whenever the original source has been updated. Set this to ``False`` for a diff --git a/mako/runtime.py b/mako/runtime.py index 863b4e7..0be67fc 100644 --- a/mako/runtime.py +++ b/mako/runtime.py @@ -10,7 +10,12 @@ from mako import exceptions, util import __builtin__, inspect, sys class Context(object): - """provides runtime namespace, output buffer, and various callstacks for templates.""" + """Provides runtime namespace, output buffer, and various callstacks for templates. + + See :ref:`runtime_toplevel` for detail on the usage of :class:`.Context`. + + """ + def __init__(self, buffer, **data): self._buffer_stack = [buffer] self._orig = data # original data, minus the builtins @@ -29,26 +34,40 @@ class Context(object): @property def lookup(self): + """Return the :class:`.TemplateLookup` associated + with this :class:`.Context`. + + """ return self._with_template.lookup @property def kwargs(self): + """Return the dictionary of keyword argments associated with this + :class:`.Context`. + + """ return self._kwargs.copy() def push_caller(self, caller): + """Pushes a 'caller' callable onto the callstack for this :class:`.Context`.""" + + self.caller_stack.append(caller) def pop_caller(self): + """Pops a 'caller' callable onto the callstack for this :class:`.Context`.""" + del self.caller_stack[-1] def keys(self): + """Return a list of all names established in this :class:`.Context`.""" return self._data.keys() def __getitem__(self, key): return self._data[key] def _push_writer(self): - """push a capturing buffer onto this Context and return the new Writer function.""" + """push a capturing buffer onto this Context and return the new writer function.""" buf = util.FastEncodingBuffer() self._buffer_stack.append(buf) @@ -74,15 +93,17 @@ class Context(object): return self._buffer_stack.pop() def get(self, key, default=None): + """Return a value from this :class:`.Context`.""" + return self._data.get(key, default) def write(self, string): - """write a string to this Context's underlying output buffer.""" + """Write a string to this :class:`.Context` object's underlying output buffer.""" self._buffer_stack[-1].write(string) def writer(self): - """return the current writer function""" + """Return the current writer function""" return self._buffer_stack[-1].write @@ -97,15 +118,19 @@ class Context(object): c.namespaces = self.namespaces c.caller_stack = self.caller_stack return c + def locals_(self, d): - """create a new Context with a copy of this Context's current state, updated with the given dictionary.""" + """create a new :class:`.Context` with a copy of this + :class:`Context`'s current state, updated with the given dictionary.""" + if len(d) == 0: return self c = self._copy() c._data.update(d) return c + def _clean_inheritance_tokens(self): - """create a new copy of this Context with tokens related to inheritance state removed.""" + """create a new copy of this :class:`.Context`. with tokens related to inheritance state removed.""" c = self._copy() x = c._data x.pop('self', None) @@ -130,7 +155,13 @@ class CallerStack(list): class Undefined(object): - """represents an undefined value in a template.""" + """Represents an undefined value in a template. + + All template modules have a constant value + ``UNDEFINED`` present which is an instance of this + object. + + """ def __str__(self): raise NameError("Undefined") def __nonzero__(self): @@ -151,8 +182,10 @@ class _NSAttr(object): raise AttributeError(key) class Namespace(object): - """provides access to collections of rendering methods, which - can be local, from other templates, or from imported modules""" + """Provides access to collections of rendering methods, which + can be local, from other templates, or from imported modules. + + """ def __init__(self, name, context, module=None, template=None, templateuri=None, @@ -204,9 +237,25 @@ class Namespace(object): return self._attr def get_namespace(self, uri): - """return a namespace corresponding to the given template uri. + """Return a :class:`.Namespace` corresponding to the given uri. - if a relative uri, it is adjusted to that of the template of this namespace""" + If the given uri is a relative uri (i.e. it does not + contain ia leading slash ``/``), the uri is adjusted to + be relative to the uri of the namespace itself. This + method is therefore mostly useful off of the built-in + ``local`` namespace, described in :ref:`namespace_local` + + In + most cases, a template wouldn't need this function, and + should instead use the ``<%namespace>`` tag to load + namespaces. However, since all ``<%namespace>`` tags are + evaulated before the body of a template ever runs, + this method can be used to locate namespaces using + expressions that were generated within the body code of + the template, or to conditionally use a particular + namespace. + + """ key = (self, uri) if self.context.namespaces.has_key(key): return self.context.namespaces[key] @@ -286,7 +335,11 @@ class Namespace(object): raise AttributeError("Namespace '%s' has no member '%s'" % (self.name, key)) def supports_caller(func): - """apply a caller_stack compatibility decorator to a plain Python function.""" + """Apply a caller_stack compatibility decorator to a plain Python function. + + See the example in :ref:`namespaces_python_modules`. + + """ def wrap_stackframe(context, *args, **kwargs): context.caller_stack._push_frame() @@ -297,7 +350,11 @@ def supports_caller(func): return wrap_stackframe def capture(context, callable_, *args, **kwargs): - """execute the given template def, capturing the output into a buffer.""" + """Execute the given template def, capturing the output into a buffer. + + See the example in :ref:`namespaces_python_modules`. + + """ if not callable(callable_): raise exceptions.RuntimeException( |