Python: Mac OS X での locale.getpreferredencoding()
(追記)この記事に載せているパッチよりも Apple によるロケール周りの変更点を Python 2.5.1 にも適用するのパッチを使った方がよさそうです。Mac OS X 標準の Python との互換性があります。
TracInstall に従って、Mac OS X で Trac を動かそうとしている。以前試したときは頓挫したのだが、今回は Python を含むすべてのライブラリを一からインストールして、じっくりやってみることにした。
とりあえず、tracd
を起動するところまでは問題なくいったのだけれど、URL にアクセスしてみると早速こんなエラーが。
Traceback (most recent call last):
File "/path/to/trac/lib/python2.5/site-packages/trac/web/main.py", line 406, in dispatch_request
dispatcher.dispatch(req)
File "/path/to/trac/lib/python2.5/site-packages/trac/web/main.py", line 207, in dispatch
populate_hdf(req.hdf, self.env, req)
File "/path/to/trac/lib/python2.5/site-packages/trac/web/main.py", line 77, in populate_hdf
'time': format_datetime(),
File "/path/to/trac/lib/python2.5/site-packages/trac/util/datefmt.py", line 65, in format_datetime
return unicode(text, encoding, 'replace')
LookupError: unknown encoding: X-MAC-JAPANESE
じっくりやってみる、と書いた矢先にくじけそうになりましたが、諦めずに原因を追ってみますね。
その前に、今回試したバージョンは、
- Python 2.5.1
- Trac 0.10.4
です。
ソースコードを読む
スタックトレースから例外の発生箇所は簡単に分かるので、ソースコードを読んでみる (/trac/util/datefmt.py
) 。
def format_datetime(t=None, format='%x %X', gmt=False):
if t is None:
t = time.time()
if not isinstance(t, (list, tuple, time.struct_time)):
if gmt:
t = time.gmtime(float(t))
else:
t = time.localtime(float(t))
text = time.strftime(format, t)
encoding = locale.getpreferredencoding() or sys.getdefaultencoding()
if sys.platform != 'win32':
encoding = locale.getlocale(locale.LC_TIME)[1] or encoding
# the above is broken on win32, e.g. we'd get '437' instead of 'cp437'
return unicode(text, encoding, 'replace')
今回のエラーはビルトイン関数の unicode
が X-MAC-JAPANESE
エンコーディングをサポートしていないのが原因のようだ。X-MAC-JAPANESE
は Mac ユーザにとってはお馴染みの MacJapanese(ほぼ Shift-JIS)のことだろう。たしかにリファレンスの 4.8.3 Standard Encodings を読んでもそれらしきエンコーディングがない。
となると、考えられる解決方法はふたつ
- MacJapanese をサポートするコーデックを追加
- そもそも、
locale.getpreferredencoding()
でサポートしていないエンコーディングを返さない。この場合はshift_jis
を返してしまっていい気がする
まあ、1. が真っ当なんだろうけど、2. でも問題ないというか、むしろ、getpreferredencoding
という名前のメソッドがサポートされていないエンコーディングを返すよりいいんじゃないだろうか。
_localmodule.c を変更
とりあえず、Python 2.5.1 の Modules/_localemodule.c
で、X-MAC-JAPANESE
の場合は shift_jis
を返すように変更してみた。
--- Modules/_localemodule.c.orig 2007-07-19 02:47:21.000000000 +0900
+++ Modules/_localemodule.c 2007-07-19 03:17:28.000000000 +0900
@@ -426,6 +426,7 @@
case kCFStringEncodingMacCyrillic: return "mac-cyrillic";
case kCFStringEncodingMacTurkish: return "mac-turkish";
case kCFStringEncodingMacIcelandic: return "mac-icelandic";
+ case kCFStringEncodingMacJapanese: return "shift_jis";
/* XXX which one is mac-latin2? */
}
if (!name) {
ちなみに、このへんのコードでは Mac OS X のフレームワークである Core Foundation が利用されている。