Tags

The template code tries to mimic Python syntax as far as possible, but is limited to what is required for templates and does not allow executing arbitrary Python statements. In some spots it also borrows Javascript semantics.

ll.ul4c supports the following tag types:

<?print?>

The print tag outputs the value of a variable or any other expression. If the expression doesn’t evaluate to a string it will be converted to a string first. The format of the string depends on the renderer, but should follow Python’s str() output as much as possible:

<h1><?print person.lastname?>, <?print person.firstname?></h1>

Printing None or undefined objects produces no output.

Hint

The <?print?> tag is implemented by ll.ul4c.PrintAST.

<?printx?>

The printx tag outputs the value of a variable or any other expression and escapes the characters <, >, &, ' and " with the appropriate character or entity references for XML or HTML output.

Hint

The <?printx?> tag is implemented by ll.ul4c.PrintXAST.

<?for?>

The for tag can be used to loop over the items in a list, the characters in a string, the keys in a dictionary or any other iterable object. The end of the loop body must be marked with an <?end for?> tag:

<ul>
   <?for person in data.persons?>
      <li><?print person.lastname?>, <?print person.firstname?></li>
   <?end for?>
</ul>

In for loops variable unpacking is supported, so you can do the following:

<?for (key, value) in dict.items()?>

if dict is a dictionary.

This unpacking can be arbitrarily nested, i.e. the following is possible too:

<?for (i, (key, value)) in enumerate(dict.items())?>

Hint

The <?for?> tag is implemented by ll.ul4c.ForBlockAST.

<?break?>

The break tag can be used to break out of the innermost running loop.

Hint

The <?break?> tag is implemented by ll.ul4c.BreakAST.

<?continue?>

The continue tag can be used to skip the rest of the loop body of the innermost running loop and continue with the next iteration of the loop.

Hint

The <?continue?> tag is implemented by ll.ul4c.ContinueAST.

<?if?>

The if tag can be used to output a part of the template only when a condition is true. The end of the if block must be marked with an <?end if?> tag. The truth value of an object is mostly the same as in Python:

  • None is false.

  • The integer 0 and the float value 0.0 are false.

  • Empty strings, lists and dictionaries are false.

  • timedelta and monthdelta objects for an empty timespan (i.e. timedelta(0, 0, 0) and monthdelta(0)) are false.

  • False is false.

  • Undefined is false.

  • Anything else is true.

For example we can output the person list only if there are any persons:

<?if persons?>
   <ul>
      <?for person in persons?>
         <li><?print person.lastname?>, <?print person.firstname?></li>
      <?end for?>
   </ul>
<?end if?>

elif and else are supported too:

<?if persons?>
   <ul>
      <?for person in persons?>
         <li><?print person.lastname?>, <?print person.firstname?></li>
      <?end for?>
   </ul>
<?else?>
   <p>No persons found!</p>
<?end if?>

or:

<?if len(persons)==0?>
   No persons found!
<?elif len(persons)==1?>
   One person found!
<?else?>
   <?print len(persons)?> persons found!
<?end if?>

Hint

The <?if?>, <?elif?> and <?else?> tags are implemented by ll.ul4c.ConditionalBlocksAST, ll.ul4c.IfBlockAST, ll.ul4c.ElIfBlockAST and ll.ul4c.ElseBlockAST.

<?code?>

The code tag can contain statements that define or modify variables or expressions which will be evaluated for their side effects. Apart from the assigment operator =, the following augmented assignment operators are supported:

  • += (adds a value to the variable)

  • -= (subtracts a value from the variable)

  • *= (multiplies the variable by a value)

  • /= (divides the variable by a value)

  • //= (divides the variable by a value, rounding down to the next smallest integer)

  • %= (Does a modulo operation and replaces the variable value with the result)

  • <<= (Does bitwise “shift left” operation and replaces the variable value with the result)

  • >>= (Does bitwise “shift right” operation and replaces the variable value with the result)

  • &= (Does bitwise “and” operation and replaces the variable value with the result)

  • |= (Does bitwise “or” operation and replaces the variable value with the result)

  • ^= (Does bitwise “exclusive-or” operation and replaces the variable value with the result)

For example the following template will output 40:

<?code x = 17?>
<?code x += 23?>
<?print x?>

Hint

The content of <?code?> tags is implemented as UL4 expressions.

<?render?>

The render tag allows one template to call other templates. The following Python code demonstrates this:

from ll import ul4c

# Template 1
source1 = """\
<?if data?>\
<ul>
<?for i in data?><?render itemtmpl(item=i)?><?end for?>\
</ul>
<?end if?>\
"""

tmpl1 = ul4c.Template(source1)

# Template 2
source2 = "<li><?print xmlescape(item)?></li>\n"

tmpl2 = ul4c.Template(source2)

# Data object for the outer template
data = ["Python", "Java", "Javascript", "PHP"]

print(tmpl1.renders(itemtmpl=tmpl2, data=data))

This will output:

<ul>
<li>Python</li>
<li>Java</li>
<li>Javascript</li>
<li>PHP</li>
</ul>

I.e. templates can be passed just like any other object as a variable. <?render itemtmpl(item=i)?> renders the itemtmpl template and passes the i variable, which will be available in the inner template under the name item.

Hint

The <?render?> tag is implemented by ll.ul4c.RenderAST.

<?renderx?>

The renderx tag works similar to the render tag, except that the output of the template called will be XML escaped (like printx does). The following Python code demonstrates this:

from ll import ul4c

# Template 1
tmpl1 = ul4c.Template("<&>")

# Template 2
tmpl2 = ul4c.Template("<?renderx tmpl()?>\n")

print(tmpl1.renders(tmpl=tmpl2))

This will output:

&lt;&amp;&gt;

Hint

The <?renderx?> tag is implemented by ll.ul4c.RenderXAST.

<?render_or_print?>

The render_or_print tag combines the functionality of the render and the print tag, so for example

<?render_or_print foo(bar)?>

is more or less equivalent to

<?if istemplate(foo)?>
   <?render foo(bar)?>
<?else?>
   <?print foo?>
<?end if?>

i.e. if foo is renderable, it will be rendered, otherwise it will be printed. Furthermore the arguments to the call will always be evaluated even if foo isn’t renderable, so for example:

<?render_or_print 'foo'(None+None)?>

will fail with:

<?render_or_print 'foo'(None+None)?>
                        ~~~~~~~~~
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'

Hint

The <?render_or_print?> tag is implemented by ll.ul4c.RenderOrPrintAST.

<?render_or_printx?>

The render_or_printx tag is similar to render_or_print except that the object will be output via <?printx?> instead of <?print?> if it isn’t renderable.

Hint

The <?render_or_printx?> tag is implemented by ll.ul4c.RenderOrPrintXAST.

<?renderx_or_print?>

The renderx_or_print tag is similar to render_or_print except that the object will be rendered via <?renderx?> instead of <?render?> if it is renderable.

Hint

The <?renderx_or_print?> tag is implemented by ll.ul4c.RenderXOrPrintAST.

<?renderx_or_printx?>

The renderx_or_printx tag is similar to renderx_or_print except that the object will be output via <?printx?> instead of <?print?> if it isn’t renderable.

Hint

The <?renderx_or_printx?> tag is implemented by ll.ul4c.RenderXOrPrintXAST.

<?def?>

The def tag defines a new template as a variable. Usage looks like this:

<?def quote?>
   "<?print text?>"
<?end def?>

This defines a local variable quote that is a template object. This template can be rendered like any other template that has been passed to the outermost template:

<?render quote(text="foo")?>

It’s also possible to include a signature in the definition of the template. This makes it possible to define default values for template variables and to call templates with positional arguments:

<?def quote(text='foo')?>
   "<?print text?>"
<?end def?>
<?render quote()?> and <?render quote("bar")?>

This will output "foo" and "bar".

* and ** arguments are also supported:

<?def weightedsum(*args)?>
   <?print sum(i*arg for (i, arg) in enumerate(args, 1))?>
<?end def?>
<?render weightedsum(17, 23, 42)?>

This will print 189 (i.e. 1 * 17 + 2 * 23 + 3 * 42).

Hint

The <?def?> tag simply creates a Template object inside another Template object.

<?renderblocks?>

The renderblocks tag is syntactic sugar for rendering a template and passing other templates as arguments in the call. For example if we have the following template:

<?def page(head, body, lang="en", doctype=False)?>
   <?if doctype?>
      <!DOCTYPE html>
   <?end if?>
   <html lang="<?printx lang?>">
      <head>
         <?render head()?>
      </head>
      <body>
         <?render body()?>
      </body>
   </html>
<?end def?>

then we can render this template in the following way:

<?renderblocks page(lang="de", doctype=True)?>
   <?def head?>
      <title>Foo</title>
   <?end def?>
   <?def body?>
      <h1>Bar!</h1>
   <?end def?>
<?end renderblocks?>

This is syntactic sugar for:

<?def head?>
   <title>Foo</title>
<?end def?>
<?def body?>
   <h1>Bar!</h1>
<?end def?>
<?render page(lang="de", doctype=True, head=head, body=body)?>

In both cases the output will be:

<!DOCTYPE html>
<html lang="de">
   <head>
      <title>Foo</title>
   </head>
   <body>
      <h1>Bar!</h1>
   </body>
</html>

All variables defined between <?renderblocks page(...)?> and <?end renderblocks?> are passed as additional keyword arguments in the render call to page. (But note that those variables will be local to the <?renderblocks?> block, i.e. they will not leak into the surrounding code.)

Hint

The <?renderblocks?> tag is implemented by ll.ul4c.RenderBlocksAST.

<?renderblock?>

The renderblock is a special version of renderblocks. The complete content of the renderblock block will be wrapped in a signatureless template named content and this template will be passed as the keyword argument content to the render call. With this we can define a generic template for HTML links:

<?def a(content, **attrs)?>
   <a<?for (an, av) in attrs.items()?> <?print an?>="<?printx av?>"<?end for?>>
      <?render content()?>
   </a>
<?end def?>

and then use it like this:

<?renderblock a(class="extern", href="http://www.python.org/")?>
   Link to the Python homepage
<?end renderblock?>

The output will be:

<a class="extern" href="http://www.python.org/">
   Link to the Python homepage
</a>

Hint

The <?renderblock?> tag is implemented by ll.ul4c.RenderBlockAST.

<?return?>

The return tag returns a value from the template when the template is called as a function. For more info see Templates as functions.

Hint

The <?return?> tag is implemented by ll.ul4c.ReturnAST.

<?ul4?>

The ul4 tag can be used to specify a name and a signature for the template itself. This overwrites the name and signature specified in the ul4c.Template constructor:

>>> from ll import ul4c
>>> t = ul4c.Template("<?ul4 foo(x)?><?print x?>")
>>> t.name
'foo'
>>> t.signature
<Signature (x)>

Hint

The <?ul4?> tag has no corresponding AST nodes. Its content will set attributes of the template instead.

<?note?>

A note tag is a comment and can be used to explain the template code. When the template gets executed, the content of the tag will be completely ignored.

The <?note?> tag supports two variants:

  • The comment can be included as the content of the tag:

    <?note comment?>
    
  • The comment can be included between a <?note?> and an <?end note?> tag:

    <?note?>
    comment
    <?end note?>
    

    This second variant makes it possible to include UL4 source code in <?note?> tags.

Hint

A <?note?> tag has no corresponding AST nodes.

<?doc?>

A doc tag contains the documentation of the template itself. The content of the <?doc?> tag is available as the doc attribute:

>>> from ll import ul4c
>>> t = ul4c.Template("<?doc foo?><?print x?>")
>>> t.doc
'foo'

Each <?doc?> contains the documentation for the template to which the <?doc?> tag belongs, i.e. if the <?doc?> tag is at the outermost level, it belongs to the outermost template. If the <?doc?> tag is inside a local template, it is the documentation for the local template. If multiple <?doc?> tags are given, only the first one will be used, all later ones will be ignored.

The <?doc?> tag supports two variants:

  • The description can be included as the content of the tag:

    <?doc description?>
    
  • The description can be included between a <?doc?> and an <?end doc?> tag:

    <?doc?>
    description
    <?end doc?>
    

    This second variant makes it possible to include UL4 source code in <?doc?> tags.

Note that the template name, documentation and signature are accessible inside the templates themselves, i.e.:

<?def f(x=17, y=23)?>
   <?doc return the sum of x and y?>
   <?return x+y?>
<?end def?>
<?print f.name?>
<?print f.doc?>
<?print f.signature?>

will output:

f
return the sum of x and y
(x=17, y=23)

Hint

A <?doc?> tag has no corresponding AST nodes. Its content will set the doc property of the template instead.

<?ignore?>

An ignore tag can be used to “comment out” template code, so that the code will never be executed. <?ignore?> and <?end ignore?> tags nest, so code that already contains <?ignore?> and <?end ignore?> tags can be ignored by added additional <?ignore?> and <?end ignore?> tags around it.

It is not required that the content between the <?ignore?> and <?end ignore?> tag is proper UL4 code.

For example the follow template won’t output anything:

<?ignore?>
   <?for i in range(20)?>
      <?print i?>
   <?end for?>
   <?ignore?>
      <?note Unfinished if?>
      <?if 42?>
   <?end ignore?>
<?end ignore?>

Hint

An <?ignore?> tag has no corresponding AST nodes.

<?whitespace?>

The whitespace tag can be used to overwrite the handling of whitespace in the template. For more info see Whitespace handling.

Hint

A <?whitespace?> tag has no corresponding AST nodes. Its content will set the whitespace attribute of the template instead.