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