AmazonLinuxで作成したvirtualenvの環境でmarkupsafeを使おうとしたらImportErrorが発生した時の対処法

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

サーモン大好き、横山です。

今やってる作業で、 AmazonLinuxの virtualenv をそのまま利用すると、ImportErrorが発生して困ったことになりました。 その時対処した手順を紹介します。

発生環境

Amazon Linux EC2

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2016.09-release-notes/

python

$ python -V
Python 2.7.12

virtualenv

$ virtualenv --version
12.0.7

再現手順

virtualenvで環境作成し、pipでmarkupsafeをinstallし、 import markupsafe 行う

$ cd /tmp
$ virtualenv --python=/usr/bin/python27 venv
$ . venv/bin/activate
(venv)$ pip install markupsafe
You are using pip version 6.0.8, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting markupsafe
  Downloading MarkupSafe-0.23.tar.gz
Installing collected packages: markupsafe
  Running setup.py install for markupsafe
    building 'markupsafe._speedups' extension
    gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python2.7 -c markupsafe/_speedups.c -o build/temp.linux-x86_64-2.7/markupsafe/_speedups.o
    gcc -pthread -shared build/temp.linux-x86_64-2.7/markupsafe/_speedups.o -L/usr/lib64 -lpython2.7 -o build/lib.linux-x86_64-2.7/markupsafe/_speedups.so
Successfully installed markupsafe

$ python
Python 2.7.12 (default, Sep  1 2016, 22:14:00)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import markupsafe
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named markupsafe

事象の確認と原因

venv/lib64/python2.7/dist-packages の中にmarkupsafeは存在している。

(venv)$ ls venv/lib64/python2.7/dist-packages/
MarkupSafe-0.23-py2.7.egg-info  markupsafe

pip freeze には出てこない

(venv)$ pip freeze
You are using pip version 6.0.8, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

sys.path の中身を確認して見ると、 /tmp/venv/lib64/python2.7/dist-packages が含まれていない

(venv)$ python -c 'import sys;import pprint; pprint.pprint(sys.path)'
['',
 '/tmp/venv/local/lib64/python2.7/site-packages',
 '/tmp/venv/local/lib/python2.7/site-packages',
 '/tmp/venv/lib64/python2.7',
 '/tmp/venv/lib/python2.7',
 '/tmp/venv/lib64/python2.7/site-packages',
 '/tmp/venv/lib/python2.7/site-packages',
 '/tmp/venv/lib64/python2.7/lib-dynload',
 '/tmp/venv/local/lib/python2.7/dist-packages',
 '/tmp/venv/local/lib/python2.7/dist-packages',
 '/tmp/venv/lib/python2.7/dist-packages',
 '/usr/lib64/python2.7',
 '/usr/lib/python2.7']

sys.path/tmp/venv/lib64/python2.7/dist-packages を追加して、importすると成功します。

(venv)$ python
Python 2.7.12 (default, Sep  1 2016, 22:14:00)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import markupsafe
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named markupsafe
>>> import sys
>>> sys.path.append('/tmp/venv/lib64/python2.7/dist-packages')
>>> import markupsafe
>>>

どうやら、sys.pathに /tmp/venv/lib64/python2.7/dist-packages が含まれておらずimportに失敗するのが原因のようです。

解決方法

OS側のpipとvirtualenvを更新し、virtualenvの環境を作り直します。

(venv)$ deactivate
$ sudo -i
# pip install --upgrade pip
# pip install --upgrade virtualenv
# exit

参考: django - python virtualenv ImportError with celery and billiard - Stack Overflow

動作確認

上記再現手順を行ってもエラーが出ないことが確認できました。

$ cd /tmp
$ virtualenv --python=/usr/bin/python27 venv2 #先程作った環境とは別にvenv2を作成
$ . venv2/bin/activate
(venv2)$ pip install markupsafe
Collecting markupsafe
  Using cached MarkupSafe-0.23.tar.gz
Building wheels for collected packages: markupsafe
  Running setup.py bdist_wheel for markupsafe ... done
  Stored in directory: /home/ec2-user/.cache/pip/wheels/a3/fa/dc/0198eed9ad95489b8a4f45d14dd5d2aee3f8984e46862c5748
Successfully built markupsafe
Installing collected packages: markupsafe
Successfully installed markupsafe-0.23

(venv2)$ python
Python 2.7.12 (default, Sep  1 2016, 22:14:00)
[GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import markupsafe
>>>

pip freeze にも表示されます。

(venv2)$ pip freeze
MarkupSafe==0.23

sys.path にも /tmp/venv2/lib/python2.7/dist-packages が存在しませんが、 venv2/lib64venv2/lib へシンボリックリンクが貼られているので参照出来るようになってます。 ここでもう一度 ls -l venv の中を見てみると、アップグレード前の venv/lib64 はシンボリックリンクになっていません

(venv2)$ python -c 'import sys;import pprint; pprint.pprint(sys.path)'
['',
 '/tmp/venv2/lib/python27.zip',
 '/tmp/venv2/lib64/python2.7',
 '/tmp/venv2/lib64/python2.7/plat-linux2',
 '/tmp/venv2/lib64/python2.7/lib-tk',
 '/tmp/venv2/lib64/python2.7/lib-old',
 '/tmp/venv2/lib64/python2.7/lib-dynload',
 '/usr/lib64/python2.7',
 '/usr/lib/python2.7',
 '/tmp/venv2/local/lib/python2.7/site-packages',
 '/tmp/venv2/local/lib/python2.7/dist-packages',
 '/tmp/venv2/lib/python2.7/site-packages',
 '/tmp/venv2/local/lib/python2.7/dist-packages',
 '/tmp/venv2/lib/python2.7/dist-packages']

(venv2)$ ls -l venv2/
合計 20
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 06:03 bin
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 06:03 include
drwxrwxr-x 3 ec2-user ec2-user 4096  1月 18 06:03 lib
lrwxrwxrwx 1 ec2-user ec2-user    3  1月 18 06:03 lib64 -> lib
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 06:03 local
-rw-rw-r-- 1 ec2-user ec2-user   60  1月 18 06:04 pip-selfcheck.json

(venv2)$ ls -l venv/
合計 24
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 05:49 bin
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 05:49 include
drwxrwxr-x 3 ec2-user ec2-user 4096  1月 18 05:49 lib
drwxrwxr-x 3 ec2-user ec2-user 4096  1月 18 05:49 lib64
drwxrwxr-x 2 ec2-user ec2-user 4096  1月 18 05:49 local
-rw-rw-r-- 1 ec2-user ec2-user   60  1月 18 05:50 pip-selfcheck.json

まとめ

markupsafe のモジュールは、 大きいところですと Jinja2 を使用すると必要になるモジュールです。
Jinja2を使いたいのに、 markupsafe のImportErrorでわからんという時は参考にしてもらえば幸いです。