Windowsで作業していたら pip install
や flake8
, mypy
等いろんなところで UnicodeDecodeError
が出て困ったので調べた。
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 23 2018, 23:31:17) [MSC v.1916 32 bit (Intel)] on win32
調べてみてわかったのだけど、昔より悪くなってますね・・・
結論: モンキーパッチで対抗だ(無保証)
%APPDATA%\Python\Python36\site-packages\usercustomize.py
に下記のコードを書いて、 encoding
引数なしの open
の挙動を変えた。
import builtins
__original = open
def __open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
# ここでprintデバッグすると状況が分かる
if 'b' not in mode and not encoding:
encoding = 'utf-8'
return __original(file, mode, buffering, encoding, errors, newline, closefd, opener)
builtins.open = __open
'b' not in mode
というのがポイントでひと手間かかった。
Windowsが cp932
止めるまで耐え忍ぶしかない。
調査過程
エラー発生
UnicodeDecodeError: 'cp932' codec can't decode byte 0x83
以前遭遇したことがあるのでデフォルトエンコーディングを変更する方向で調べる
sys.setdefaultencoding は既に死んでいる
import sys
reload(sys) # 無い(importlib.reload)
sys.setdefaultencoding("utf-8") # 無い(たぶん python-3.3 以降)
しかし、
AttributeError: module 'sys' has no attribute 'setdefaultencoding'
- https://stackoverflow.com/questions/3828723/why-should-we-not-use-sys-setdefaultencodingutf-8-in-a-py-script
- https://bugs.python.org/issue9549 # python-3.3 2012-09
setdefaultencoding
は、以前から使うなって言われていて完全に無くなった様子。
reload
で使えていたのが救済措置だったということですね。
環境変数PYTHONIOENCODING
PYTHONIOENCODING="UTF-8"
だめです。標準入出力用らしい。
localeが関係あるぽい
openのencoding引数無しのときは locale.getpreferredencoding
が使われるらしい
>>> import locale
>>> locale.getpreferredencoding()
'cp932'
たしかに
Windowsのpythonで locale.getpreferredencoding() を変える方法は無い
無いんだなこれが。
>>> locale.setlocale(locale.LC_ALL, 'ja_JP.UTF-8')
'ja_JP.UTF-8'
>>> locale.getpreferredencoding()
'cp932'
ぐぬぬ
外側で LANG=ja_JP.UTF-8
とか chcp 65001
とかやっても変わりません。
モンキーパッチ作戦その1
import locale
def getpreferredencoding():
return 'utf-8'
locale.getpreferredencoding = getpreferredencoding
>>> import locale
>>> locale.getpreferredencoding()
'utf-8'
いけるか?と思ったが encoding
引数無しの open
の挙動が変わりませんでした。
で、最初の open
を置き換える方法に辿り着いた。