「pip install --upgrade pip
」コマンドを実行した後、pip
コマンドを実行すると「ImportError: cannot import name main」というエラーが発生する場合の対応方法について説明します。
目次
1. 現象
環境
- WSL (Windows Subsystem for Linux) の Ubuntu 16.04.4 LTS (Microsoft Store からインストール)
起きた現象
元々この環境には、python がインストールされていましたが、pip
は導入されていなかったため、python-pip を導入しました。
$ sudo apt install python-pip
そして、pip のバージョンを上げました。
$ pip install --upgrade pip
すると、pip
コマンドを実行する際、下記のエラーが発生するようになりました。
$ pip
Traceback (most recent call last):
File "/usr/bin/pip", line 9, in <module>
from pip import main
ImportError: cannot import name main
2. 原因
この問題の原因は、apt で最初にインストールした pip (バージョン 8.1.1) と、「pip install --upgrade pip
」というコマンドで後からインストールされる pip (バージョン 10.0.1) に互換性がないことです。これには、Python のライブラリパスの優先順位なども関係しています。
そもそも「apt で pip を導入」した後で、「pip自身 で pip を更新」するというのは、あまり良いやり方とは思えません。1つのものを 2つのツールで管理している状況では、何かしら問題が起こるだろうなと思うのが普通の感覚なのではないでしょうか。
参考
- 近況1 – 雑記
- pip install –upgrade pip (10.0.0) 後の奇妙な挙動について – 雑記
- 複数の対策方法が紹介されています。
3. 対処法その1
pyenv で導入した python を使えば、本記事のエラーを忘れることができます?。
pyenv については、以下の記事を参考にしてください。
4. 対処法その2
基本方針
いろいろな対策方法があると思いますが、私のオススメは、
です。
つまり、以下のように python-pip を導入するだけです。
$ sudo apt install python-pip
以下は実行しません。
$ pip install --upgrade pip
pip
コマンドを使うと、次のように「 pip
のバージョンが古いので、pip install --upgrade pip
を実行してバージョンを上げるとよいですよ」みたいなメッセージが表示されますが無視しましょう。
定期的に apt update
を実行してパッケージを更新していれば、いずれ python-pip レポジトリが更新され、ローカルの pip のバージョンが更新されます。そして、python-pip の pipバージョンが 10 以上になれば、「pip install --upgrade pip
」を実行しても問題なくなるはずです。
もし、既に「pip install --upgrade pip
」を実行している場合は、以下のコマンドで削除できます。(~/.local/
以下にインストールされたファイルが削除されます)
$ python -m pip uninstall pip
pip によるパッケージのインストール
そして、pip
コマンドで何かパッケージをインストールする場合は、以下のようにします。
(1) ユーザー用にパッケージをインストールする場合
$ pip install --user パッケージ名
~/.local/lib/
以下にパッケージがインストールされます。
(2) システム用にインストールする場合
$ sudo pip install パッケージ名
/usr/local/lib/
以下にパッケージがインストールされます。- インストールしたモジュールは、rootしかアクセスできません。
5. おわりに
世界的によく使われているであろう、Ubuntu, Python, pip といったメジャーなソフトウェアでも、こんな問題が起きてしまいます。面倒ですが、その都度調査しないといけません。
A. おまけ: Pythonのライブラリパスに ~/.local/lib/ を追加させない方法
今回の状況を少し整理してみましょう。
ユーザー名を foo として話しを進めます。
まず、
$ sudo apt install python-pip
このコマンドにより、
/usr/bin/pip
コマンドがインストールされます。/usr/lib/python2.7/dist-packages/
以下に pip (8.1.1) がインストールされます。
次に、
$ pip install --upgrade pip
このコマンドにより、
~/.local/bin/pip
コマンドがインストールされます(実際は、pip2
、pip2.7
もあります)。~/.local/lib/python2.7/site-packages/
以下に pip (10.0.1) がインストールされます。
この時点で、Pythonのライブラリパスには ~/.local/lib
以下のディレクトリが追加されます。
$ python -c 'import sys; print sys.path'
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/mnt/c/Users/foo/.local/lib/python2.7/site-packages', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
この出力内容を見やすくします。
‘/usr/lib/python2.7’
‘/usr/lib/python2.7/plat-x86_64-linux-gnu’
‘/usr/lib/python2.7/lib-tk’
‘/usr/lib/python2.7/lib-old’
‘/usr/lib/python2.7/lib-dynload’
‘/mnt/c/Users/foo/.local/lib/python2.7/site-packages’
‘/usr/local/lib/python2.7/dist-packages’
‘/usr/lib/python2.7/dist-packages’
※ /mnt/c/Users/foo/.local/lib/… は、 ~/.local/lib/… と同じパスです。
/mnt/c/Users/foo/.local/lib/… が、/usr/lib/… よりも先にきています。
ということなので、この環境で pip モジュールを使おうとすると、pip (10.0.1) の方が呼び出されます。
ですので、~/.local/bin/pip
を実行すれば問題ありません(こちらも 10.0.1 なので)。しかし、/usr/bin/pip
(バージョン 8.1.1) の方を実行すると、内部で呼び出される pip (10.0.1) と互換性がないためにエラーになります。
では、sudo
を付けて /usr/bin/pip
を実行すれば、/usr/lib/… にある pip (8.1.1) が呼び出されてエラーは起きないのではないか? と思うかもしれませんが、残念ながらこの場合も、/mnt/c/Users/foo/.local/lib/… にある pip (10.0.1) が呼び出されてエラーになります。
このあたり、少し不自然な動作であるように感じます。
Pythonのライブラリパスから、~/.local/lib/… を除こうと思ったら、python コマンドの -s
オプションを使うか、環境変数 PYTHONNOUSERSITE (もしくは PYTHONUSERBASE) を使う必要があります。
-s
オプションを使って、ライブラリパスを出力してみましょう。
$ python -s -c 'import sys; print sys.path'
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
この出力内容を見やすくします。
‘/usr/lib/python2.7’
‘/usr/lib/python2.7/plat-x86_64-linux-gnu’
‘/usr/lib/python2.7/lib-tk’
‘/usr/lib/python2.7/lib-old’
‘/usr/lib/python2.7/lib-dynload’
‘/usr/local/lib/python2.7/dist-packages’
‘/usr/lib/python2.7/dist-packages’
/mnt/c/Users/foo/.local/lib/… がなくなりました。
少し上の方で、
$ sudo pip install パッケージ名
でインストールしたパッケージは、/usr/local/lib/
以下にインストールされると書きましたが、「~/.local/lib/
以下にも同じパッケージが存在していて、/usr/local/lib/
以下にある方を呼び出したい場合」は、今書いたように、-s
オプションか 環境変数 PYTHONNOUSERSITE (もしくは PYTHONUSERBASE) を使って、ライブラリパスに ~/.local/lib/
を追加しないようにする必要があります。
ありがとうございました。助かりました!
コメントありがとうございます。
お役に立てて嬉しいです!