Как работать с unicode в mako?
Я постоянно получаю эту ошибку с помощью 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 -*-
и, внутри них, все строки costant имеют префикс "u".
Я знаю, что параметр self.stuff содержит строки unicode, но способ, которым я создаю объекты mako, должен позаботиться об этом (в противном случае эти аргументы хороши для?).
Есть ли что-то, что я забыл сделать?
Еще один вопрос: какая точка encoding_errors = 'replace'?
= РЕДАКТИРОВАТЬ =
Я оставил только одну строку юникода, и это трассировка:
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)
Ответы
Ответ 1
Наконец, я сохранил свои шаблоны в unicode, фактически (я думаю) utf-16 вместо utf-8. их размер на диске удвоился, и mako начал жаловаться на "CompileException (" Unicode decode operation encoding "utf-8" bla bla ", поэтому я изменил первую строку во всех из них:
## -*- 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.
Ответ 2
Для гуглеров:
Mako создает исключение mako.exceptions.CompileException: Unicode decode operation of encoding 'ascii' failed in file
и т.д., когда ваш файл шаблона воспринимает символы не-ascii и когда спецификация Unicode не записывается в файл. Вам нужно вручную добавить спецификацию (это делается не автоматически, по крайней мере в моем текстовом редакторе), так что это:
$file test.htm
test.htm: HTML document, UTF-8 Unicode text
становится следующим:
$file test.htm
test.htm: HTML document, UTF-8 Unicode (with BOM) text
Ответ 3
Ни одно из этих предложений (включая принятый ответ) не работает во всех случаях, особенно там, где шаблон mako создает контент (например, ${value | n}), где значение содержит символы не ascii.
Это потому, что по умолчанию mako обертывает unicode (foo) вокруг любых значений в сгенерированных скомпилированных шаблонах, что все равно приведет к:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 0: ordinal not in range(128)
Единственный верный способ сделать mako-дескриптор unicode в python2 - заменить обработчик по умолчанию ('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)