summaryrefslogtreecommitdiff
path: root/doc/build/filtering.rst
blob: 3d0225e7cb33f92fe9f276692c262d07dd2a201b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
.. _filtering_toplevel:

=======================
Filtering and Buffering
=======================

.. _expression_filtering:

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)``

  .. versionadded:: 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 ``&lt;tag&gt;some value&lt;/tag&gt;``, 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>"
    %>

    Here's some tagged text: ${"text" | myescape}

Or from any Python module:

.. sourcecode:: mako

    <%!
        import myfilters
    %>

    Here's 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: &lt;html&gt;some html&lt;/html&gt;

.. _filtering_default_filters:

The ``default_filters`` Argument
--------------------------------

In addition to the ``expression_filter`` argument, the
``default_filters`` argument to both :class:`.Template` and
:class:`.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):

.. 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")))

.. _expression_filtering_nfilter:

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 as in ``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.

Including the ``n`` filter in a ``<%page>`` tag will only disable
``default_filters``. In effect this makes the filters from the tag replace
default filters instead of adding to them. For example:

.. sourcecode:: mako

    <%page expression_filter="n, json.dumps"/>
    data = {a: ${123}, b: ${"123"}};

will suppress turning the values into strings using the default filter, so that
``json.dumps`` (which requires ``imports=["import json"]`` or something
equivalent) can take the value type into account, formatting numbers as numeric
literals and strings as string literals.

.. versionadded:: 1.0.14 The ``n`` filter can now be used in the ``<%page>`` tag.

Filtering Defs and Blocks
=========================

The ``%def`` and ``%block`` tags have an argument called ``filter`` 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 :class:`.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
==========

.. versionadded:: 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 :func:`.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, and blocks too. Note that when calling a top-level def from the
:class:`.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.