wheelripe

Usage

CLI

Point it at a project directory, a lockfile, or a list of specs. With no argument it looks in the current directory and picks the most precise file it finds: uv.lock > pylock.toml > poetry.lock > Pipfile.lock > requirements*.txt > pyproject.toml.

# the current project, CPython 3.15, default platforms
wheelripe

# free-threaded 3.15t, every platform you ship
wheelripe uv.lock -p 3.15t --platform linux-x86_64,linux-aarch64,macos-arm64,windows-amd64

# no lockfile handy? pass specs
wheelripe numpy==1.26.4 pydantic-core==2.41.5 orjson

# older glibc in production
wheelripe requirements.txt --glibc 2.28

Unpinned specs (orjson, numpy>=1.26) are checked at the newest release matching the specifier. Pinned ones (==, or anything from a lockfile) are checked at exactly that version, and if it has no wheel wheelripe looks forward for the first newer release that does.

PyTorch and private indexes

Point wheelripe at any PEP 691 (JSON) or PEP 503 (HTML) simple index with the options pip takes. Files from every index are pooled, like pip, and versions come from the file names, so local builds such as 2.14.0+cpu match the way pip matches them.

$ wheelripe torch==2.13.0 numpy==2.5.4 --index-url https://download.pytorch.org/whl/cpu --extra-index-url https://pypi.org/simple
cli · 2 packages · index download.pytorch.org/whl/cpu + pypi.org

BUMP     torch 2.13.0 → 2.14.0   no cp315 wheel in 2.13.0 for macos-arm64, windows-amd64 (ships cp310–cp315); 2.14.0 is the first release with one · ready on linux-x86_64
READY    1 package (1 with binary wheels · 0 pure Python)

# a requirements file that already says where to look needs no flags
wheelripe requirements.txt        # -i / --extra-index-url lines, also inside -r includes

# uv.lock: each package is checked on the registry uv locked it from
wheelripe uv.lock -p 3.15t

# a private index: credentials go to that host only and are never printed
wheelripe -i "https://$INDEX_USER:$INDEX_TOKEN@pypi.corp.example/simple" requirements.txt

Precedence, credentials and what happens when an index refuses are on the configuration page.

Explain a single wheel

$ wheelripe wheel orjson-3.13.0-cp315-cp315-manylinux_2_39_x86_64.whl -p 3.15t
orjson-3.13.0-cp315-cp315-manylinux_2_39_x86_64.whl on CPython 3.15t
  no   linux-x86_64       built for the GIL build cp315, not free-threaded cp315t; needs glibc 2.39, your floor is 2.34
  no   macos-arm64        built for the GIL build cp315, not free-threaded cp315t; built for manylinux_2_39_x86_64, not macos-arm64
  no   windows-amd64      ...

Output formats

-f text (default, coloured unless NO_COLOR is set), -f json (schema), -f markdown (a table for PR comments or issues), -f github (workflow annotations). --summary FILE and --json-out FILE write extra copies alongside whatever goes to stdout.

GitHub Action

A weekly job that tells you when your last blocker clears:

# .github/workflows/py315.yml
name: ripe for 3.15?
on:
  schedule: [{cron: "0 6 * * 1"}]
  workflow_dispatch:
jobs:
  wheels:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: Blackman99/wheelripe@v0.1.0
        id: ripe
        with:
          python-version: "3.15t"
          platforms: linux-x86_64,macos-arm64,windows-amd64
          fail-on: blocked
      - if: steps.ripe.outputs.ripe == 'true'
        run: echo "Every dependency has a 3.15t wheel. Time to upgrade."
InputDefaultMeaning
path.Lockfile, requirements, pyproject or directory. Space-separated for several.
python-version3.15Target CPython; append t for free-threaded.
platformslinux-x86_64,macos-arm64,windows-amd64Comma-separated platform keys.
fail-onbumpbump, blocked, build or never.
glibc2.34Oldest glibc you deploy on.
macos14Oldest macOS you support.
index-urlSimple-API index to use instead of PyPI, e.g. https://download.pytorch.org/whl/cpu.
extra-index-urlMore simple-API indexes, separated by spaces or newlines; pooled with the first.

For a private index, build the URL from repository secrets. GitHub masks them in the log, and wheelripe never prints credentials anyway:

- uses: Blackman99/wheelripe@v0.1.0
  with:
    path: requirements.txt
    index-url: https://${{ secrets.INDEX_USER }}:${{ secrets.INDEX_TOKEN }}@pypi.corp.example/simple
    extra-index-url: https://pypi.org/simple
OutputMeaning
ripetrue when everything installs from a wheel.
blockedCount blocked upstream (including requires-python exclusions).
bumpCount fixed by a version bump.
reportPath to the JSON report.

The step also writes a Markdown table to the job summary and an annotation per problem package. It runs on Linux, macOS and Windows runners (CI tests all three).

MCP server

wheelripe mcp is a read-only stdio MCP server, so an agent can check before it bumps requires-python or a CI matrix.

{
  "mcpServers": {
    "wheelripe": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/Blackman99/wheelripe", "wheelripe", "mcp"]
    }
  }
}
ToolArgumentsReturns
check_python_upgradepath or requirements[], python, platforms[], glibc, macos, index_url, extra_index_urls[]Markdown table + the full JSON report as structured content.
explain_wheelfilename, python, platforms[]Installs yes/no per platform, with the reason.

Both tools are annotated readOnlyHint; they only read local files and the package index.

Configuration →