PEP ### - Wheel Variants¶
Resource | Link |
---|---|
PEP Link |
To Be Published |
DPO Discussion |
Implementation variants: rehashing and refocusing |
Github Repository |
https://github.com/wheelnext/pep_wheel_variants |
Abstract¶
This PEP proposes an evolution of Python Wheels standard to support hardware-specific or platform-dependent package variants. Current mechanisms for distinguishing Python Wheels (i.e Python ABI version, OS, CPU architecture, and Build ID) are insufficient for modern hardware diversity, particularly for environments requiring specialized dependencies such as high performance computing, hardware accelerated software (GPU, FPGA, ASIC, etc.), etc.
This proposal introduces Wheel Variants
, a mechanism for publishing platform-dependent wheels and selecting the most suitable
package variant for a given platform.
To enable fine-grained package selection without fragmenting the Python ecosystem, this PEP proposes:
-
A
Wheel Variant
system that enables multiple wheels for the same Python package version, distinguished by hardware-specific attributes. -
A
Provider Plugin
system that dynamically detects platform attributes and recommends the most suitable wheel. -
A hash-based identification mechanism for wheel variants, ensuring compatibility while maintaining clarity in package naming.
This approach allows seamless package resolution without requiring intrusive changes to installers
, ensures backward
compatibility, and minimizes the burden on package maintainers.
Motivation¶
Existing approaches to handling platform-specific Python packages are suboptimal. Some methods include maintaining
separate package indexes for different hardware configurations, bundling all potential dependencies into a single
"mega-wheel," or creating separate package names (mypackage-gpu
, mypackage-cpu
). Each of these approaches has
significant drawbacks, such as excessive binary size, dependency confusion, and inefficient dependency resolution, etc.
The need for a systematic and scalable approach to selecting optimized wheels based on platform characteristics has become increasingly urgent as Python usage expands across diverse computing environments, from cloud computing to embedded systems and AI accelerators.
Rationale¶
User Stories¶
-
A user wants to install a version of NumPy that is specialized for their CPU architecture.
-
A user wants to install a version of PyTorch that is specialized for their GPU architecture.
-
A user wants to install a version of mpi4py that has certain features enabled (e.g. specific MPI implementations for their hardware).
-
A library maintainer wants to build their library for wasm32-wasi with and without pthreads support.
-
A library maintainer wants to build their library for an Emscripten platform for Pyodide with extensions for graphics compiled in.
-
A library maintainer wants to provide packages of their game library using different graphics backends.
-
SciPy wants to provide packages built against different BLAS libraries, like OpenBLAS and Accelerate on macOS. This is something they indirectly do today
-
Manylinux standard doesn’t cover all use-cases: github.com/pypa/manylinux/issues/1725
Specification¶
Wheel Variants¶
A Wheel Variant
is a Python Wheel designed to support a specific platform configuration. Wheel Variants will
follow an extended filename pattern, incorporating an additional hash to indicate a specific variant:
mypackage-0.0.1~abcd1234-py3-none-any.whl
This ~abcd1234
hash is computed based on platform attributes detected by the user-installed provider plugins
and
aggregated by variantlib
, ensuring uniqueness and scalability while maintaining compatibility with existing tooling.
The variantlib
library will generate these hashes using hashlib.shake_128()
, providing a lightweight and
deterministic method of identifying platform-specific variants.
Provider Plugins¶
A Provider Plugin
detects the characteristics of the host platform and provides relevant metadata to variantlib
.
Each plugin must implement a standard entry point:
[project.entry-points."variantlib.plugins"]
my_plugin = "my_plugin.plugin:MyVariantPlugin"
The plugin itself follows a minimal interface:
from variantlib.config import ProviderConfig
from my_plugin import __version__
class MyVariantPlugin:
__provider_name__ = "my_plugin"
__version__ = __version__
def run(self) -> ProviderConfig | None:
"""
Detects platform attributes and returns a ProviderConfig if applicable.
"""
Integration with installers
¶
Upon package installation, pip/uv/etc.
will:
-
Query
variantlib
for installedProvider Plugins
. -
Generate a list of possible variant hashes based on detected attributes.
-
Search package repositories for matching wheels.
-
Select the most relevant variant based on predefined priority rules.
-
Install the selected wheel, or fall back to a generic version if no variant is found.
-
Users must have control over which plugins are active, with the ability to disable or prioritize them via
pip.conf
orvariant.conf
. -
A
[uv] pip install --no-variant package
option should be available to force installation of generic wheels. -
A
[uv] pip install --variant=abcd1234 package
option should be available to force installation of generic wheels. -
Platform detection can be expensive, it must be cache-able. The following caching policy might be a good start (ultimately up to the tool):
- Run once and cache
- Void at restart
- Void at plugin update
- Void manually:
[uv] pip cache --void variant_cache
Backward Compatibility¶
The introduction of Wheel Variants
does not break existing installer
(pip
, uv
, etc.) versions, as older versions
will simply ignore variant wheels. This is ensured by modifying the standard wheel filename regex ensures that legacy
pip
versions do not mistakenly install incompatible variants.
Security Implications¶
The Provider Plugin
mechanism introduces potential security risks, such as untrusted plugins providing misleading
platform data. To mitigate this:
- Plugins should be sourced from trusted repositories. It's essentially remote code execution at install time.
How to Teach This¶
User documentation will be updated to:
- Explain the concept of
Wheel Variants
and how they improve package selection. - Provide guidance on writing and publishing
Provider Plugins
. - Detail configuration options, such as overriding variant selection or disabling the feature entirely.
- Include debugging instructions for users encountering unexpected behavior.
Reference Implementation¶
A prototype implementation has been developed, demonstrating:
-
variantlib
, the library handling plugin registration and variant selection. -
Demo
Provider Plugins
capable of detectingfictional hardware
andfictional technology
. -
A modified version of
pip
integrating variant-aware package resolution.
Rejected Ideas¶
Several alternative approaches were considered and ultimately rejected:
-
Explicit Package Naming (
mypackage-gpu
,mypackage-cpu
)- Leads to dependency resolution issues and combinatorial explosion of package variants.
-
Bundling All Dependencies into a Single Wheel
- Results in unnecessarily large downloads and inefficiencies.
-
Modifying
pip
Internals Directly- Would impose significant maintenance burden on
pip
maintainers and slow adaptation to new hardware platforms.
- Would impose significant maintenance burden on
-
One index per configuration
- Significant user complexity. Force the user to carefully read the documentation.
- Totally breaks the dependency tree:
transformers => pytorch
Open Issues¶
-
Dependency Management
- How should dependencies be expressed when a package depends on a variant of another package?
-
Lockfile Support
- Should lockfiles store variant hashes or remain variant-agnostic?
-
Platform Detection Edge Cases
- How should plugins handle ambiguous or incomplete hardware information?
- Probably should stay up to the plugin maintainer to decide.
-
How to maintain a source-of-truth
- Everybody who build CUDA-accelerated Wheel Variants need to use exactly the metadata that will be provided to installers.
- Same logic for CPU, every
AVX512
specialized packages need to highlight that feature in the exact same way. - Shall we have a package like
troveclassifiers
to act as a "source of truth"?
Conclusion¶
This proposal outlines a scalable and backward-compatible solution for platform-specific Python Wheel distribution.
By leveraging Wheel Variants
and Provider Plugins
, this mechanism simplifies package installation for users while
maintaining efficiency for package maintainers and repository hosts.