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.
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.
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
get_installed_distributionsinstall_cmd.parse_args(list(map(attrgetter("project_name"), working_set))) - I'll edit this answerI 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)
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
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
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.
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 ...
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:
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)
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.
The below Windows cmd snippet does the following:
- Upgrades
pipto latest version.
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
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)
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])
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 packagecut -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.pip install --upgrade `pip freeze | cut -d '=' -f 1`.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
pip list --outdated --format=jsonReturns a JSON-formatted list of all outdated packages.
jq -r '.[].name'Extracts name from the JSON output.
xargs -n1 pip install -UUpgrades all Python packages one by one.
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.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.
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.
sudo -H) version when updating the packages for your whole system.If you are on macOS,
make sure you have Homebrew installed
install jq in order to read the JSON you’re about to generate
brew install jq
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}'`
jq is universal (and already installed).pip list --outdated --format json | jq '.[].name' | xargs -i pip install {} -UTo 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'))
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.
Use pipx instead:
pipx upgrade-all
pip3 upgrade-all leads to ERROR: unknown command "upgrade-all" I guess that command is removed againpip install --upgrade `pip list --format=freeze | cut -d '=' -f 1`
pip list --format=freeze includes pip and setuptools. pip freeze does not.
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.
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
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.
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
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)
pip freeze(likebundle installornpm shrinkwrap). Best to save a copy of that before tinkering.pip list --format freeze | %{pip install --upgrade $_.split('==')[0]}(I am unable to post an answer here yet)