如何在Mako中处理Unicode?
我在使用mako的时候总是遇到这个错误:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 6: ordinal not in range(128)
我已经尽可能地告诉mako我在使用unicode:
mylookup = TemplateLookup(
directories=['plugins/stl/templates'],
input_encoding='utf-8',
output_encoding='utf-8',
default_filters=['decode.utf8'],
encoding_errors='replace')
self.template = Template(self.getTemplate(), lookup=mylookup,
module_directory=tempfile.gettempdir(),
input_encoding='utf-8',
output_encoding='utf-8',
default_filters=['decode.utf8'],
encoding_errors='replace')
html = self.template.render_unicode(data=self.stuff)
我所有的模板文件开头都是:
## -*- coding: utf-8 -*-
而且,在这些文件里面,所有的常量字符串前面都有“u”的前缀。我知道self.stuff这个参数包含unicode字符串,但我创建mako对象的方式应该能处理这个问题(否则这些参数有什么用呢?)。我是不是忘记做什么了?
还有一个问题:encoding_errors='replace'有什么用?
=编辑= 我只留下了一个unicode字符串,这就是错误追踪信息:
Traceback (most recent call last):
File "C:\My Dropbox\src\flucso\src\plugins\stl\main.py", line 240, in updateView
flags=self.makoflags)
File "C:\Python26\lib\site-packages\mako-0.3.4-py2.6.egg\mako\template.py", line 198, in render_unicode
as_unicode=True)
File "C:\Python26\lib\site-packages\mako-0.3.4-py2.6.egg\mako\runtime.py", line 403, in _render
_render_context(template, callable_, context, *args, **_kwargs_for_callable(callable_, data))
File "C:\Python26\lib\site-packages\mako-0.3.4-py2.6.egg\mako\runtime.py", line 434, in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File "C:\Python26\lib\site-packages\mako-0.3.4-py2.6.egg\mako\runtime.py", line 457, in _exec_template
callable_(context, *args, **kwargs)
File "memory:0x41317f0", line 89, in render_body
File "C:\Python26\lib\site-packages\mako-0.3.4-py2.6.egg\mako\runtime.py", line 278, in <lambda>
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
File "FriendFeed_mako", line 49, in render_inlist_entry
File "C:\Python26\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u263c' in position 8: ordinal not in range(128)
3 个回答
这些建议(包括被接受的答案)并不是在所有情况下都有效,特别是当mako模板渲染内容时(例如,${value | n}),如果这个值包含非ASCII字符,就会出现问题。
这是因为默认情况下,mako会在生成的编译模板中的任何值周围加上unicode(foo),这仍然会导致:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)
在Python2中,确保mako能够正确处理unicode的唯一可靠方法是替换默认的('unicode')处理器,方法如下:
def handle_unicode(value):
if isinstance(value, basestring):
return unicode(value.decode('ascii', errors='ignore'))
return unicode(value)
...
lookup = TemplateLookup(
directories=[self._root.template_path],
imports=['from utils.view import handle_unicode'],
default_filters=["handle_unicode"]
)
...
template = self._lookup.get_template(self.template())
rtn = template.render(request=self.request)
为了方便搜索的朋友:
当你的模板文件里有非ASCII字符时,Mako会抛出一个异常,内容是 mako.exceptions.CompileException: Unicode decode operation of encoding 'ascii' failed in file
等等。这种情况通常发生在文件里没有写入Unicode BOM的时候。你需要手动添加这个BOM(至少在我的文本编辑器里,这个不会自动添加),这样:
$file test.htm
test.htm: HTML document, UTF-8 Unicode text
就变成这样:
$file test.htm
test.htm: HTML document, UTF-8 Unicode (with BOM) text
最后,我把我的模板保存成了unicode格式,实际上(我猜)是utf-16,而不是utf-8。这样一来,它们在磁盘上的大小翻了一倍,mako开始抱怨出现了“CompileException(‘utf-8’的unicode解码操作,等等)”,所以我把所有模板的第一行改成了:
## -*- coding: utf-16 -*-
并且去掉了所有的“.decode('utf-8')” - 常量字符串前面还是有“u”的。
现在在python中的初始化是:
mylookup = TemplateLookup(
directories=['plugins/stl/templates'],
input_encoding='utf-16',
output_encoding='utf-16',
encoding_errors='replace')
self.template = Template(self.getTemplate(), lookup=mylookup,
module_directory=tempfile.gettempdir(),
input_encoding='utf-16',
output_encoding='utf-16',
encoding_errors='replace')
现在可以正常工作了。看起来utf-8不是个好选择(或者说我保存模板时没能用utf-8),但我无法解释为什么在eclipse/pydev中能正常工作。