PylonsHQ.

Layout: Fixed-width

Why do I get a UnicodeDecodeError when using Mako?

In a traceback you may see the error message: UnicodeDecodeError: 'ascii' codec can't decode byte...

Mako uses unicode internally. This error usually occurs when you've given Mako a non-ascii raw string. Upon converting the raw string to unicode (via unicode(your_str)), the UnicodeDecodeError is raised.

Make Mako input (and output) UTF-8

You can tell Mako the encoding of strings in the template by specifying a "magic encoding comment" at the top of the file (like you would with a .py file):

1
# -*- coding: utf-8 -*-

Alternatively, the encoding can be specified for all mako templates in your Pylons project by adding the following to the end of your project's load_environment function in the YOURPROJECT/config/environment.py file:

1
tmpl_options['mako.input_encoding'] = 'utf-8'

By default, Pylons configures Mako to output to a UTF-8 encoded raw string (i.e. when you call render() on a mako template). This would be equivalent to the following code in the same file:

Pylons does this by default

1
tmpl_options['mako.output_encoding'] = 'utf-8'

Make sure you use proper unicode strings

Specifying the encoding of the template tells Mako about the strings defined within the template. This would solve UnicodeEncodeErrors for a template such as:

1
2
3
4
5
6
<html>
  <head><title>voix m'a réveillé</title></head>
  <body>
    ${u"voix m'a réveillé."}
  </body>
</html>

However Mako cannot and will not assume the encoding of raw strings passed to it via expressions, such as:

Bad

1
${h.submit(value='Änderungen speichern')}

Mako will internally call unicode() on the output of h.submit in this case (which would be a raw string containing non-ascii characters), causing a UnicodeDecodeError. Non-ascii strings used in an expression must be unicode:

Good

1
${h.submit(value=u'Änderungen speichern')}

If the request parameters (request.params) are being used in Mako expressions, they can be converted to Unicode automatically for you. Pylons 0.9.6 does this by default; to enable automatic unicode conversion of request parameters in versions prior to 0.9.6, modify the pylons.config.Config constructor line in load_environment to the following:

Pylons 0.9.5 and below

1
2
return pylons.config.Config(tmpl_options, map, paths,
                            request_settings=dict(charset='utf-8', errors='replace'))

Alternatively...

Mako's calling of unicode(data) occurs because the unicode function acts as Mako's default filter. You can change the default filter to decode raw strings to 'utf-8' via the decode.utf8 filter. However, this is a lazy way of solving this issue, has performance repercussions, and is NOT recommended:

1
tmpl_options['mako.default_filters'] = ['decode.utf8']

From the mako docs:

Note that the built-in decode object is slower than the unicode function, since unlike unicode its not a Python builtin, and it also checks the type of the incoming data to determine if string conversion is needed first.

See also:
The Mako Unicode Chapter
Pylons Unicode Document
Pylons Unicode Document - Request Parameters

Christoph Haas, Ksenia Marasanova, Philip Jenvey

Labels

templates-faq templates-faq Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 16, 2008

    Maciej Litwiniuk says:

    Alternative way with adding .syntax { background: #f8f8f8; } .syntax .c { col...

    Alternative way with adding

    1
    tmpl_options['mako.default_filters'] = ['decode.utf8']
    

    at the end of your environment.py is required, if you wan't to use things like

    1
    {c.news.title}
    

    inside your template, where "news" if object fetched from DB, and title is unicode string.

    1. Mar 04, 2009

      Marius Gedminas says:

      I think you mean "and title is a UTF-8 string". You can tell SQLAlchemy whether...

      I think you mean "and title is a UTF-8 string".

      You can tell SQLAlchemy whether you want Python unicode objects or Python str objects with 8-bit characters in your model definition, by choosing Unicode() versus String() columns. With Unicode() there's no need to change mako's default_filters.


Powered by Pylons - Contact Administrators