Genshiの文字化け
開発したWebアプリケーションで時折文字化けが起こるので調べてみたら原因が分かった。多分Genshiのバグだと思う。
- HTMLParser.parse() in genshi/input.py:
def _generate(): try: bufsize = 4 * 1024 # 4K done = False while 1: while not done and len(self._queue) == 0: data = self.source.read(bufsize)
これだ!
検証コード
>>> from genshi.input import HTML >>> unicode_text = u"あ" * 5000 >>> [(i, c) for i, c in enumerate(str(HTML(unicode_text)).decode('utf-8')) if c != u"あ"] [] >>> utf8_text = unicode_text.encode('utf-8') >>> [(i, c) for i, c in enumerate(str(HTML(utf8_text)).decode('utf-8')) if c != u"あ"] [(1365, u'\ufffd'), (1366, u'\ufffd'), (1367, u'\ufffd'), (2732, u'\ufffd'), (2733, u'\ufffd')]
utf-8を渡した場合、バッファ境界でマルチバイト文字の「泣き別れ」が起こっていることが分かる。
- 1365*3=4095=4K
- 2732*3=8196=8K
補足
文字化けはToscaWidgetsを使った一部の編集画面でのみ起こっていて、どうやら
- WidgetRepeater.update_params() in toscawidgets/core.py
outputs = [ w.render(v_f(w), **a_f(w)) for w in d['children'][:d.repetitions] ] d["output"] = '\n'.join(o for o in outputs if o)
ここでutf-8文字列化しているために上記のGenshiのバグをピンポイントで突いてしまったようだ。
とりあえずの回避策:
from toscawidgets.widgets.forms import * _FormFieldRepeater = FormFieldRepeater class FormFieldRepeater(_FormFieldRepeater): def update_params(self, d): super(_FormFieldRepeater, self).update_params(d) # Genshi の潜在的なバグを回避するために, 強制的に unicode に変換する d["output"] = d["output"].decode('utf-8')