Syntax

Some relevant parts of this section were copied from the official Slim documentation.

Line Indicators

|
The pipe tells Plim to just copy the line. It essentially escapes any processing.
,

The comma tells Plim to copy the line (similar to |), but makes sure that a single trailing space is appended.

注解

Slim syntax instead has the single quote ( ' ) line indicator.

-
The dash denotes control code. Examples of control code are loops, conditionals, mako tags, and extensions.
=
The equal sign tells Plim it’s a Python call that produces output to add to the buffer.
=,
Same as the single equal sign ( = ), except that it adds an explicit single trailing whitespace after the python expression.
==

Same as the single equal sign ( = ), but adds the “n” filter to mako expression.

== python_expression                       =>      ${python_expression|n}

== python_expression | custom_filter       =>      ${python_expression |n,custom_filter}
==,
Same as the double equal sign ( == ), except that it adds an explicit single trailing whitespace after the python expression.
/

Use the forward slash for code comments - anything after it won’t get displayed in the final mako markup.

注解

There is no an equivalent syntax for Slim’s “/!” html comment. This line indicator has been considered redundant since Plim supports raw HTML tags:

/ You can use raw HTML comment tags, as well as all other tags
<!-- HTML comment -->
<div>

  / You can use Plim markup inside the raw HTML
  a href="#" = link.title

/ If you use raw HTML, you have to close all tags manually
</div>

Indentation

Plim indentation rules are the same as of Slim: indentation matters, but it’s not as strict as Haml. If you want to first indent 2 spaces, then 5 spaces, it’s your choice. To nest markup you only need to indent by one space, the rest is gravy.

Tag Attributes

Static Attrbutes

Static tag attributes can be specified in the same form as any valid python string declaration.

For example

input type='text' name="username" value='''Max Power''' maxlength="""32"""

will be rendered as

<input type="text" name="username" value="Max Power" maxlength="32"/>

As in Python string declarations, you must take care of correct quote escaping

input value='It\'s simple'
input value="It's simple"
input value='''It's simple'''
input value="""It's simple"""

input value="He said \"All right!\""
input value='He said "All right!"'
input value='''He said "All right!"'''
input value="""He said "All right!\""""

You can omit quotes from numeric attribute values:

input type='text' name="measure" value=+.97 maxlength=32

produces

<input type="text" name="measure" value="+.97" maxlength="32"/>

Dynamic Attributes

Dynamic values can be specified in forms of:

  • Mako expression

    input type="text" name="username" value="${user.name}" maxlength=32
    a href="${request.route_url('user_profile', tagname=user.login, _scheme='https')}"
    

    or

    input type="text" name="username" value=${user.name} maxlength=32
    a href=${request.route_url('user_profile', tagname=user.login, _scheme='https')}
    
  • Python expression

    input type="text" name="username" value=user.name maxlength=32
    a href=request.route_url('user_profile', tagname=user.login, _scheme='https')
    

    or with parentheses

    input type="text" name="username" value=(user.name) maxlength=32
    a href=(request.route_url('user_profile', tagname=user.login, _scheme='https'))
    

All these examples produce the same mako markup:

<input type="text" name="username" value="${user.name}" maxlength="32"/>
<a href="${request.route_url('user_profile', tagname=user.login, _scheme='https')}"></a>

Boolean Attributes

Boolean attributes can be specified either by static or dynamic method:

Static attribute example:

/ Static boolean attribute "disabled"
input type="text" name="username" disabled="disabled"

/ If you wrap your attributes with parentheses, you can use
  shortcut form
input (type="text" name="username" disabled)

Dynamic attribute example (note the trailing question mark):

/ Dynamic boolean attribute "disabled"
  will be evaluated to 'disabled="disabled"' if `is_disabled`
  evaluates to True

input type="text" name="username" disabled=${is_disabled}?

/ or you can write it that way
input type="text" name="username" disabled=is_disabled?

/ or even that way
input type="text" name="username" disabled=(is_disabled or
                                            is_really_disabled)?

Dynamic unpacking

This feature is an equivalent to Slim’s splat attributes, but the syntax was changed in order to correspond to Python’s **kwargs semantics.

Consider the following python dictionary:

attrs = {
    'id': 'navbar-1',
    'class': 'navbar',
    'href': '#',
    'data-context': 'same-frame',
}

Now we can unpack the dictionary in order to populate tags with attributes. The following line:

a**attrs Link

will be translated to mako template which will output an equivalent to the following HTML markup

<a id="navbar-1" class="navbar" href="#" data-context="same-frame">Link</a>

Here are some other examples

a **attrs|Link

a **attrs **more_attrs Link

a(**attrs disabled) Disabled Link

a **function_returning_dict(
  *args, **kwargs
) Link

Attribute Wrapping

You can wrap tag attributes with parentheses (). Unlike Slim, Plim doesn’t support square [] or curly {} braces for attributes wrapping.

body
  h1(id="logo" class="small tagline") = page_logo
  h2 id=(id_from_variable + '-idx') = page_tagline

If you wrap the attributes, you can spread them across multiple lines:

body

  h1 (id="logo"
    class="small tagline") = page_logo

  h2 id=(
    id_from_variable +
    '-idx'
  ) = page_tagline

Inline Tag Content

You can put content on the same line with the tag:

body
  h1 id="headline" Welcome to my site.

Or nest it. Note: use either a pipe or Implicit literal indicators

body
  h1 id="headline"

    / Explicit literal with pipe character
    | Welcome to my site.

    / Implicit literal (uppercase letter at the beginning of the line)
    Yes, Welcome to my site

Dynamic Tag Content

You can make the call on the same line

body
  h1 id="headline" = page_headline

Or nest it.

body
  h1 id="headline"
    = page_headline

id and class Shortcuts

You can specify the id and class attributes in the following shortcut form.

body

  / Static shortcuts
  h1#headline
    = page_headline
  h2#tagline.small.tagline
    = page_tagline
  .content
    = show_content

This is the same as:

body
  h1 id="headline"
    = page_headline
  h2 id="tagline" class="small tagline"
    = page_tagline
  div class="content"
    = show_content

In contrast to Slim, Plim allows you to insert dynamic expressions right into the shortcuts:

/ Dynamic shortcuts
h1#headline-${'dynamic'} = page_headline
h2#${tagline.id}.small-${tagline.cls}.${tagline.other_cls}
  = page_tagline
.${'content'}
  = show_content

This is the same as:

h1 id="headline-${'dynamic'}" = page_headline
h2 id="${tagline.id}" class="small-${tagline.cls} ${tagline.other_cls}"
  = page_tagline
div class="${'content'}"
  = show_content

Inline Tags

Sometimes you may want to be a little more compact and inline the tags.

ul
  li.first: a href="/a" A link
  li: a href="/b" B link

For readability, don’t forget you can wrap the attributes.

ul
  li.first: a(href="/a") A link
  li: a(href="/b") B link

Inline Statements

You can inline python loops and conditional expressions in the same manner as tags.

ul: -for link in ['About', 'Blog', 'Sitemap']: li: a href=route_to(link) = link

will be rendered as

<ul>
%for link in ['About', 'Blog', 'Sitemap']:
<li><a href="${route_to(link)}">${link}</a></li>
%endfor
</ul>

Evaluate Python Code in Text

Use standard mako expression syntax. The text escaping depends on mako’s default filters settings.

body
  h1 Welcome ${current_user.name} to the show.
  Explicit non-escaped ${content|n} is also possible.

Currently, Mako doesn’t provide a simple way to escape the interpolation of expressions (i.e. render as is). You can use either the <%text> tag (or Plim’s -text equivalent for blocks of mako syntax examples), or this trick

body
  h1 Welcome ${'${current_user.name}'} to the show.

Embedded Markup

You can embed plim markup right into literal blocks:

a href="#" Embedded `strong string` everywhere

is rendered as

<a href="#">Embedded <strong>string</strong> everywhere</a>

If you want to put two embedded strings next to each other, add a trailing underscore character after the first embedded string:

a href="#" Embedded `strong string`_`i s` everywhere

is rendered as

<a href="#">Embedded <strong>string</strong><i>s</i> everywhere</a>

The embedding mechanism is recursive so you can embed plim markup into embedded plim markup:

Another `a href="#" very ``strong funny ````i recursive``````` test

is rendered as

Another <a href="#">very <strong>funny <i>recursive</i></strong></a> test

Skip HTML Escaping

Use either a double equal sign

body
  h1 id="headline"
    == page_headline

or the explicit | n filter at the end of the expression

body
  h1 id="headline"
    = page_headline | n

Code Comments

Use forward slash / for code comments

body
  p
    / This is a comment.
      Indentation is the natural way to get block comments

Raw HTML Tags

Plim allows you to use raw HTML tag lines, and also to mix them with any available control logic. It is particularly useful in situations like this one:

- if edit_profile
  / Wrap interface with editable block
  <div id="edit-profile">

- include new_or_edit_interface.html

- if edit_profile
  / close wrapper tag
  </div>

Doctype Declarations

There is no default option for doctype declaration tag. Therefore, you should explicitly specify the desired doctype:

doctype 5

Here is the full list of available doctypes:

doctype html

<!DOCTYPE html>

doctype 5

<!DOCTYPE html>

doctype 1.1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

doctype strict

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

doctype xml

<?xml version="1.0" encoding="utf-8" ?>

doctype transitional

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

doctype frameset

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

doctype basic

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

doctype mobile

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">

Control Logic

if/elif/else statements

-if items
  table
    -for item in items
      tr
        td = item.name
        td = item.price
-elif show_empty
  p No items found
-else
  a href=request.route_url('items.add') =, _('Add items')

unless statement

This is the shortcut form of the - if not (<EXPR>) statement.

-unless user.authenticated
  p Please, sign in.
-else
  p Welcome, ${user.name}!

for statement

table
  -for item in items
    tr
      td = item.name
      td = item.price

You can use the -continue and -break commands inside the -for block. See the section Returning Early from a Template.

while statement

-python
  i = 0
  limit = 5

ul
  -while i < limit
    li#idx-${i}.up: a href='#' title="Title" == i
    -py i += 1

You can use the -continue and -break commands inside the -while block. See the section Returning Early from a Template.

until statement

This is the shortcut form of the - while not (<EXPR>) statement.

-until i < 0
  li#idx-${i}.down-${i}: a href='''#''' title="""Title""" ==, i
  -py i -= 1

You can use the -continue and -break commands inside the -until block. See the section Returning Early from a Template.

with statement

The % with statement was introduced in Mako 0.7.0.

-with <EXPR> as <VAR>
  / Do some stuff

try/except statements

- try
  div = item[0]
  div = price['usd']

- except IndexError
  div IndexError

- except KeyError as e
  div = e

Returning Early from a Template

Plim provides a shortcut to Mako’s <% return %> template directive.

- if not len(records)
  No records found.
  -return

This is the same as

- if not len(records)
  No records found.
  -py return

You can use it at any position of the template, not only inside control structures.

There are also the -break and -continue shortcuts, that can be used inside the -for, -while, and -until loops.

Literals

You can specify either explicit or implicit literal blocks. The difference is, whether you prepend a block with the explicit pipe char | or start it by one of the implicit indicators.

Explicit Literals

Use a pipe ( | ) or comma ( , ) literal indicators to start the escape. Each following line that is indented greater than the first one is copied over.

body
  p
    / Explicit literal
    | This is a test of the text block.
body
  p
    |
      This is a test of the text block.

The parsed result of both the above examples:

<body><p>This is a test of the text block.</p></body>

The left margin is set to the zero. Any additional spaces will be copied over.

body
  p
    |  This line is on the zero left margin.
        This line will have one space in front of it.
          This line will have two spaces in front of it.
            And so on...

Implicit Literals

Literal blocks can be implicitly specified by the following starting sequences:

  • an uppercase ASCII letter;
  • any non-ASCII letter;
  • a digit without prefixed positive/negative signs;
  • HTML-escaped character, for example &nbsp;;
  • Mako open brace sequence ${;
  • an open square brace [;
  • an open parenthesis (;
  • any unicode character outside the range of U0021 - U007E (ASCII 33 - 126).
p
  | pipe is the explicit literal indicator. It is required if your line starts with
    the non-literal character.

p
  I'm the implicit literal, because my first letter is in uppercase.

p
  1. Digits
  2. are
  3. the
  4. implicit
  5. literals
  6. too.

p
  ${raw_mako_expression} indicates the implicit literal line.

p
  If subsequent lines do not start with implicit literal indicator,
    you must indent them
  | or you can use the "explicit" pipe.
p
  если ваш блок текста написан на русском, или любом другом языке, не
  использующим символы из ASCII-диапазона, то вам даже не обязательно
  использовать заглавную букву в начале блока.

  / if your literal blocks are written in Russian, or any other
    language which uses non-ASCII letters, you can put even the
    lowercase letter at the beginning of the block

Python Blocks

Classic Blocks

Use -py or -python to insert the <% %> mako tag.

For example

- python x = 1

or

-py
    x = 1

or even

- python x = 1
    y = x + 1
    if True:
        y += 1
    else:
        y -= 1

In latter case, the first line x = 1 will be aligned with the second line y = x + 1.

New-style blocks

0.9.1 新版功能: New-style blocks were introduced for better readability of embedded python code.

Use a sequence of at least three dashes to start a new-style python block.

Here are the overwritten examples of the classic ones. The results are the same:

--- x = 1
-------------
    x = 1
--- x = 1
    y = x + 1
    if True:
        y += 1
    else:
        y -= 1

And here’s an example of how we can use an inline statement for providing a block description

ul#userlist
    ---------- # prepare a list of users ---------------
        users = UsersService.get_many(max=100, offset=0)
        friends = UsersService.get_friends_for(users)
    ----------------------------------------------------
    -for user in users: li
        h4: a#user-${user.id} href='#' = user.name
        ul: -for friend in friends[user.id]: li
            a#friend-${friend.id} href='#' = friend.name

the result (indentation will be stripped out):

<ul id="userlist">
    <%
        # prepare a list of users
        users = UsersService.get_many(max=100, offset=0)
        friends = UsersService.get_friends_for(users)
    %>

    %for user in users:
        <li>
            <h4>
                <a href="#" id="user-${user.id}">${user.name}</a>
            </h4>
            <ul>
                %for friend in friends[user.id]:
                    <li>
                        <a href="#" id="friend-${friend.id}">${friend.name}</a>
                    </li>
                %endfor
            </ul>
        </li>
    %endfor
</ul>

Module-level Blocks

Use -py! or -python! block to insert the <%! %> mako tag.

-py!
    import mylib
    import re

    def filter(text):
        return re.sub(r'^@', '', text)

0.9.1 新版功能: The same example with a new-style syntax:

---! import mylib
     import re

     def filter(text):
         return re.sub(r'^@', '', text)

Mako Tags

Plim supports a complete set of Mako Tags, except the <%doc>. The latter has been considered deprecated, since Plim itself has built-in support of multi-line comments.

注解

As all mako tags start with the < char, which indicates a raw HTML line, they all can be written “as is”. The only thing you must remember is to manually close the pair tags.

-page tag

-page args="x, y, z='default'"

produces

<%page args="x, y, z='default'"/>

See the details of what <%page> is used for in The body() Method and Caching sections of Mako Documentation.

-include tag

-include footer.html

or

-include file="footer.html"

produce the same output

<%include file="footer.html"/>

See the <%include> section of Mako Documentation to get more information about this tag.

-inherit tag

-inherit base.html

or

-inherit file="base.html"

will generate the same

<%inherit file="base.html"/>

See Mako’s inheritance documentation to get more information about template inheritance.

-namespace tag

-namespace name="helper" helpers.html

or

-namespace file="helpers.html" name="helper"

produce

<%namespace file="helpers.html" name="helper"/>

See Mako’s namespace documentation to get more information about template namespaces.

-def tag

-def account(accountname, type='regular')

or

-def name="account(accountname, type='regular')"

produce

<%def name="account(accountname, type='regular')">
</%def>

See Mako’s defs and blocks documentation to get more information about functions and blocks.

-block tag

Unlike -def statements, blocks can be anonymous

-block
  This is an anonymous block.

Or they can be named as functions

-block name="post_prose"
  = pageargs['post'].content

or

-block post_prose
  = pageargs['post'].content

As in -def, both above examples produce the same result

<%block name="post_prose">
${pageargs['post'].content}</%block>

You can also specify other block arguments as well

- block filter="h"
  html this is some escaped html.

See Mako’s defs and blocks documentation to get more information about functions and blocks.

-call tag

This statement allows you to define custom tags.

The following examples

-call expression="${4==4}" self:conditional
  |i'm the result

- call expression=${4==4} self:conditional
  | i'm the result

- call self:conditional
  | i'm the result

- call self:conditional

will produce

<%self:conditional expression="${4==4}">
i'm the result
</%self:conditional>

<%self:conditional expression="${4==4}">
i'm the result
</%self:conditional>

<%self:conditional>
i'm the result
</%self:conditional>

<%self:conditional>
</%self:conditional>

Please consult the sections <%nsname:defname> and Calling a Def with Embedded Content and/or Other Defs of Mako Documentation to get more information about custom tags.

-text tag

As it is mentioned in Mako documentation, this tag suspends the Mako lexer’s normal parsing of Mako template directives, and returns its entire body contents as plain text. It is used pretty much to write documentation about Mako:

-text filter="h"
  here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

- text filter="h" here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

- text filter="h" = syntax
  <%def name="x()">${x}</%def>

-text
  here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

-text , here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>