Injecting static content in TurboGears

Something that you usually need to do when providing a library or a reusable wsgi application is installing static data with the library itself.

This can be quickly performed by adding something like

package_data = {”:[‘*.html’, ‘*.js’, ‘*.css’, ‘*.png’]}

to your setup.py

But then how can we let our turbogears application serve that?

  • For html files (genshi templates) the solution is quite simple, you can just expose them by using @expose(‘librarypackage.templatesdir.template’). For example supposing we are installing libcool with its templates in libcool/templates you can do @expose(‘libcool.templates.index’)
  • For js and css files you can add them to your pages by creating a tw.api.JSLink or tw.api.CSSLink object. Just create inside your library something like: cool_js = tw.api.JSLink(modname = __name__, filename = ‘static/cool.js’) and then place in the controller exposing the view where you want to use that js file cool_js.inject()
  • Exposing images can be more complex, you have to declare a widget which will render the img tag by using ToscaWidgets resources exposure.
    class IconLink(tw.api.Link):
        """
        A link to an icon.
        """
        template = """<img src="$link" alt="$alt" />"""
    
        params = dict(alt="Alternative text when not displaying the image")
    
        def __init__(self, *args, **kw):
            super(IconLink, self).__init__(*args, **kw)
            self.alt = kw.get('alt')

    then you can create one IconLink for each icon in your library with something like: parent = IconLink(modname=__name__, filename=’static/icons/parent.png’, alt=’Up’) and inside your views you can place the icon by doing ${parent.display()} . This will add the image by exposing it from inside the static directory of your library package. Remember that you need to add an __init__.py inside the static directory and its subdirectory if you want setuptools to correctly install the static files.

Quick fix for ToscaWidget 0.9.6 bug with ListForm

There is a little bug in ToscaWidget 0.9.6 when creating a form with a ListForm. The solution can be to use a TableForm or to fix the ListForm itself. The problem is inside the genshi template for the ListForm and can be fixed by changing tw.forms-0.9.6-py2.5.egg/tw/forms/templates/list_form.html in each line where there is a call to field.display(value_for(field), **args_for(field)) this must be surrounded with XML(…) so that the result from field.display won’t be escaped by genshi.

This should fix the problem when you see the XML code instead of the form itself inside your web page.

Force tw.jquery to include jquery for you and avoid double inclusion if you are using a jquery widget

One big problem when facing ToscaWidgets is when you have to use widgets that use javascript libraries and you are already importing them for your own use.

That usually ends up in a double import of the javascript library that in the best case is useless and in the worst one breaks everything. Looking around inside ToscaWidgets documentation you can end up finding that each Resource has an inject method that inserts the resource inside your template. As JSLink is a subclass of tw.api.Resource you can end up injecting the needed <script> tag inside your template and this will let ToscaWidgets know that you have already imported that javascript file.

For example if you are using tw.jquery to let ToscaWidgets know that you need jquery you can put a tw.jquery.jquery_js.inject() call inside the controller method that will require to render the template that uses jquery. If you need jquery on each page you can simply put it inside the __call__ method of your BaseController class (it is declared inside lib/base.py).

This is useful to include the same version of jQuery that tw.jquery will use, but even more it is useful to prevent tw.jquery to include jQuery again if you are already using the library for something different from a ToscaWidgets widget

On Sprox

Lately I have tried to use Sprox with Elixir.

First of all I have to thank percious. He is incredibly reliable and helpful. There is actually a bug in sprox that makes him threat one-to-many relationships as one-to-one relationships and makes it show a single selection field instead of a multiple selection field. This can be avoided changing the field type to sprox.widgets.PropertyMultipleSelectField but percious has been so kind to fix it on the fly while I was testing the problem for him and now sprox correctly detects the field type by default.

Bad enough there is a big problem with Elixir. As Sprox probably creates internal instances of the Entity you pass to him this causes an  undesidered behaviour. When using SQLAlchemy, until you add the object to the session it won’t be saved on the database, but with Elixir creating an object means saving it on the db and this results in having multiple empty entities saved on db each time you open a forum generated with Sprox. If you have any required field in your entity your application will crash as it won’t be able to save it.

In the end I had to switch back from Elixir to DeclarativeBase for my application and everything worked fine