How do you debug Mako templates?

Viewed 11136

So far I've found it impossible to produce usable tracebacks when Mako templates aren't coded correctly.

Is there any way to debug templates besides iterating for every line of code?

6 Answers

I break them down into pieces, and then reassemble the pieces when I've found the problem.

Not good, but it's really hard to tell what went wrong in a big, complex template.

My main frustration with Mako was that it was hard to see what was happening in the template. As the template code is a runnable object that is in-memory, no debugger can look into it.

One solution is to write the template code to file, and re-run the template using this file as a standard python module. Then you can debug to your hearts content.

An example:

import sys
from mako import exceptions, template 
from mako.template import DefTemplate
from mako.runtime import _render

<Do Great Stuff>

try:
    template.render(**arguments))
except:
    # Try to re-create the error using a proper file template
    # This will give a clearer error message.
    with open('failed_template.py', 'w') as out:
        out.write(template._code)
    import failed_template
    data = dict(callable=failed_template.render_body, **arguments)
    try:
        _render(DefTemplate(template, failed_template.render_body),
                failed_template.render_body,
                [],
                data)
    except:
        msg = '<An error occurred when rendering template for %s>\n'%arguments
        msg += exceptions.text_error_template().render()
        print(msg, file=sys.stderr)
        raise

Combining the two top answers with my own special sauce:

from flask.ext.mako import render_template as render_template_1
from mako import exceptions

app.config['MAKO_TRANSLATE_EXCEPTIONS'] = False    # seems to be necessary

def render_template(*args, **kwargs):
    kwargs2 = dict(**kwargs)
    kwargs2['config'] = app.config     # this is irrelevant, but useful
    try:
        return render_template_1(*args, **kwargs2)
    except:
        if app.config.get('DEBUG'):
            return exceptions.html_error_template().render()
        raise

It wraps the stock "render_template" function:

  • catch exceptions, and
    • if debugging, render a backtrace
    • if not debugging, raise the exception again so it will be logged
  • make config accessible from the page (irrelevant)
Related