Windows
Python3

最近のUnicodeDecodeError

Windowsで作業していたら pip installflake8, 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'

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


usercustomize.py

import locale

def getpreferredencoding():
return 'utf-8'
locale.getpreferredencoding = getpreferredencoding


>>> import locale

>>> locale.getpreferredencoding()
'utf-8'

いけるか?と思ったが encoding 引数無しの open の挙動が変わりませんでした。

で、最初の open を置き換える方法に辿り着いた。


参考になりました