matplotlib 使おうとしたら No module named '_bz2' エラーで怒られた
matplotlib 使おうとしたら No module named '_bz2' エラーで怒られた.
環境構築でハマることが多いな...
動作環境
- CentOS 7
- Python 3.6.5
- matplotlib 2.2.2
背景
pipでmatplotlibのインストールは完了.
実際コードを動かそうとしたらコンソールに次のようなエラーが出た.
$ python app.py
Traceback (most recent call last):
File "app.py", line 3, in <module>
from matplotlib import pyplot
File "/home/vagrant/.anyenv/envs/pyenv/versions/3.6.5/lib/python3.6/site-packages/matplotlib/__init__.py", line 127, in <module>
from . import cbook
File "/home/vagrant/.anyenv/envs/pyenv/versions/3.6.5/lib/python3.6/site-packages/matplotlib/cbook/__init__.py", line 13, in <module>
import bz2
File "/home/vagrant/.anyenv/envs/pyenv/versions/3.6.5/lib/python3.6/bz2.py", line 23, in <module>
from _bz2 import BZ2Compressor, BZ2Decompressor
ModuleNotFoundError: No module named '_bz2'
_bz2
ってモジュールがないよ, と怒られてる.
ちなみに app.py
ファイル冒頭では次のようにいくつかのモジュールを呼び出している.
# app.py
import math
import numpy as np
from matplotlib import pyplot # <- ここでエラー
今回のエラーは matplotlib を呼び出したときに発生したもの.
解決手順
ググったらbug reportを発見.
This is a problem as _bz2 is not always installed, and not listed as a required dependency of matplotlib.
I am able to fix the issue easily by moving the import of bz2 back down
inside of the to_filehandle() function, or alternatively placing it inside a try/except block.
どうやら bz2 に依存してるっぽい.
この報告者の言う方法ではなく, それに答えてくれてる方の修正commitをgithubで確認.
それ通りに修正.
念の為対象ファイルのオリジナルをコピーしておく.
$ cd /home/vagrant/.anyenv/envs/pyenv/versions/3.6.5/lib/python3.6/site-packages/matplotlib/cbook/
# backup
$ cp __init__.py __init__.py.org
# 確認
$ ls -lah | grep -i init
-rw-rw-r-- 1 vagrant vagrant 86K May 25 00:21 __init__.py
-rw-rw-r-- 1 vagrant vagrant 86K May 26 15:46 __init__.py.org
ok.
じゃあ変更するか.
# /matplotlib/cbook/__init__.py
# 中略
def to_filehandle(fname, flag='rU', return_opened=False, encoding=None):
"""
*fname* can be an `os.PathLike` or a file handle. Support for gzipped
files is automatic, if the filename ends in .gz. *flag* is a
read/write flag for :func:`file`
"""
if hasattr(os, "PathLike") and isinstance(fname, os.PathLike):
return to_filehandle(
os.fspath(fname),
flag=flag, return_opened=return_opened, encoding=encoding)
if isinstance(fname, six.string_types):
if fname.endswith('.gz'):
# get rid of 'U' in flag for gzipped files.
flag = flag.replace('U', '')
fh = gzip.open(fname, flag)
elif fname.endswith('.bz2'):
import bz2 # file冒頭のimportをここで宣言するように改修
# get rid of 'U' in flag for bz2 files
flag = flag.replace('U', '')
fh = bz2.BZ2File(fname, flag)
else:
fh = io.open(fname, flag, encoding=encoding)
opened = True
elif hasattr(fname, 'seek'):
fh = fname
opened = False
else:
raise ValueError('fname must be a PathLike or file handle')
if return_opened:
return fh, opened
return fh
# 以下 略
↑このファイル内で to_filehandle()
が呼ばれている.
その中に, ファイル冒頭でimportされている bz2 を移動.
移動先は elif fname.endswith('.bz2'):
直下.
ここまでできたら動作確認.
>>> import matplotlib
>>>
ちゃんと読めてる.
これでmatplotlibが使えるね.
今回は以上.