pypi-changes
A CLI tool that inspects a Python interpreter's installed packages and compares them against the latest releases on PyPI. It shows which packages are outdated, how long ago each release was published, and highlights major version bumps so you can make informed upgrade decisions.
Getting started
Install from PyPI:
pip install pypi-changes
Run against the current Python interpreter:
pypi-changes
Or point it at a specific interpreter (useful for checking virtual environments):
pypi-changes /path/to/venv/bin/python
How-to guides
Check for outdated packages
Run pypi-changes without arguments to see a tree of all installed packages with their version status. Outdated
packages appear in red, with major version bumps in bold red:
$ pypi-changes
🐍 Distributions within /usr/bin/python
├── virtualenv 20.38.0 10 days remote 21.1.0 2 days
├── certifi 2026.1.4 2 months remote 2026.2.25 4 days
├── rich 14.3.3 9 days
├── packaging 26.0 a month
├── urllib3 1.26.20 1 year, 6 months remote 2.6.3 2 months
├── requests 2.32.5 6 months
├── pluggy 1.6.0 10 months
└── covdefaults 2.3.0 2 years
Generate a requirements file for upgrades
Use the requirements output format to produce a requirements.txt-compatible list of outdated packages pinned to
their latest versions:
$ pypi-changes --output requirements
virtualenv==21.1.0
certifi==2026.2.25
urllib3==2.6.3
wheel-filename==2.1.0
Pipe directly into pip install to upgrade:
pypi-changes --output requirements > upgrades.txt
pip install -r upgrades.txt
Get machine-readable output
Use JSON output for scripting or integration with other tools:
$ pypi-changes --output json
[
{
"name": "virtualenv",
"version": "20.38.0",
"up_to_date": false,
"current": {
"version": "20.38.0",
"date": "2026-02-19T07:47:59.778389+00:00",
"since": "10 days"
},
"latest": {
"version": "21.1.0",
"date": "2026-02-27T08:49:27.516392+00:00",
"since": "2 days"
}
},
{
"name": "rich",
"version": "14.3.3",
"up_to_date": true,
"current": {
"version": "14.3.3",
"date": "2026-02-19T17:23:13.732467+00:00",
"since": "9 days"
},
"latest": {
"version": "14.3.3",
"date": "2026-02-19T17:23:13.732467+00:00",
"since": "9 days"
}
}
]
Each entry includes name, version, up_to_date, and detailed current/latest release information with dates and
human-readable time deltas.
Sort packages alphabetically
By default, packages are sorted by release date (most recently updated first). To sort alphabetically:
pypi-changes --sort alphabetic
Speed up repeated runs with caching
Requests to PyPI are cached in a local SQLite database for 1 hour by default. To adjust the cache duration:
pypi-changes --cache-duration 7200 # cache for 2 hours
pypi-changes --cache-duration 0 # bypass cache entirely
pypi-changes --cache-duration -1 # cache forever
To change the cache file location:
pypi-changes --cache-path /tmp/pypi-cache.sqlite
Use with a private package index
Set the PIP_INDEX_URL environment variable to merge releases from a private index server (e.g. Artifactory) with PyPI
data:
PIP_INDEX_URL=https://my-artifactory.example.com/simple pypi-changes
Control request parallelism
PyPI release information is fetched in parallel. Adjust the number of concurrent requests with --jobs:
pypi-changes --jobs 20 # increase parallelism
pypi-changes --jobs 1 # sequential requests
Reference
Usage
pypi-changes [-h] [--jobs COUNT] [--cache-path PATH] [--cache-duration SEC]
[--sort [{a,alphabetic,u,updated}]] [--output {tree,json,requirements}]
[PYTHON_EXE]
Positional arguments
| Argument | Description |
|---|---|
PYTHON_EXE |
Python interpreter to inspect. Defaults to python found on $PATH. |
Options
| Flag | Default | Description |
|---|---|---|
--jobs, -j |
10 |
Maximum number of parallel requests when loading distribution information from PyPI. |
--cache-path, -c |
platform path | Path to the SQLite file used for caching HTTP requests. |
--cache-duration, -d |
3600 |
Seconds to cache requests. 0 bypasses the cache, -1 caches forever. |
--sort, -s |
updated |
Sort order: a/alphabetic or u/updated (most recent first). |
--output, -o |
tree |
Output format: tree, json, or requirements. |
Output formats
tree (default) -- a Rich-rendered tree showing each package with its installed version, time since release, and
remote version if outdated. Major version bumps appear in bold red; minor/patch bumps in red.
json -- a JSON array where each element contains:
name-- package nameversion-- installed versionup_to_date-- booleancurrent-- object withversion,date(ISO 8601), andsince(human-readable delta)latest-- object with the same fields for the newest stable release
requirements -- prints only outdated packages in name==version format, suitable for piping into
pip install -r.
Environment variables
| Variable | Description |
|---|---|
PIP_INDEX_URL |
When set to a non-PyPI URL, merges releases from that index server with PyPI release data. |
How it works
pypi-changes inspects the target Python interpreter's sys.path to discover all installed distributions (packages
with .dist-info or .egg-info directories). It then fetches each package's release history from the
PyPI JSON API in parallel, using a thread pool controlled by --jobs.
Releases are sorted by semantic version. The latest stable release (excluding dev and pre-releases) is selected for comparison against the installed version. When a release has no uploaded artifacts (common for some yanked or placeholder versions), a synthesized timestamp is generated internally for sorting purposes but is not displayed to the user.
HTTP responses are cached in a local SQLite database via requests-cache to avoid redundant network calls on repeated runs. Expired entries are cleaned up automatically on each invocation.
When PIP_INDEX_URL is set to a non-PyPI URL, pypi-changes also queries that index via the
Simple Repository API and merges any
versions not found on PyPI into the release list. This is useful for organizations hosting internal packages on private
registries.
Metadata
Release files for pypi-changes 1.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pypi_changes-1.7.0.tar.gz | 138.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pypi_changes-1.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 153.4 kB
Release files / pypi_changes-1.7.0.tar.gz
| Download URL | pypi_changes-1.7.0.tar.gz |
|---|---|
| Size | 138.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6ffcc44c5b368d37f13567e1cbe3af0f861c1118049ebda6ef3f863045aa8476
|
|
BLAKE2b-256 checksum How to use checksums |
d335ac9e3370a72959878ebccec51641e38ef76a03968ab321761307a19f8aef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / pypi_changes-1.7.0-py3-none-any.whl
| Download URL | pypi_changes-1.7.0-py3-none-any.whl |
|---|---|
| Size | 15.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
32c7f0d2e2ab2362b0094809d7db5c0e4bfb7802f27e116bd8a3e01c16493f8b
|
|
BLAKE2b-256 checksum How to use checksums |
c5d69e16e185837e9ba8edc7c30724a511433432851dd5acb7b87ef9472dd3d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log