PIP 10 问题 "module 'pip' has no attribute 'main'"

#Python @Python
版权声明:所有博客文章除特殊声明外均为原创,允许转载,但要求注明出处。

最近有不少朋友反映用 PIP 更新包时遇到了问题,典型场景之一是在 PyCharm 中更新软件包,可能遇到如下的出错信息(截屏来自 JetBrains 社区):

PyCharm 截图

其实从图中的 Traceback 就能看出,问题出在 PyCharm 试图调用 pip 模块的方法 main,而 pip 模块却没有定义这个方法。那么是不是 PyCharm 自身的 bug 呢?想一想也觉得应该不是。毕竟 PyCharm 的模块管理功能已经面世很久了,经过大量用户使用,不太可能存在这么严重的问题。那么我们不妨自己检查一下,这个方法是否真的不存在:

测试 PIP main

这就有意思了,pip.main 果然是不存在的。可是为什么 PyCharm 会去调用一个不存在的方法?从常理来说是讲不通的,然而这个明显矛盾的现象会让人不仅猜想,会不会是 pip 不同版本之间接口变化导致的?

大胆假设,小心求证。研究 pip 源码有点麻烦,因为库比较大,版本又相当多。不过有一个取巧的方法:注意到当前 pip 的版本是 10, 而按照一般规范,相同大版本是不应该有 API 变更的,那么我们不妨建两个虚拟环境,将 PIP 库分别设置到 9/10 版本,比较它们是否有所差异。

mkdir p9
cd p9
virtualenv venv
venv\scripts\activate
python -m pip install pip==9.0.3

这里需要注意的一点是,因为我们目前的 PIP 已经是 v10 了,要在虚拟化境中降级的话,需要使用 python -m pip 的形式,而不能直接使用 pip 命令。

然后用同样办法建一个 PIP 10 的虚拟环境,比较 venv\Lib\site-packages\pip__init__.py:

比较 PIP

至此真相大白了,PIP模块版本 v10 和 v9 相比,做了相当大的改动(主文件基本上是空的),而 v9 的确有一个 main 方法。所以上述问题的确是版本不兼容引起的。

需要说明的是,PyCharm 官方已经在最近的版本中修正了这个问题,详见 PyCharm Issue PY-29395,所以你如果同样在 PyCharm 中遇到这个问题,请更新你的软件。

另外一个类似的问题是,在 Debian 系的 Linux 系统中,如果你是通过 APT 安装的 PIP,然后又通过 PIP 更新自身,那么你可能会看到同样的错误信息。这是因为 PIP 的启动脚本是 Debian 团队而不是 PIP 团队维护的:

PIP Debian 脚本

这种情况目前似乎还没有非常完美的解决方案,不过有两个临时的办法:

  1. 可以用 python -m pip 替换 pip 命令;
  2. 也可以用虚拟环境 virtualenv 或 pyenv。

当然,我们希望将来 Debian 团队为我们提供一个升级的脚本。