Developing Custom Tags

In complex applications you may encounter presentation problems which the standard collection of tags cannot easily solve. Albatross allows you to register additional tags, which are then available for use in your templates. Custom tags are named with an alx- prefix to distinguish them from standard al- tags.

Custom tags should subclass either EmptyTag or EnclosingTag, and have a name class attribute. The name should start with alx- and contain only letters, numbers and the underscore character.

Custom tags that produce form inputs need to register the names of those inputs with the NameRecorderMixin via the input_add() method. For more information, see section NameRecorderMixin, NameRecorderMixin in the Mixin Class Reference.

The following is a simple calendar tag which formats a single month like the unix cal(1) program.

import time
import calendar
import albatross


class Calendar(albatross.EmptyTag):

    name = 'alx-calendar'

    def to_html(self, ctx):
        year = self.get_attrib('year')
        if year is not None:
            year = ctx.eval_expr(year)
        month = self.get_attrib('month')
        if month is not None:
            month = ctx.eval_expr(month)
        if month is None or year is None:
            now = time.localtime(time.time())
            if year is None:
                year = now[0]
            if month is None:
                month = now[1]
        ctx.write_content('<table>\n')
        ctx.write_content('<tr align="center"><td colspan="7">%s %s</td></tr>\n' \
                          % (calendar.month_name[month], year))
        ctx.write_content('<tr>')
        for i in range(7):
            ctx.write_content('<td>%s</td>' \
                              % calendar.day_abbr[(i + 6) % 7][:2])
        ctx.write_content('</tr>\n')
        calendar.setfirstweekday(6)
        for r in calendar.monthcalendar(year, month):
            ctx.write_content('<tr align="right">')
            for i in range(7):
                if r[i]:
                    ctx.write_content('<td>%s</td>' % r[i])
                else:
                    ctx.write_content('<td></td>')
            ctx.write_content('</tr>\n')
        ctx.write_content('</table>\n')

To use the tag in your application you must make the class available to the execution context. If you are using an Albatross application object you can do this by passing the class to the register_tagclasses() method of the application object.

from albatross import SimpleApp

app = SimpleApp('ext.py', '.', 'start')
app.register_tagclasses(Calendar)

All Albatross application classes inherit from the ResourceMixin in the albatross.context module. Execution contexts which are used with application objects inherit from the AppContext class from the albatross.app module which automatically retrieves all resources from the parent application object.

If you are using the SimpleContext class for your execution context then you will need to call the register_tagclasses() method of the execution context immediately after construction.

The following is an example template file which uses the <alx-calendar> tag.

<html>
<head><title>Calendar for <al-value expr="year"></title></head>
<body>
<h1>Calendar for <al-value expr="year"></h1>
<table cellpadding="10">
<al-for iter="r" expr="range(1,13)" cols="3" flow="across">
 <tr valign="top">
 <al-for iter="m" expr="r.value()">
  <td><alx-calendar month="m.value()" year="year"></td>
 </al-for>
 </tr>
</al-for>
</table>
</body>
</html>

A complete program which uses this extension tag and template file can be found in the samples/extension directory. Use the install.py script to install the sample.

cd samples/extension
python install.py

The implementation of the standard tags also makes a good reference when writing custom tags. All standard tags are defined in albatross.tags.

albatross.template — Base classes for implementing tags

The module contains the following classes which are intended to be used in implementing custom tags.

class albatross.template.Tag(ctx, filename, line_num, attribs)

This is the base class upon which all tags are implemented. You are unlikely to ever subclass this directly. The EmptyTag and EnclosingTag classes inherit from this class.

class albatross.template.EmptyTag(ctx, filename, line_num, attribs)

Use this class as a subclass for all tags which do not require a closing tag and therefore do not enclose content. Examples of standard HTML tags which do not enclose content are <BR> and <HR>.

class albatross.template.EnclosingTag(ctx, filename, line_num, attribs)

Use this class as a subclass for all tags which enclose content. Examples of standard HTML tags which enclose content are <BODY> and <TABLE>.

class albatross.template.Text(text)

A simple wrapper around the string passed in the text constructor argument which passes that string to the to_html() method when the object is converted to HTML.

class albatross.template.Content

A simple wrapper around a list which calls the to_html() method of all list elements when the object is converted to HTML.

Tag Objects

Tag.raise_error(msg)

Raises a TemplateError exception using the string in the msg argument.

Tag.has_attrib(name)

Returns TRUE if the attribute specified in the name argument was defined for the tag. All attribute names are converted to lower case by the template parser.

Tag.assert_has_attrib(name)

If the attribute specified in the name argument is not defined for the tag a TemplateError exception will be raised.

Tag.assert_any_attrib(*names)

If none of the attributes specified by the arguments are defined for the tag a TemplateError exception will be raised.

Tag.get_attrib(name[, default ``= None``])

Retrieves the value of the attribute specified in the name argument.

Tag.set_attrib(name, value)

Sets the value of the attribute named in the name argument to the value in the value argument.

Tag.set_attrib_order(order)

Defines the order that the tag attributes will be written during conversion to HTML. The template parser captures the attribute sequence from the template file then calls this method.

Tag.attrib_items()

Returns a list of attribute name, value tuples which are defined for the tag.

Tag.write_attribs_except(ctx[, ...])

Sends all tag attributes to the write_content() method of the execution context in the ctx argument. Any attributes named in additional arguments will not be written.

EmptyTag Objects

EmptyTag.has_content()

Returns 0 to inform the template parser that the tag does not enclose content.

EmptyTag.to_html(ctx)

The template interpreter calls this method to convert the tag to HTML for the execution context in the ctx argument. The default implementation does nothing.

You must override this method in your tag class to perform all actions which are necessary to “execute” the tag.

EnclosingTag Objects

EnclosingTag.content

An instance of the Content class which is created during the constructor.

EnclosingTag.has_content()

Returns 1 to inform the template parser that the tag encloses content.

EnclosingTag.append(item)

Called by the template parser to append the content in the item argument to the tag. The method implementation simply passes item to the append() method of the content member.

You should override this method if you need to maintain multiple content lists within your tag.

EnclosingTag.to_html(ctx)

The template interpreter calls this method to convert the tag to HTML for the execution context in the ctx argument. The default implementation passes ctx to the the to_html() method of the content member.

You must override this method in your tag class to perform all actions which are necessary to “execute” the tag.

Text Objects

Text.to_html(ctx)

Sends the wrapped text to the write_content() method of the execution context in the ctx argument. You should not ever need to subclass these objects.

Content Objects

Content.append(item)

Appends the value in the item argument to the internal Python list.

Content.to_html(ctx)

Sequentially invokes the to_html() method of every item in the internal Python list passing the ctx argument.