20
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

最近のUnicodeDecodeError

Last updated at Posted at 2019-04-20

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 を置き換える方法に辿り着いた。

参考になりました

20
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?