2883

Is it possible to upgrade all Python packages at one time with pip?

Note: that there is a feature request for this on the official issue tracker.

6
  • 80
    Beware software rot—upgrading dependencies might break your app. You can list the exact version of all installed packages with pip freeze (like bundle install or npm shrinkwrap). Best to save a copy of that before tinkering. Commented May 22, 2013 at 13:01
  • 7
    If you want to update a single package and all of its dependencies (arguably a more sensible approach), do this: pip install -U --upgrade-strategy eager your-package Commented Feb 24, 2021 at 15:33
  • 22
    I use PowerShell 7 and currently I use this one-liner: pip list --format freeze | %{pip install --upgrade $_.split('==')[0]} (I am unable to post an answer here yet) Commented Mar 7, 2021 at 5:11
  • 2
    For those wondering like me, the was until recently pip didn't have a dependency resolver. github.com/pypa/pip/issues/4551 Commented Sep 11, 2022 at 19:07
  • @user15290516, your solution works like a charm. Thank you. Commented Apr 9 at 2:13

65 Answers 65

10

Sent through a pull-request to the pip folks; in the meantime use this pip library solution I wrote:

from operator import attrgetter

## Old solution:
# from pip import get_installed_distributions
# from pip.commands import install
## New solution:
from pkg_resources import working_set
from pip._internal.commands import install    

install_cmd = install.InstallCommand()

options, args = install_cmd.parse_args(
    ## Old solution:
    # list(map(attrgetter("project_name")
    #          get_installed_distributions()))
    ## New solution:
    list(map(attrgetter("project_name"), working_set))
)

options.upgrade = True
install_cmd.run(options, args)  # Chuck this in a try/except and print as wanted
Sign up to request clarification or add additional context in comments.

3 Comments

Version with error handling (as per comment): gist.github.com/SamuelMarks/7885f2e8e5f0562b1063
On pip3 there is no such function as get_installed_distributions
@areop-enap - For at least a little while, this will work instead: install_cmd.parse_args(list(map(attrgetter("project_name"), working_set))) - I'll edit this answer
9

This seemed to work for me...

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

I used printf with a space afterwards to properly separate the package names.

Comments

8

A JSON + jq answer:

pip list -o --format json | jq '.[] | .name' | xargs pip install -U

1 Comment

the jq filtering can be further simplified to jq -c '.[].name'
8

I use this one-liner setup as an alias to upgrade my pip3 packages:

pip3 list --outdated | sed '1,2d; s/ .*//' | xargs -n1 pip3 install -U

or (as suggested by @Marc, awk can be used):

pip3 list --outdated | awk 'NR>2 {print $1}' | xargs -n1 pip3 install -U

or:

pip3 list --outdated | tail -n +3 | cut -d ' ' -f1 | xargs -n1 pip3 install -U

(note that while it's most likely the case these will work with most shells, your shell will have to support either sed and xargs for the first script or awk and xargs for the second script or tail, cut, and xargs for the third script. These packages come preinstalled on most Unix and Unix-like systems)

  1. pip3 list --outdated gets a list of installed outdated pip3 packages:

    pip3 list --outdated
    

    Output:

    Package        Version Latest Type
    -------------- ------- ------ -----
    dbus-python    1.2.18  1.3.2  sdist
    pycairo        1.20.1  1.25.1 sdist
    PyGObject      3.42.1  3.46.0 sdist
    systemd-python 234     235    sdist
    
  2. sed '1,2d; s/ .*//', awk 'NR>2 {print $1}', or tail -n +3 | cut -d ' ' -f1 removes the first 2 lines and keeps only the first word for each remaining line:

    pip3 list --outdated | sed '1,2d; s/ .*//'
    # or $pip3 list --outdated | awk 'NR>2 {print $1}'
    # or $pip3 list --outdated | tail -n +3 | cut -d ' ' -f1
    

    Output:

    dbus-python
    pycairo
    PyGObject
    systemd-python
    
  3. xargs -n1 pip3 install -U passes the name of each package as an argument to pip3 install -U (pip command to recursively upgrade all packages).

I ran some benchmarks and sed appeared to be faster on my system. I used sed, awk, and then tail and cut to read a text file input 5000 times and alter and output it to /dev/null and timed it. Granted the test setup is pretty minimal and not very exhaustive, but I feel can give at least a rough general idea of what can be expected from each script (albeit any differences in real world use will be pretty negligible/non existent). Here are the results I got on my machine:

sed:
------------------
real    0m8.984s
user    0m3.411s
sys 0m5.822s

awk:
------------------
real    0m14.606s
user    0m5.457s
sys 0m9.350s

tail-cut:
------------------
real    0m15.483s
user    0m6.240s
sys 0m16.360s

The benchmark setup can be found in the gist -> HERE <-

I personally prefer the sed method the most as it requires less piping than the tail and cut method and it's a bit "lighter" than awk. Line by line parsing/editing is the exact use case sed is designed for.

Comments

7

I've been using pur lately. It's simple and to the point. It updates your requirements.txt file to reflect the upgrades and you can then upgrade with your requirements.txt file as usual.

$ pip install pur
...
Successfully installed pur-4.0.1

$ pur
Updated boto3: 1.4.2 -> 1.4.4
Updated Django: 1.10.4 -> 1.10.5
Updated django-bootstrap3: 7.1.0 -> 8.1.0
All requirements up-to-date.

$ pip install --upgrade -r requirements.txt
Successfully installed Django-1.10.5 ...

Comments

6

See all outdated packages

pip list --outdated --format=columns

Install

sudo pip install pipdate

then type

sudo -H pipdate

Comments

6

Here's the code for updating all Python 3 packages (in the activated virtualenv) via pip:

import pkg_resources
from subprocess import call

for dist in pkg_resources.working_set:
    call("python3 -m pip install --upgrade " + dist.project_name, shell=True)

Comments

5

Here is my variation on rbp's answer, which bypasses "editable" and development distributions. It shares two flaws of the original: it re-downloads and reinstalls unnecessarily; and an error on one package will prevent the upgrade of every package after that.

pip freeze |sed -ne 's/==.*//p' |xargs pip install -U --

Related bug reports, a bit disjointed after the migration from Bitbucket:

Comments

5

Here is a script that only updates the outdated packages.

import os, sys
from subprocess import check_output, call

file = check_output(["pip.exe",  "list", "--outdated", "--format=legacy"])
line = str(file).split()

for distro in line[::6]:
    call("pip install --upgrade " + distro, shell=True)

For a new version of pip that does not output as a legacy format (version 18+):

import os, sys
from subprocess import check_output, call

file = check_output(["pip.exe", "list", "-o", "--format=json"])
line = str(file).split()

for distro in line[1::8]:
    distro = str(distro).strip('"\",')
    call("pip install --upgrade " + distro, shell=True)

2 Comments

That sadly no longer works. pip --format does not accept "legacy" as a choice. At least not on my python release.
@StormShadow as you hope know, pip really poorly control depencies. it does exactly as other solution - yep(( Better to add disclaimer
5

Use:

import pip
pkgs = [p.key for p in pip.get_installed_distributions()]
for pkg in pkgs:
    pip.main(['install', '--upgrade', pkg])

Or even:

import pip
commands = ['install', '--upgrade']
pkgs = commands.extend([p.key for p in pip.get_installed_distributions()])
pip.main(commands)

It works fast as it is not constantly launching a shell.

2 Comments

Does constantly launching a shell really make a measurable difference when we'll end up downloading packages from pypi followed by (compilation and) installation?
@gerrit I my experience yes it does, especially in an environment where you have aggressive anti-virus software that you can't turn off running. Where I work we cannot disable or suppress the AV and each shell launch takes 20-30 seconds but, on good days, we do have a fast internet connection. When you are installing large packages the installation time can be significant but when it is a lot of smaller package the shell start time is very significant.
5

The below Windows cmd snippet does the following:

  • Upgrades pip to latest version.
  • Upgrades all outdated packages.
  • For each packages being upgraded checks requirements.txt for any version specifiers.
@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

2 Comments

@ScamCast Glad you liked it! I've just updated the snipped to the latest version I'm using.
for /F "skip=2" %G in ('pip list --outdated') do pip install %G --upgrade should do the job as well however preceding python -m pip install --upgrade pip isn't a bad idea:)
4

I have tried the code of Ramana and I found out on Ubuntu you have to write sudo for each command. Here is my script which works fine on Ubuntu 13.10 (Saucy Salamander):

#!/usr/bin/env python
import pip
from subprocess import call

for dist in pip.get_installed_distributions():
    call("sudo pip install --upgrade " + dist.project_name, shell=True)

Comments

4

Here is another way of doing with a script in Python:

import pip, tempfile, contextlib

with tempfile.TemporaryFile('w+') as temp:
    with contextlib.redirect_stdout(temp):
        pip.main(['list', '-o'])
    temp.seek(0)
    for line in temp:
        pk = line.split()[0]
        print('--> updating', pk, '<--')
        pip.main(['install', '-U', pk])

Comments

4

One liner (bash). Shortest, easiest, for me.

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

Explanations:

  • pip freeze returns package_name==version for each package
  • cut -d = -f 1 means "for each line, return the 1st line's field where fields are delimited by ="
  • $(cmd) returns the result of command cmd. So here, cmd will return the list of package names and pip install -U will upgrade them.

2 Comments

I find this syntax more readable: pip install --upgrade `pip freeze | cut -d '=' -f 1`.
That's the same, it's just bash syntax preferences, not command changes
4

If you are using venv, where you don't need to use sudo:

pip list --outdated --format=json \
    | jq -r '.[].name' \
    | xargs -n1 pip install -U

Explanation

  1. pip list --outdated --format=json

Returns a JSON-formatted list of all outdated packages.

  1. jq -r '.[].name'

Extracts name from the JSON output.

  1. xargs -n1 pip install -U

Upgrades all Python packages one by one.

1 Comment

Listing the outdated packages as json is the right approach, as it is less likely subject to change in comparison to parsing with cut or sed even if it requires installation of jq.
3
import os
import pip
from subprocess import call, check_call

pip_check_list = ['pip', 'pip3']
pip_list = []
FNULL = open(os.devnull, 'w')


for s_pip in pip_check_list:
    try:
        check_call([s_pip, '-h'], stdout=FNULL)
        pip_list.append(s_pip)
    except FileNotFoundError:
        pass


for dist in pip.get_installed_distributions():
    for pip in pip_list:
        call("{0} install --upgrade ".format(pip) + dist.project_name, shell=True)

I took Ramana's answer and made it pip3 friendly.

Comments

3

As another answer here stated:

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

Is a possible solution: Some comments here, myself included, had issues with permissions while using this command. A little change to the following solved those for me.

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

Note the added sudo -H which allowed the command to run with root permissions.

To upgrade only outdated versions on a local / user environment for pip3

pip3 install --user -U `pip3 list -ol --format=json|grep -Po 'name": "\K.*?(?=")'`

The switch -ol works similar to --outdated --local or -o --user. On Debian Testing you might also add the switch --break-system-packages to install command. But do that only on your own risk. This command might be useful on super up-to-date systems where AI runs and anything with root is avoided. It helps porting from Stable Diffusion 1.5 to 2.1 with rocm support for example.

1 Comment

Use the first version with a virtual environment and the second (sudo -H) version when updating the packages for your whole system.
2

One line in cmd:

for /F "delims= " %i in ('pip list --outdated --format=legacy') do pip install -U %i

So a

pip check

afterwards should make sure no dependencies are broken.

Comments

2

If you are on macOS,

  1. make sure you have Homebrew installed

  2. install jq in order to read the JSON you’re about to generate

    brew install jq
    
  3. update each item on the list of outdated packages generated by pip3 list --outdated

    pip3 install --upgrade  `pip3 list --outdated --format json | jq '.[] | .name' | awk -F'"' '{print $2}'`
    

2 Comments

Works for linux as well, given jq is universal (and already installed).
the following also works fine pip list --outdated --format json | jq '.[].name' | xargs -i pip install {} -U
1

for in a bat script:

call pip freeze > requirements.txt
call powershell "(Get-Content requirements.txt) | ForEach-Object { $_ -replace '==', '>=' } | Set-Content requirements.txt"
call pip install -r requirements.txt --upgrade

Comments

1

To upgrade all of your pip default packages in your default Python version, just run the below Python code in your terminal or command prompt:

import subprocess
import re

pkg_list = subprocess.getoutput('pip freeze')

pkg_list = pkg_list.split('\n')

new_pkg = []
for i in pkg_list:
    re.findall(r"^(.*)==.*", str(i))
    new = re.findall(r"^(.*)==.*", str(i))[0]
    new_pkg.append(new)

for i in new_pkg:
    print(subprocess.getoutput('pip install '+str(i)+' --upgrade'))

Comments

1
  1. By using pip-upgrader

    • using this library you can easily upgrade all the dependencies packages. These are set up you follows.

      pip install pip-upgrader
      
      pip-upgrade path/of/requirements_txt_file
      

An interactive pip requirements upgrader. Because upgrading requirements, package by package, is a pain in the ass. It also updates the version in your requirements.txt file.

Comments

1

Use pipx instead:

pipx upgrade-all

3 Comments

What is this "pipx" you speak of? E.g., can you add some references? Please respond by editing (changing) your answer, not here in comments (******** without ******** "Edit:", "Update:", or similar - the answer should appear as if it was written today).
pip3 upgrade-all leads to ERROR: unknown command "upgrade-all" I guess that command is removed again
1
pip install --upgrade `pip list --format=freeze | cut -d '=' -f 1`

pip list --format=freeze includes pip and setuptools. pip freeze does not.

1 Comment

1

Several answers here suggest using pip list --outdated in combination with jq and xargs. That works, but there’s now a faster and more robust way using uv, a modern Python package manager from the team behind ruff.

With uv and jq you can upgrade all outdated packages in one shot:

outdated=($(uv pip list --outdated --format=json | jq -r '.[].name')); (( ${#outdated[@]} )) && uv pip install -U "${outdated[@]}" || echo '✅ All packages are up to date!'

Advantages:

  • Fast: uv installs and resolves dependencies much faster than pip.

  • Robust: avoids piping into xargs (common in older answers) and handles the case where there are no outdated packages gracefully.

  • Modern: uv is a drop-in replacement for pip, but with lockfile support and deterministic installs.

Convenience function:

You can make this a reusable command by defining a function in your shell rc file (~/.bashrc, ~/.zshrc, etc.):

pip_upgrade_outdated() {
  local outdated=($(uv pip list --outdated --format=json | jq -r '.[].name'))
  (( ${#outdated[@]} )) && uv pip install -U "${outdated[@]}" || echo '✅ All packages are up to date!'
}

Then just run:

pip_upgrade_outdated

and you’ll either upgrade everything or get a friendly “all up to date” message.

Cross-compatibility:

If you need to ensure compatibility across systems, including sh, the predecessor of bash and zsh, you can use this function:

pip_upgrade_outdated() {
    # Disable globbing to avoid accidental wildcard expansion
    set -f

    # Save IFS and set it to a literal newline
    old_ifs=$IFS
    IFS='
' # <- that's a real newline between the quotes

    # Put package names (newline-separated) into "$@" as individual args
    # (Command substitution happens first, then word-splitting uses our IFS.)
    # shellcheck disable=SC2046
    set -- $(uv pip list --outdated --format=json | jq -r '.[].name')

    # Restore IFS and globbing
    IFS=$old_ifs
    set +f

    if [ "$#" -gt 0 ]; then
        uv pip install -U "$@"
    else
        echo '✅ All packages are up to date!'
    fi
}

The one-liner solution:

For those who love one-line solutions, here is a POSIX sh-compatible command:

uv pip install -U $(uv pip list --outdated --format=json | jq -r '.[].name')

Note that the one-line version does not gracefully handle the situation when there is no outdateed package.

Comments

0

All posted solutions here break dependencies.

From this conversation to include the functionality directly into pip, including properly managing dependencies:

The author of Meta Package Manager (MPM) writes that MPM can emulate the missing upgrade-all command:

mpm --pip upgrade --all

2 Comments

What do you mean by "break dependencies"? Can you elaborate?
You run update and then you end up with version conflicts, that's what breaking dependencies means. But it turns out MPM does the same, despite the author promising diffently.
0

I like to use pip-tools to handle this process.

Package pip-tools presents two scripts:

pip-compile: used to create a viable requirements.txt from a requirement.in file. pip-sync: used to sync the local environment pip repository to match that of your requirements.txt file.

If I want to upgrade a particular package say:

django==3.2.12

to

django==3.2.16

I can then change the base version of Django in requirements.in, run pip-compile and then run pip-sync. This will effectively upgrade django (and all dependent packages too) by removing older versions and then installing new versions.

It is very simple to use for upgrades in addition to pip package maintenance.

Comments

0

If you want upgrade only packaged installed by pip, and to avoid upgrading packages that are installed by other tools (like apt, yum etc.), then you can use this script that I use on my Ubuntu (maybe works also on other distros) - based on this post:

printf "To update with pip: pip install -U"
pip list --outdated 2>/dev/null | gawk '{print $1;}' | while read; do pip show "${REPLY}" 2>/dev/null | grep 'Location: /usr/local/lib/python2.7/dist-packages' >/dev/null; if (( $? == 0 )); then printf " ${REPLY}"; fi; done; echo

Comments

0

That works for me for Python 3.12 out of the box, directly or in a virtual environment:

pip3 list -o | cut -f1 -d' ' | tr " " "\n" | awk '{if(NR>=3)print}' | cut -d' ' -f1 | xargs -n1 pip3 install -U

Comments

0

I use the following to upgrade packages installed in /opt/... virtual environments:

( pip=/opt/SOMEPACKAGE/bin/pip; "$pip" install -U $("$pip" list -o | sed -n -e '1,2d; s/[[:space:]].*//p') )

(unrelated tip, if you need shell variables, run commands inside a ( ... ) subshell so as to not pollute)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.