This site is an archive of ama.ne.jp.

SupervisorとTornadoの相性の話

Supervisorの上で動くTornadoに日本語パスを渡すとコケることがあったので、調べてみることにした。

例外はこんな感じである。osモジュールで問題が起こってるっぽい。今のところ非ASCIIを含むURLが渡されるハンドラはStaticFileHandlerだけなので、ファイル情報の問い合わせで大破していることになる。

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/site-packages/tornado/web.py", line 1445, in _execute
    result = yield result
  File "/usr/local/lib/python3.5/site-packages/tornado/gen.py", line 1008, in run
    value = future.result()
  File "/usr/local/lib/python3.5/site-packages/tornado/concurrent.py", line 232, in result
    raise_exc_info(self._exc_info)
  File "<string>", line 3, in raise_exc_info
  File "/usr/local/lib/python3.5/site-packages/tornado/gen.py", line 282, in wrapper
    yielded = next(result)
  File "/usr/local/lib/python3.5/site-packages/tornado/web.py", line 2265, in get
    self.root, absolute_path)
  File "/usr/local/lib/python3.5/site-packages/tornado/web.py", line 2446, in validate_absolute_path
    if (os.path.isdir(absolute_path) and
  File "/usr/local/lib/python3.5/genericpath.py", line 42, in isdir
    st = os.stat(s)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 39-40: ordinal not in range(128)

日本語パスを含んでいるだけでosモジュールの関数が例外を上げる……? インタラクティブシェルでは再現しなかったので、TornadoかTornadoをデーモン化しているSupervisorの問題だろう。

osモジュールの関数は、設定されたlocaleを元にファイル名のエンコードを行っている。

Python 標準ライブラリ 16.1. os

Python では、ファイル名、コマンドライン引数、および環境変数を表すのに文字列型を使用します。一部のシステムでは、これらをオペレーティングシステムに渡す前に、文字列からバイト列へ、またはその逆のデコードが必要です。Python はこの変換行うためにファイルシステムのエンコーディングを使用します (sys.getfilesystemencoding() 参照)。

Python 標準ライブラリ 28.1. sys

sys.getfilesystemencoding()
Unicode ファイル名をシステムのファイル名に変換する際に使用するエンコード名を返します。返り値ははオペレーティングシステムに依存します:

Unix では、エンコーディングはユーザー設定 (nl_langinfo(CODESET) の結果) に従います。

調べたところ、問題はSupervisorがTornadoに適切なlocaleを与えていないという点にあると分かった。

UnicodeEncodeError: 'ascii' codec can't encode character

解決策としては、supervisorの設定ファイルに以下のような環境変数の設定を加えればよさそう。

environment=LANG="en_US.utf8", LC_ALL="en_US.UTF-8", LC_LANG="en_US.UTF-8"

設定後は無事にアクセスできるようになった。よかったね。

(2016-11-05) 同じような問題がDockerの中で動くTornadoなどでも起こりました。これはもう素直にlocaleを設定すればいいです。