wheel
wheel is the PyPA reference implementation of the Python wheel binary distribution format (PEP 427), providing a command-line tool for inspecting, unpacking, repacking, converting, and retagging .whl files. As of v0.46.0, it no longer ships the setuptools bdist_wheel command — that implementation now lives in setuptools ≥70.1. Current stable version is 0.46.3, released on a roughly quarterly cadence with occasional patch releases for CVEs and compatibility fixes.
Warnings
- breaking v0.46.0 removed the bdist_wheel setuptools command implementation from wheel entirely. Projects with setuptools <70.1 that relied on wheel providing the bdist_wheel command will see 'error: invalid command bdist_wheel'. wheel.bdist_wheel is now only an alias pointing at setuptools.command.bdist_wheel.
- breaking wheel.metadata and internal submodules (wheel.cli, wheel._bdist_wheel, wheel.macosx_libfile removed in 0.46.0, temporarily restored in 0.46.1) are private. Importing them may raise ImportError across minor releases with no deprecation cycle.
- breaking wheel.macosx_libfile was removed in v0.46.0 and only temporarily restored in v0.46.1. Any code importing it is relying on an undocumented internal that will disappear again.
- deprecated Importing wheel.bdist_wheel now emits a FutureWarning (was DeprecationWarning before v0.46.2). Custom bdist_wheel subclasses that inherit from wheel.bdist_wheel.bdist_wheel will break in a future release.
- gotcha Adding 'wheel' to build-system.requires in pyproject.toml is no longer necessary or recommended for setuptools-based projects. Listing it unnecessarily forces it to be installed even for sdist-only builds.
- breaking v0.46.0 removed the vendored 'packaging' library and now requires it as an explicit runtime dependency. Environments where packaging is absent (e.g. minimal build containers) will get an ImportError when any wheel CLI command is invoked.
- gotcha CVE-2026-24049 (fixed in v0.46.2): 'wheel unpack' could alter permissions of files outside the destination tree with a maliciously crafted wheel. Any version <0.46.2 unpacking untrusted wheels is vulnerable.
Install
-
pip install wheel -
uv add wheel
Imports
- wheel (CLI entry point)
import subprocess; subprocess.run(['wheel', 'unpack', 'some.whl'])
- bdist_wheel (setuptools command)
from setuptools.command.bdist_wheel import bdist_wheel
- wheel.metadata (private module)
from packaging.metadata import Metadata
Quickstart
import subprocess
import sys
# Demonstrate the four main wheel CLI operations
# 1. Unpack a wheel (verifies RECORD hashes)
# subprocess.run(['wheel', 'unpack', 'someproject-1.0-py3-none-any.whl', '--dest', '/tmp/unpacked'], check=True)
# 2. Repack a previously unpacked wheel directory
# subprocess.run(['wheel', 'pack', '/tmp/unpacked/someproject-1.0', '--dest-dir', '/tmp/repacked'], check=True)
# 3. Retag a wheel (e.g. mark as universal py3)
# subprocess.run(['wheel', 'tags', '--python-tag', 'py3', 'someproject-1.0-py2-none-any.whl'], check=True)
# 4. Convert a legacy .egg to .whl
# subprocess.run(['wheel', 'convert', 'someproject-1.0-py3.egg'], check=True)
# Show installed wheel version
result = subprocess.run(
[sys.executable, '-m', 'wheel', 'version'],
capture_output=True, text=True
)
print(result.stdout.strip())