Linux

【Ubuntu】pip install –upgrade pip コマンドを実行すると、その後、ImportError: cannot import name main というエラーが発生する場合の対応方法

投稿日:2018年6月28日 更新日:

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つのツールで管理している状況では、何かしら問題が起こるだろうなと思うのが普通の感覚なのではないでしょうか。

参考

3. お勧めな対策

基本方針

いろいろな対策方法があると思いますが、私のオススメは、

pip の導入や更新には、apt のみを使う

です。

つまり、以下のように 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しかアクセスできません。

4. おわりに

世界的によく使われているであろう、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 コマンドがインストールされます(実際は、pip2pip2.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/ を追加しないようにする必要があります。

B. 参考

📂-Linux

執筆者:labo


  1. 金田篤実 より:

    ありがとうございました。助かりました!

comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

CentOS

CentOS 6 での yum update エラーに対応しました

問題 先日、CentOS 6.9 で yum update したところ、以下のエラーが発生しました。 https://ca.mirror.babylon.network/remi/enterprise …

Linux

ドキュメントルートに chmod コマンドを実行する際、指定すると便利なモード引数

目次1. はじめに2. chmod に関する前提知識3. ディレクトリは rwxr-xr-x ファイルは rw-r–r– にする解説4. ディレクトリは rwxrwxr-x ファイルは rw-rw …

CentOS

CentOS 6 で yum update した時、remi-php70 レポジトリ内のパッケージの依存性解決ができない場合の解決方法

目次現象解決方法 その1解決方法 その2解決方法 その3まとめ参考 現象 remi-php70 リポジトリを使っている CentOS 6 の環境で PHP関連のパッケージを更新しようと思い、以下のコマ …

Linux

Ubuntu ではユーザー名に大文字が使えません(デフォルトでは)

Ubuntu で ユーザーを追加するには adduser というコマンドを使います。 例えば、”foo” という名前のユーザーを追加するには、以下のコマンドになります。 $ a …

Linux

シェルスクリプト (Bash) では組み込みコマンド set を活用しましょう

Linux や MacOS、Windows の WSL でシェルスクリプト(Bash)を書く場合は、組み込みコマンド set を活用しましょう。より完成度の高い処理を書くことができます。 スポンサード …