title: SupervisorとTornadoの相性の話
author: Amane Katagiri
summary: pythonのosモジュールが狂う
date: 2016-04-03T07:36:00+09:00
modified: 2016-11-05T02:35:00+09:00
category: tech
license: CC BY 4.0
rating: sfw
ai_summary: Supervisor上で稼働するTornadoにおいて、日本語を含むファイルパスへアクセスした際に発生するUnicodeEncodeErrorの原因と解決策をまとめています。エラーの原因は、Supervisorが適切なロケールをプロセスに渡さないためにPythonのファイルシステムエンコーディングがASCIIになってしまうことです。対策として、Supervisorの設定にUTF-8の環境変数を追加する方法を紹介しています。
ai_keywords: Tornado, Supervisor, UnicodeEncodeError, Python, ロケール, UTF-8, 環境変数, 日本語パス, StaticFileHandler, トラブルシューティング

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

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

```python
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](http://supervisord.org/)の問題だろう。

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

[Python 標準ライブラリ 16.1. os](http://docs.python.jp/3.3/library/os.html)

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

[Python 標準ライブラリ 28.1. sys](http://docs.python.jp/3.3/library/sys.html#sys.getfilesystemencoding)

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

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

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

[UnicodeEncodeError: 'ascii' codec can't encode character](http://stackoverflow.com/questions/3715865/unicodeencodeerror-ascii-codec-cant-encode-character "UnicodeEncodeError: 'ascii' codec can't encode character")

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

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

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

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