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

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


当前回答

以下Windows cmd代码段执行以下操作:

将pip升级到最新版本。升级所有过时的软件包。对于正在升级的每个包,检查requirements.txt中的任何版本说明符。

@echo off
Setlocal EnableDelayedExpansion
rem https://stackoverflow.com/questions/2720014/

echo Upgrading pip...
python -m pip install --upgrade pip
echo.

echo Upgrading packages...
set upgrade_count=0
pip list --outdated > pip-upgrade-outdated.txt
for /F "skip=2 tokens=1,3 delims= " %%i in (pip-upgrade-outdated.txt) do (
    echo ^>%%i
    set package=%%i
    set latest=%%j
    set requirements=!package!

    rem for each outdated package check for any version requirements:
    set dotest=1
    for /F %%r in (.\python\requirements.txt) do (
        if !dotest!==1 (
            call :substr "%%r" !package! _substr
            rem check if a given line refers to a package we are about to upgrade:
            if "%%r" NEQ !_substr! (
                rem check if the line contains more than just a package name:
                if "%%r" NEQ "!package!" (
                    rem set requirements to the contents of the line:
                    echo requirements: %%r, latest: !latest!
                    set requirements=%%r
                )
                rem stop testing after the first instance found,
                rem prevents from mistakenly matching "py" with "pylint", "numpy" etc.
                rem requirements.txt must be structured with shorter names going first
                set dotest=0
            )
        )
    )
    rem pip install !requirements!
    pip install --upgrade !requirements!
    set /a "upgrade_count+=1"
    echo.
)

if !upgrade_count!==0 (
    echo All packages are up to date.
) else (
    type pip-upgrade-outdated.txt
)

if "%1" neq "-silent" (
    echo.
    set /p temp="> Press Enter to exit..."
)
exit /b


:substr
rem string substition done in a separate subroutine -
rem allows expand both variables in the substring syntax.
rem replaces str_search with an empty string.
rem returns the result in the 3rd parameter, passed by reference from the caller.
set str_source=%1
set str_search=%2
set str_result=!str_source:%str_search%=!
set "%~3=!str_result!"
rem echo !str_source!, !str_search!, !str_result!
exit /b

其他回答

我在升级方面也遇到了同样的问题。问题是,我从不升级所有包。我只升级我需要的,因为项目可能会中断。

因为没有一种简单的方法来逐个包升级和更新requirements.txt文件,所以我编写了这个pip升级程序,它还更新了所选包(或所有包)的requirements.txt文件中的版本。

安装

pip install pip-upgrader

用法

激活virtualenv(这很重要,因为它还将在当前virtualenv中安装升级包的新版本)。

cd到项目目录中,然后运行:

pip-upgrade

高级用法

如果需求放置在非标准位置,请将其作为参数发送:

pip-upgrade path/to/requirements.txt

如果您已经知道要升级的软件包,只需将其作为参数发送:

pip-upgrade -p django -p celery -p dateutil

如果需要升级到发布前/发布后版本,请在命令中添加--prerelease参数。

完全披露:我写了这个包裹。

一行(bash)。对我来说最短、最简单。

pip install -U $(pip freeze | cut -d = -f 1)

解释:

pip冻结返回每个包的package_name==版本cut-d=-f 1表示“对于每一行,返回第一行的字段,其中字段由=分隔”$(cmd)返回命令cmd的结果。因此,在这里,cmd将返回包名列表,pip install-U将对其进行升级。

如果您安装了pip<22.3,则使用纯Bash/Z外壳一个衬垫实现:

for p in $(pip list -o --format freeze); do pip install -U ${p%%=*}; done

或者,以一种格式良好的方式:

for p in $(pip list -o --format freeze)
do
    pip install -U ${p%%=*}
done

在这之后,您将得到pip>=22.3,其中-o和--format冻结是互斥的,您不能再使用这一行。

这似乎对我有用。。。

pip install -U $(pip list --outdated | awk '{printf $1" "}')

之后,我使用带有空格的printf来正确分隔包名。

还没有内置标志。从pip版本22.3开始,--过时和--format=freeze变得互斥。使用Python解析json输出:

pip --disable-pip-version-check list --outdated --format=json | python -c "import json, sys; print('\n'.join([x['name'] for x in json.load(sys.stdin)]))"

如果您正在使用pip<22.3,则可以使用:

pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1  | xargs -n1 pip install -U

对于旧版本的pip:

pip freeze --local | grep -v '^\-e' | cut -d = -f 1  | xargs -n1 pip install -U

grep是跳过可编辑(“-e”)包定义,正如@jawache所建议的那样。(是的,您可以用sed、awk、perl或…替换grep+cut)。xargs的-n1标志防止在更新一个包失败时停止所有操作(谢谢@andss)。


注意:这有无限的潜在变化。我试图让这个答案简短明了,但请在评论中提出建议!