PySQLite2.4.1+でマルチバイトを扱う時の注意点

うちのMacで、MailArchiveExtPluginTracに日本語メールを取り込むと、以下のエラーが発生するようになってしまった。

ProgrammingError: You must not use 8-bit bytestrings unless you use
a text_factory that can interpret 8-bit bytestrings (like text_factory = str).
It is highly recommended that you instead just sitch your application
to Unicode strings.

以前は動いてた気がするので、Snow Leopardに入れ替えた影響かなぁと思いつつ調べてみた。

上記エラーメッセージでググるとそこそこひっかかります。

エラーメッセージにも書いてあるが、Unicode文字列(Unicode strings)を使ってないのが原因らしい。確かに、MailArchiveExtPluginのエラー発生箇所は以下で、Unicode文字列をUTF-8エンコードしてstr型(バイト列型)に変換し、PySQLiteに渡しているんだよね。

            cursor.execute("UPDATE mailarc SET "
                "category=%s, utcdate=%s, zoneoffset=%s, subject=%s,"
                "fromname=%s, fromaddr=%s, header=%s, text=%s, threadroot=%s, threadparent=%s "
                "WHERE messageid=%s",
                (self.category.encode('utf-8'),
                self.utcdate,
                self.zoneoffset,
                self.subject.encode('utf-8'), self.fromname.encode('utf-8'),
                self.fromaddr.encode('utf-8'), '', self.body.encode('utf-8'),
                self.thread_root, self.thread_parent,
                self.messageid))

さらに調べると、djangoのサイトにばっちし書いてある!

if Database.version_info >= (2,4,1): 
    # Starting in 2.4.1, the str type is not accepted anymore, therefore, 
    # we convert all str objects to Unicode 
    # As registering a adapter for a primitive type causes a small 
    # slow-down, this adapter is only registered for sqlite3 versions 
    # needing it. 
    Database.register_adapter(str, lambda s:s.decode('utf-8')) 

なるほどね、、まとめると

  • PySQL 2.4.1以降では、str型だとマルチバイトは弾くようになった
  • なので、Unicode文字列で送ってやる必要がある
  • 確かに、うちのMacはPySQL 2.4.1でした(>_