check out when packages changed
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pypi_changes-1.5.1.tar.gz.
File metadata
- Download URL: pypi_changes-1.5.1.tar.gz
- Upload date:
- Size: 137.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d237927fd80b904bc18ebdfccda29b59232367b142b745c6b312fd334ccd414
|
|
| MD5 |
d82fc76327d82ce98f4190ab0edcd534
|
|
| BLAKE2b-256 |
154b0844f0c2f419b5a2680d85a4651043de30bda57b386d6e7f895413320751
|
Provenance
The following attestation bundles were made for pypi_changes-1.5.1.tar.gz:
Publisher:
release.yaml on gaborbernat/pypi-changes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pypi_changes-1.5.1.tar.gz -
Subject digest:
7d237927fd80b904bc18ebdfccda29b59232367b142b745c6b312fd334ccd414 - Sigstore transparency entry: 1006543481
- Sigstore integration time:
-
Permalink:
gaborbernat/pypi-changes@362060575c0e6d3cf9b6d1a78e8ae5b1f0b8d4bf -
Branch / Tag:
refs/tags/1.5.1 - Owner: https://github.com/gaborbernat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@362060575c0e6d3cf9b6d1a78e8ae5b1f0b8d4bf -
Trigger Event:
push
-
Statement type:
File details
Details for the file pypi_changes-1.5.1-py3-none-any.whl.
File metadata
- Download URL: pypi_changes-1.5.1-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
709caeb35a654d19e1a7fc1ccbf68fb42ed8260bb53aadda372ce7656cc74206
|
|
| MD5 |
031db02bd1844b2d719e54943d5da206
|
|
| BLAKE2b-256 |
73184819c4c3760d60d0c37a3e5f5cc27c1baa35b93960a0c0d2c16d308c3fe7
|
Provenance
The following attestation bundles were made for pypi_changes-1.5.1-py3-none-any.whl:
Publisher:
release.yaml on gaborbernat/pypi-changes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pypi_changes-1.5.1-py3-none-any.whl -
Subject digest:
709caeb35a654d19e1a7fc1ccbf68fb42ed8260bb53aadda372ce7656cc74206 - Sigstore transparency entry: 1006543491
- Sigstore integration time:
-
Permalink:
gaborbernat/pypi-changes@362060575c0e6d3cf9b6d1a78e8ae5b1f0b8d4bf -
Branch / Tag:
refs/tags/1.5.1 - Owner: https://github.com/gaborbernat
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@362060575c0e6d3cf9b6d1a78e8ae5b1f0b8d4bf -
Trigger Event:
push
-
Statement type: