是否可以使用pip一次性升级所有Python包?

注意:官方问题跟踪器上对此有一个功能请求。


当前回答

拉玛纳的回答对我来说是最好的,但我不得不补充几点:

import pip
for dist in pip.get_installed_distributions():
    if 'site-packages' in dist.location:
        try:
            pip.call_subprocess(['pip', 'install', '-U', dist.key])
        except Exception, exc:
            print exc

站点包检查排除了我的开发包,因为它们不在系统站点包目录中。try-except只是跳过已从PyPI中删除的包。

对于endolith:我也希望有一个简单的pip.install(dist.key,upgrade=True),但它看起来不像是要让命令行以外的任何东西使用pip(文档没有提到内部API,pip开发人员也没有使用docstring)。

其他回答

更稳健的解决方案

对于pip3,请使用以下命令:

pip3 freeze --local |sed -rn 's/^([^=# \t\\][^ \t=]*)=.*/echo; echo Processing \1 ...; pip3 install -U \1/p' |sh

对于pip,只需删除3s即可:

pip freeze --local |sed -rn 's/^([^=# \t\\][^ \t=]*)=.*/echo; echo Processing \1 ...; pip install -U \1/p' |sh

OS X奇数

截至2017年7月,OS X附带了一个非常旧的sed版本(已有十几年历史)。要获得扩展正则表达式,请在上面的解决方案中使用-E而不是-r。

使用流行解决方案解决问题

这个解决方案经过了精心设计和测试1,而即使是最流行的解决方案也存在问题。

由于pip命令行特性的变化而导致的可移植性问题由于常见的pip或pip3子进程故障导致xargs崩溃来自原始xargs输出的拥挤日志记录依赖Python到OS桥,同时可能升级它3

上面的命令使用最简单和最可移植的pip语法,并结合sed和sh来完全解决这些问题。sed操作的详细信息可以使用注释的版本2进行详细检查。


细节

[1] 在Linux 4.8.16-200.fc24.x86_64集群中测试并定期使用,并在其他五种Linux/Unix版本上测试。它还可以在Windows 10上安装的Cygwin64上运行。需要在iOS上进行测试。

[2] 为了更清楚地看到命令的解剖结构,这与上面的pip3命令完全等价,并带有注释:

# Match lines from pip's local package list output
# that meet the following three criteria and pass the
# package name to the replacement string in group 1.
# (a) Do not start with invalid characters
# (b) Follow the rule of no white space in the package names
# (c) Immediately follow the package name with an equal sign
sed="s/^([^=# \t\\][^ \t=]*)=.*"

# Separate the output of package upgrades with a blank line
sed="$sed/echo"

# Indicate what package is being processed
sed="$sed; echo Processing \1 ..."

# Perform the upgrade using just the valid package name
sed="$sed; pip3 install -U \1"

# Output the commands
sed="$sed/p"

# Stream edit the list as above
# and pass the commands to a shell
pip3 freeze --local | sed -rn "$sed" | sh

[3] 升级也用于升级Python或PIP组件的Python或PIP组件可能会导致死锁或包数据库损坏。

在我看来,这个选项更简单易懂:

pip install -U `pip list --outdated | awk 'NR>2 {print $1}'`

解释是,pip-list——过时输出所有过时包的列表,格式如下:

Package   Version Latest Type 
--------- ------- ------ -----
fonttools 3.31.0  3.32.0 wheel
urllib3   1.24    1.24.1 wheel
requests  2.20.0  2.20.1 wheel

在awk命令中,NR>2跳过前两条记录(行),{print$1}选择每行的第一个单词(正如SergioAraujo所建议的,我删除了tail-n+3,因为awk确实可以处理跳过记录)。

python -c 'import pip; [pip.main(["install", "--upgrade", d.project_name]) for d in pip.get_installed_distributions()]'

一行!

您可以使用以下Python代码。与pip冻结不同,这不会打印警告和FIXME错误。对于管道<10.0.1

import pip
from subprocess import call

packages = [dist.project_name for dist in pip.get_installed_distributions()]
call("pip install --upgrade " + ' '.join(packages), shell=True)

对于pip>=10.0.1

import pkg_resources
from subprocess import call

packages = [dist.project_name for dist in pkg_resources.working_set]
call("pip install --upgrade " + ' '.join(packages), shell=True)

没有必要这么麻烦或安装一些软件包。

在Linux shell上更新pip包:

pip list --outdated --format=freeze | awk -F"==" '{print $1}' | xargs -i pip install -U {}

在Windows powershell上更新pip包:

pip list --outdated --format=freeze | ForEach { pip install -U $_.split("==")[0] }

一些要点:

将pip作为python版本替换为pip3或pip2。pip-list——过时,用于检查过时的pip包。--我的pip版本22.0.3的格式只有3种类型:列(默认)、冻结或json。冻结是命令管道中更好的选项。尽可能多地保持命令简单和可用。