如何让"python -m venv"直接安装最新的pip版本

28
在编译新版本的Python时,我会下载并运行get-pip.py来安装最新版本的pip到Python可执行文件的旁边。
$ /opt/python/3.7.0/bin/python --version
Python 3.7.0
$ /opt/python/3.7.0/bin/pip --version
pip 18.0 from /opt/python/3.7.0/lib/python3.7/site-packages/pip (python 3.7)

我在/opt/python下有25个这样的版本,尽管我主要使用每个未到达EOL的主要.次要版本的最新的5个版本。为了设置一个环境,我过去会运行virtualenvvirtualenvutils并使用-p /opt/python/X.Y.Z/bin/python选项来获取具有特定版本的虚拟环境。

使用Python 3.7时,这将给出imp模块弃用警告:

$ virtualenv -p /opt/python/3.7.0/bin/python /tmp/py37virtualenv
Running virtualenv with interpreter /opt/python/3.7.0/bin/python
Using base prefix '/opt/python/3.7.0'
/opt/util/virtualenvutils/lib/python3.6/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
New python executable in /tmp/py37virtualenv/bin/python
Installing setuptools, pip, wheel...done.

我对这个问题在 virtualenv 中得到解决的希望不大,因为至少从 2014 年以来就已经出现了 PendingDeprecationWarning (可以从这个问题的输出中看到

在研究将 virtualenv 替换为 python -m venv 时,在 virtualenvutils 中创建了一个基于 venv 的虚拟环境:

$ /opt/python/3.7.0/bin/python -m venv /tmp/py37venv
$ /tmp/py37venv/bin/pip --version
pip 10.0.1 from /tmp/py37venv/lib/python3.7/site-packages/pip (python 3.7)

您正在使用旧版本的pip! 如果您继续使用,您将会收到以下提示:

您正在使用pip版本10.0.1,可是最新的版本是18.0。
您应该考虑通过执行'pip install --upgrade pip'命令进行升级

在使用virtualenv创建的虚拟环境中,您将立即获得最新版本:

$ /tmp/py37virtualenv/bin/pip --version
pip 18.0 from /tmp/py37virtualenv/lib/python3.7/site-packages/pip (python 3.7)

我可以运行一个创建后的步骤:

/tmp/py37venv/bin/pip install -U --disable-pip-version-check pip 

这将需要额外的时间。而且,如果有一些针对 pip 的安全更新,这将意味着运行非安全版本来获取安全版本,造成攻击的理想机会。

使用 virtualenvutils 很容易执行多个步骤创建一个没有 pip 的虚拟环境,然后使用 get-pip.py 添加 pip。但是,从命令行执行并不那么简单:

$ /opt/python/3.7.0/bin/python -m venv --without-pip /tmp/py37venvnopip
$ /tmp/py37venvnopip/bin/python -c "from  urllib.request import urlopen; response = urlopen('https://bootstrap.pypa.io/get-pip'); open('/tmp/tmp_get_pip.py', 'w').write(response.read())"
$ /opt/python/3.7.0/bin/python /tmp/tmp_get_pip.py
......
$ /opt/python/3.7.0/bin/pip --version

/opt/python/3.7.0/lib/python3.7/site-packages/pip 中的 pip 18.0 版本是什么原因导致了 /opt/python/3.7.0/bin/python -m venv 使用旧版本的 pip?这是在发布3.7.0时可用的版本吗?

我该如何更新我的安装,在不还原脚本,别名或使用多个命令的情况下以某种方式更新 /opt/python/3.7.0 下的内容,从而使用 /opt/python/3.7.0/bin/python -m venv 创建一个带有最新 pip 版本的虚拟环境?显然,在 /opt/python/3.7.0 下安装最新的 pip 是不够的。

有两个捆绑的 wheels:

/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/setuptools-39.0.1-py2.py3-none-any.whl
/opt/python/3.7.0/lib/python3.7/ensurepip/_bundled/pip-10.0.1-py2.py3-none-any.whl

我怀疑我需要更新它们。有没有比手动更新更好的方法?带/some/python -m venv选项会更好。

(运行/some/python -m ensurepip --upgrade不能解决问题)


运行已废弃的/opt/python/3.7.0/bin/pyvenv会出现相同的旧pip版本问题。


1
看起来 https://bugs.python.org/issue30628 涉及到这个问题,但是该网站目前无法访问。 - Anthon
1
为了能够无警告地继续进行,我最终创建了一个单文件实用程序,它会下载 _bundled 中的新的 .whl 文件并更新 ensurepip/__init__.py。此外,该实用程序还可在 PyPI 上获取。 - Anthon
3
手动升级请运行以下命令: python -m pip install --upgrade pip setuptools wheel 不要只运行 pip install,因为它会创建一个 shebang 到你默认的 pip。 - dre-hh
4个回答

18
关键是不要安装捆绑的pip版本(几乎总是过时的),而是使用它从互联网上安装最新版本。标准库venv提供了一个--without-pip标志,可以在这里提供帮助。创建没有pip的虚拟环境后,您可以直接执行ensurepip的wheel,这比安装pip然后立即使用相同的pip安装程序卸载自身并升级更快,也不会有hacky的问题。代码胜过言辞,因此这里有一个示例bash函数来描述我所描述的过程:
# in ~/.bashrc or wherever

function ve() {
    local py="python3"
    if [ ! -d ./.venv ]; then
        echo "creating venv..."
        if ! $py -m venv .venv --prompt=$(basename $PWD) --without-pip; then
            echo "ERROR: Problem creating venv" >&2
            return 1
        else
            local whl=$($py -c "import pathlib, ensurepip; whl = list(pathlib.Path(ensurepip.__path__[0]).glob('_bundled/pip*.whl'))[0]; print(whl)")
            echo "boostrapping pip using $whl"
            .venv/bin/python $whl/pip install --upgrade pip setuptools wheel
            source .venv/bin/activate
        fi
    else
        source .venv/bin/activate
    fi
}

如果您更喜欢旧项目virtualenv,它也提供了--no-pip--no-setuptools--no-wheel标志,在Python 2.7上实现相同的功能。
注意:Python 3.9+的venv选项中有一个--upgrade-deps选项,可以在创建环境后立即升级pip/setuptools版本,请参见https://bugs.python.org/issue34556获取更多信息。我不使用此选项,因为它仍然通过安装/卸载供应商版本进行不必要的安装,这比直接使用上面显示的最新版本创建环境的方法差。

有趣的是,几个月前我写了一个名为 ve 的工具,可以做类似的事情。看来我不是唯一一个想要解决在所有虚拟环境中更新 pip 的不便之处的人。在 Python 3.9 发布之前应该把它完善一下... - sinoroc

3

我使用 upgrade-ensurepip 工具更新 ensurepip 包中的 pipsetuptools wheel 文件。虽然这种方法不如通过 pip 升级 ensurepip 更加优雅,但它仍然比手动升级要好。

https://pypi.org/project/upgrade-ensurepip/


4
我不喜欢用户随意更改捆绑的pip版本的想法(例如,它们可能是由root拥有并从操作系统软件包管理器安装的,如果您更改这些文件,将会使您的操作系统混乱)。 - wim
好的观点。我已经转而使用conda,现在我不必再处理这个问题了。 - Irving Moy

3
这是一个预期行为。 python -m venv 调用 python -m ensurepip 来安装 pip,并且这个答案表明,即使使用 --upgrade 选项,ensurepip 也只会安装捆绑的版本。目前没有官方选项来更新捆绑的 pipsetuptools
我也没有好的解决方法,因为这只是设计上的行为。我想给出两个建议:
  1. 使用 pipenv。它非常好用!而且它将成为未来的官方包管理器(尽管目前与当前 Pypi 的结构有很大问题。简而言之,一个包管理器只能通过下载整个包才能确定依赖关系。这给构建依赖关系图带来了巨大的困难)。

  2. 实现自定义的 EnvBuilder,实际上有一个官方示例。在示例中,还使用了 get-pip.py 来安装最新的 pip


感谢提供envbuilder链接,我会研究一下。对于我的用例,pipenvvirtualenvutils有很多重叠之处,但我仍然需要在/usr/local/bin中创建到实际可执行文件的链接。pipenv宣布使用Pipfile,并且每个项目根目录中都有另一个配置文件(还是多余的TOML格式),这使得它在长期内变得不那么有趣。 - Anthon
pipenv 不仅仅是 virtualenvutils 的重叠,而是将 pipvirtualenv 结合在一起,这意味着它完全覆盖了这两个工具。此外,如果您决定使用 pipenv,您就不再需要 requirements.txt 了 :-) 实际上,我选择 pipenv 的最大原因是它可以真正地管理依赖关系,而不仅仅是像 pip freeze > requirements.txt 那样列出它们。例如,您删除 Pipfile 中的一个顶级依赖项,然后运行 pipenv clean,它将自动删除所有未使用的子依赖项。总之,这取决于个人观点 :-) - Sraw
virtualenvutils 不是 virtualenv,它比 virtualenv 做的更多。由于我已经摆脱了需要 requirements.txt(以及 setup.cfgMakefiletox.inisetup.pydistbuild.tox 等等)的需求,所以 pipenv 放在那里的任何东西都只会再次混乱开发树。因此,对我来说,pipenv 只是额外的工作而没有好处。每当我更改依赖项以删除某些内容时,我会保存,然后从头开始重新安装一个实用程序和它的虚拟环境(使用的 Python 微版本肯定会有新的),以获取正确的依赖关系(如果无法解决,则恢复)。 - Anthon
3
我认为这些天可能不应该推荐使用pipenv。不过,扩展EnvBuilder似乎很有趣。 - wim
官方示例已经失效了,例如setuptools的下载链接已经失效。一个更简单的替代方法是在post_setup中运行pip install --upgrade pip命令。 - Sigmatics
显示剩余2条评论

-1
如果你正在使用virtualenvwrapper,你可以将升级命令放在postmkvirtualenv脚本中。它默认在~/.virtualenvs文件夹中。
每次创建新的虚拟环境时,pip会被升级。 我知道这不是完美的解决方案,但它是有效的。
# vim ~/.virtualenvs/postmkvirtualenv 

pip install --upgrade pip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接