• how to create a tales namespace

last modified August 26, 2009 by slinkp

You can create your own custom namespace which you can then call directly in TAL. This is a powerful, clean way to reuse code among various templates.

 

First, an example to give you an idea of what you can use this for:

<span tal:replace="context/modified/dateutils:long">Tuesday - Jul 15, 2008</span>
<span tal:replace="context/modified/dateutils:short">07/15/2008</span>

And you get that without having to write any custom supporting code for your template: no creating of a view method, inheriting from some base class, relying on acquisition, nothing.

 

This is implemented as a named adapter under the hood. In the example above, the datetime (context/modified) is the context, the name is "dateutils", and "long"/"short" are methods called on the adapter. Here's what the implementation might look like:


from zope.traversing.interfaces import IPathAdapter
from zope.tales.interfaces import ITALESFunctionNamespace
from zope import interface, component

class DateUtils(object):
  component.adapts(interface.Interface)
  interface.implements(ITALESFunctionNamespace, IPathAdapter)

  def __init__(self, context):
    self.context = context
  def long(self):
    return self.context.strftime('%A  - %b %d, %Y')
  def short(self):
    return self.context.strftime('%m/%d/%y')
  def setEngine(self, engine):
    pass
 

Then we need to wire it up through zcml.

  <adapter
     for="*"
     provides="zope.traversing.interfaces.IPathAdapter"
     factory=".dateutils.DateUtils"
     name="dateutils"
     trusted="true"
     />

                                                   
   <content class=".dateutils.DateUtils">               
     <require permission="zope2.Public"                   
              attributes="setEngine long short" />
   </content>

Note that while any permission should theoretically work, we've found that for unknown reasons we have to use zope2.Public. This should hopefully not be a security hole because the invocation will always happen in a template that is otherwise protected, but caveat emptor.

Note that when you add a new method, you have to add the attribute in zcml, or you'll get a traversal error.

Alternatively, you can create a new interface to represent your new functions, implement that interface, and then your zcml is as follows;

   <content class=".dateutils.DateUtils">               
     <require permission="zope2.Public"                   
                    interface="IDateUtils" />
   </content>

And I'll finish with a caveat. There are times when creating your own tales functions makes a lot of sense. There are more times when it doesn't. Only use this abstraction when you have a great many unrelated templates that share the same basic logic. Great candidates are general-purpose "utility" functions.