Python Tips: Mac で ValueError: unknown locale: UTF-8 のエラーを解決したい

Mac OS X のターミナルで Python を利用していると次のようなエラーが出ることがあります。

ValueError: unknown locale: UTF-8

エラーの長いバージョンは次のような形です。

Traceback (most recent call last):
  File "

<string>", line 1, in <module>
  File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/locale.py", line 560, in getdefaultlocale
    return _parse_localename(localename)
  File "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/locale.py", line 487, in _parse_localename
    raise ValueError('unknown locale: %s' % localename)
ValueError: unknown locale: UTF-8
</module></string>

今回はこの問題の解決方法を見ていきたいと思います。

この問題は私の場合は matplotlib を使っているときに遭遇しましたが、検索してみると結構多くの方が遭遇されていて、 matplotlib にかぎらずいろんな状況で発生するようです。 Python 以外でも多く発生しているようです。

まずは問題の原因から見ていきます(自分なりに調べて書いていますが、間違っていたらすみません・・・)。

原因

問題の原因は、ターミナルの環境変数の locale 周りの設定がまずいことのようです。

標準ライブラリ locale の中に getdefaultlocale() という関数があるのですが、これが呼び出されたときに、デフォルトのロケール情報を取得するために次の環境変数の値を見にいきます。

  • LC_ALL
  • LC_CTYPE
  • LANG
  • LANGUAGE

その際に、これらの変数の値として「 ja_JP.UTF-8 」といったフォーマットの文字列が入っていることが期待されているようです。

しかし、 Mac のターミナルで環境変数を確認してみると、次のようになっていたりします。

$ locale
LANG="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_CTYPE="UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_ALL=

この場合に次のようなことが起こります。

上のリストの上から順に値がチェックされますが、 Python は LC_ALL は空なのでスルーします。次に LC_CTYPE をチェックするとこれには値が入っているのでこれをロケール情報として利用しようとします。ただ、格納されている値が「 UTF-8 」という予想しないフォーマットなので、うまく処理できず例外を上げる形になります。

対策

対策の方向性は 2 通りあるようです。

  • 対策 A: 環境変数をセットする
  • 対策 B: ターミナルの設定を変える

対策 A: 環境変数をセットする

上述のとおり、最初に LC_ALL がチェックされるので、これに変数をセットしておけば OK のようです。例えば Bash を使っている場合は .bashrc の中に次の 1 行を追加します。

export LC_ALL=ja_JP.UTF-8

エラーが発生するかどうかは次のコマンドでかんたんにチェックできます。

$ python -c 'import locale; print(locale.getdefaultlocale());'

エラーが出なくなれば OK です。

ちなみに上のとおりに LC_ALL をセットしてもよいですが、 LANG の値をそのまま流用するなら次のとおりとなるでしょうか。こちらの方がスマートなような気がします。

export LC_ALL=$LANG

対策 B: ターミナルの設定を変える

もうひとつの対策方法はターミナルの設定を変える方法です。

Terminal の場合と iTerm の場合について説明します。

Terminal の場合は、設定の「 Preferences → Profiles → Advanced 」を開きます。「 Set locale environment variables on startup 」というチェックボックスを見つけて、そのチェックを外します。

Terminal

iTerm の場合も Terminal と同様です。設定の「 Preferences → Profiles → Terminal 」を開きます。「 Set locale variables automatically 」というチェックボックスを見つけて、そのチェックを外します。

iTerm

いずれも、設定を変更した後新しいセッションを開くと設定が反映された状態になるので、次のコマンドなどで確認します。

$ python -c 'import locale; print(locale.getdefaultlocale());'

私の場合は例外が出なくなりました。

ちなみにこの場合の locale コマンドの出力結果は次のとおりでした。

$ locale
LANG="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_CTYPE="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_ALL=

LC_CTYPE が他と同じ「 ja_JP.UTF-8 」のフォーマットになっていることがわかりますね。

この「 locale の変数を自動セットする機能」については他の部分にも影響する可能性があるので副作用には注意が必要ですが、個人的には A の対策よりも本質的でシンプルでよい感じがします。

以上です。

ご参考になれば幸いです。

参考