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. 対処法その1

pyenv で導入した python を使えば、本記事のエラーを忘れることができます😅。

pyenv については、以下の記事を参考にしてください。

Python

Pythonのバージョンを切り替える pyenv の使い方

2020.04.06

4. 対処法その2

基本方針

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

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しかアクセスできません。

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 コマンドがインストールされます(実際は、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

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

関連記事

Linux

【Linux】 CentOS のマニュアル

CentOS は、RHEL (Red Hat Enterprise Linux)のソースコードから商標や商用パッケージ等を除去してリビルドした RHELクローンです。 マニュアルを見る場合は、RHEL …

docker

docker run コマンドのパターン覚書

docker run コマンドのパターン覚書です。

Linux

sed コマンドの基本形式

sed コマンドの基本的な指定形式について説明します。

Linux

指定した条件にマッチするファイルを検索する find コマンド

find コマンドについて説明します。 ※ 本ページで扱うのは、find (GNU findutils) 4.7.0-git です。 目次1. find コマンドの使い方式 (EXPRESSION)式 …

Linux

Linux のコマンドラインで発生するビープ音を消す

Linux のコマンドでビープ音を消す方法を紹介します。