PEP 825 – Wheel Variants: Package Format
- Author:
- Jonathan Dekhtiar <jonathan at dekhtiar.com>, Michał Górny <mgorny at quansight.com>, Konstantin Schütze <konstin at mailbox.org>, Ralf Gommers <ralf.gommers at gmail.com>, Andrey Talman <atalman at meta.com>, Charlie Marsh <charlie at astral.sh>, Michael Sarahan <msarahan at gmail.com>, Eli Uriegas <eliuriegas at meta.com>, Barry Warsaw <barry at python.org>, Donald Stufft <donald at stufft.io>, Andy R. Terrel <andy.terrel at gmail.com>
- PEP-Delegate:
- Paul Moore <p.f.moore at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Draft
- Type:
- Standards Track
- Topic:
- Packaging
- Created:
- 17-Feb-2026
- Post-History:
- 17-Feb-2026
Table of Contents
- Abstract
- Motivation
- Specification
- Definitions
- Implementation requirements
- Variant wheel
- Variant properties
- Variant label
- Variant metadata
- Index-level metadata
- Metadata consistency
- Variant ordering
- Environment markers
- Integration with pylock.toml
- Suggested implementation logic for tools (non-normative)
- Installation example (non-normative)
- Installing wheels from multiple sources (non-normative)
- Rationale
- Backwards Compatibility
- Security Implications
- How to Teach This
- Reference Implementation
- Rejected Ideas
- Open Issues
- Acknowledgements
- Change History
- Appendices
- Copyright
Abstract
This PEP provides the data format for variant wheels, an extension to
Binary distribution format that permits
building multiple variants of the same package while embedding
additional compatibility data. This data is stored inside the wheel, and
expressed via a human-readable variant label in the filename. When
wheels are hosted on an index, it is additionally exposed in a separate
JSON file as an optimization. It will be followed by additional PEPs
defining the remaining aspects of variant wheels. The final aim of the
specification is to make {tool} install {package} capable of
selecting the most appropriate variant of packages where additional
compatibility dimensions such as GPU support need to be accounted for.
Motivation
This PEP proposes a protocol to record additional compatibility data in binary packages, to allow tools to pick the correct package to use in situations where Platform compatibility tags are insufficient. There are many cases where this is necessary, most notably in the case of scientific and machine learning (ML) libraries, where high performance requires extension code that is carefully tailored to the precise hardware available in the user’s environment. Well known examples of this include:
- PyTorch and other ML tools which depend on the user’s GPU hardware and driver.
- Scientific libraries like SciPy, which can be linked to different linear algebra libraries.
- Libraries such as XGBoost that can be linked to different OpenMP runtimes.
- Libraries that ship performance enhanced builds which can be used when certain CPU instruction sets are available, such as AVX2 or AVX-512.
The problem space has been explored in greater detail in PEP 817.
Specification
Definitions
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Implementation requirements
This specification is written from the perspective of file format producers. In the context of format definitions, the word “MUST” specifically indicates that the requirement must be satisfied for the data to be considered valid according to this specification.
Tools that produce the data formats according to this specification (variant wheels, the index-level metadata file) MUST always produce files that meet the requirements of this specification.
Tools that consume the data formats according to this specification are not required to verify that the data meets these requirements, but SHOULD NOT rely on data that they have established does not meet them. The appropriate response depends on the role of the tool, and follows the same pattern as for invalid Core Metadata in wheel files. Tools that are in a position to reject invalid data at the point it enters the ecosystem, such as a package index accepting an upload, SHOULD do so. Tools that encounter it later, such as an installer resolving a dependency, SHOULD prefer to degrade gracefully rather than fail outright, for example by ignoring the variant wheels and selecting among the remaining ones.
Variant wheel
A variant wheel is an extension of the wheel format, defined in Binary distribution format. It MUST specify a variant label in the filename, which makes it distinct from non-variant wheels. It MUST include a variant metadata file, which maps the variant label to zero or more variant properties.
Variant properties
Variant properties express the compatibility of binary packages with specific platforms, in addition to Platform compatibility tags. They follow a key-value format, where a key is called a variant feature. The keys are further grouped into independently governed variant namespaces. Hence, a variant feature consists of a namespace and a feature name, whereas a variant property consists of a namespace, a feature name and a feature value.
Variant properties are serialized into a structured 3-tuple of the following format:
{namespace} :: {feature_name} :: {feature_value}
The properties with which the wheel was built are stored within the wheel, in the variant metadata file. A variant wheel can specify multiple values corresponding to a variant feature. For the wheel to be considered compatible with a system, at least one value for every feature listed in its properties MUST be compatible with the system. A variant wheel with zero properties is always deemed compatible.
The namespace and feature name components MUST be non-empty and consist
only of 0-9, a-z and _ ASCII characters (^[a-z0-9_]+$).
The feature value MUST be non-empty and consist only of 0-9,
a-z, _ and . ASCII Characters (^[a-z0-9_.]+$).
The available properties and the rules governing their compatibility will be defined in a subsequent PEP.
Examples:
# the system must be compatible with all of the following
x86_64 :: level :: v3
x86_64 :: avx512_bf16 :: on
nvidia :: cuda_version_lower_bound :: 12.8
# it must also be compatible with at least one of the following
nvidia :: sm_arch :: 120_real
nvidia :: sm_arch :: 110_real
Variant label
The wheel filename template originally defined by PEP 427 is changed to:
{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}(-{variant label})?.whl
+++++++++++++++++++
The Python tag component MUST NOT start with a digit.
Variant wheels MUST include the variant label component. Conversely,
wheels without variant label are non-variant wheels. The variant label
MUST be non-empty and consist only of 0-9, a-z, _ and .
ASCII characters (^[0-9a-z_.]+$).
Every variant label MUST uniquely correspond to a specific set of variant properties, which MUST be the same for all wheels using the same label within a single package version.
The label null is reserved and always corresponds to the variant
with zero properties, called a null variant. This variant acts as a
fallback variant that is always compatible.
Examples:
- Non-variant wheel:
numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl - Wheel with variant label
x86_64_v3:numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl - Null variant:
numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-null.whl
Variant metadata
The additional metadata specific to variant wheels is stored inside the
wheel, in *.dist-info/variant.json file, using the JSON format. This
PEP defines the following structure:
+- $schema
+- default-priorities
| +- namespace : list[str]
+- variants
+- {variant_label}
+- {namespace}
+- {feature} : list[str] = []
This structure corresponds to the version 0.1.1 of the format. The
version number is stored as part of the schema URL. The version numbers
follow semantic versioning.
The numbers starting with zero are reserved for drafts and MUST NOT be
used in production. Tools MUST NOT make any compatibility assumptions
over these versions. Once the proposal is complete, the latest draft
will be promoted to version 1.0.0.
If a backwards incompatible change is done to the specification, the major version number MUST be incremented, and the remaining version components MUST be zeroed. Tools MUST reject metadata with a major version number that they do not support.
If a backwards compatible change is done to the specification, the minor version number MUST be incremented, and the patch number MUST be zeroed. Installers and other tools that only consume variant metadata SHOULD accept metadata with a newer minor version number than the latest supported, provided that the major version is supported. Tools outputting variant metadata MUST NOT output a version that they do not explicitly support.
The top-level keys, as well as their scope and consistency requirements, are described in the subsequent sections.
Schema
The $schema key is the standard way of specifying the JSON schema used. Its value MUST be the URL of a JSON
schema corresponding to this specification, hosted on
packaging.python.org. The schema URL MUST include a version number,
and consequently every schema MUST describe the matching format version.
The schema can be used to verify the validity of the JSON file prior to
processing it, or after outputting it.
A proposed JSON schema for the current format version is included in the Appendix of this PEP. Subsequent PEPs changing the metadata format will include updated versions of the schema. The schema is available in Appendix: JSON Schema for Variant Metadata.
Default priorities
The default-priorities dictionary defines the ordering of
namespaces which is used in variant ordering. The exact algorithm is
described in the Variant ordering section.
The following key is REQUIRED:
namespace: list[str]: All variant namespaces used in variant wheels for a given package version, ordered in decreasing priority. This list MUST contain all namespaces used in variant properties, and it MUST NOT be empty: a package version providing variant wheels MUST use at least one variant namespace.
Default priorities are defined at the project scope. The value in different wheels SHOULD be identical, or one an extension of the other: additional namespaces MAY be appended. The metadata is considered consistent if the longer list starts with the elements of the shorter list, in the same order. In this case, combining the metadata MUST result in the longer list being used.
Variants
The variants dictionary provides a mapping from variant labels
to variant properties. In an individual variant wheel, it is scoped to
that wheel and it MUST contain exactly one entry, whose key is the
variant label present in that wheel’s filename.
It has 3 levels. The first level keys are variant labels, the second level keys are namespaces, and the third level keys are feature names. The third level values are sets of feature values, converted to lists and sorted lexically.
For the metadata to be consistent, the same keys MUST always correspond
to the same values. When combining metadata, the resulting variants
dictionary MUST be a union of all the input dictionaries.
Example
{
// The schema URL will be replaced with the final URL on packaging.python.org
"$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",
"default-priorities": {
// REQUIRED: specifies that x86_64 CPU properties are more important than
// aarch64 CPU properties (both are mutually exclusive, so the exact order
// does not matter), and both are more important than specific BLAS/LAPACK
// library:
"namespace": ["x86_64", "aarch64", "blas_lapack"],
},
"variants": {
// REQUIRED: in variant.json, always a single entry, with the key
// matching the variant label ("x86_64_v3_openblas") and the value
// specifying its properties (the system must be compatible with both):
// - blas_lapack :: library :: openblas
// - x86_64 :: level :: v3
"x86_64_v3_openblas": {
"blas_lapack": {
"library": ["openblas"]
},
"x86_64": {
"level": ["v3"]
}
}
}
}
Index-level metadata
When a package version that includes at least one variant wheel is
hosted on an index, a corresponding {name}-{version}-variants.json
file MUST be hosted as well. The purpose of the file is to optimize
variant metadata lookups and remove the necessity of fetching multiple
variant wheels during dependency resolution. The {name} and
{version} placeholders correspond to the package name and version,
normalized according to the same rules as wheel files, as found in the
File name convention of the Binary Distribution Format
specification.
The exact URL where the file is hosted is insignificant, but it MUST
be provided in all the responses where the variant wheels are included.
It should follow the rules for files in the
Simple repository API, except that the optional
metadata attributes served by the index (such as core-metadata,
dist-info-metadata, requires-python or yanked) are not
meaningful for that file. Indexes MAY publish or skip these attributes,
as long as the values do not prevent correct operation. Tools MAY either
use or ignore these values.
This file uses the same structure as variant metadata, except that
the variants object is index-scoped and it MUST list all variants
available on the package index for the package version in question. It
MUST be consistent with the variant metadata of the individual
wheels, as specified in metadata consistency.
This file SHOULD NOT be considered immutable and MAY be updated in a backward compatible way at any point (e.g. when adding a new variant).
Variant indexes MAY elect to either auto-generate the file from the uploaded variant wheels or allow the user to manually generate it themselves and upload it to the index.
The foo-1.2.3-variants.json corresponding to the package with two
wheel variants, one of them listed in the previous example, would look
like:
{
// The schema URL will be replaced with the final URL on packaging.python.org
"$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",
"default-priorities": {
// identical to above
},
"variants": {
// REQUIRED: entries for all wheel variants for the package version
// if a null variant is present
"null": {},
// "x86_64_v3_openblas" label corresponds to:
// - blas_lapack :: library :: openblas
// - x86_64 :: level :: v3
"x86_64_v3_openblas": {
"blas_lapack": {
"library": ["openblas"]
},
"x86_64": {
"level": ["v3"]
}
},
// "x86_64_v4_mkl" label corresponds to:
// - blas_lapack :: library :: mkl
// - x86_64 :: level :: v4
"x86_64_v4_mkl": {
"blas_lapack": {
"library": ["mkl"]
},
"x86_64": {
"level": ["v4"]
}
}
}
}
Metadata consistency
The variant metadata carried by the individual variant wheels of a package version, and the index-level metadata file where one is published, all describe the same release, and are required to agree with one another. Gathered in one place, and stated in full in the sections defining the respective keys, the requirements are:
default-priorities.namespace: the lists MUST either be identical, or the longer MUST start with the elements of the shorter one, in the same order. Combining them MUST yield the longer list.variants: the same variant label MUST always map to the same set of properties. Combining them MUST yield the union of the dictionaries.
Both rules are symmetric, so combining metadata that satisfies them gives the same result regardless of the order in which the inputs are processed.
Meeting these requirements is the responsibility of the publisher of the package version. Since the data originates from a single source per project and is copied into the wheels at build time, they are satisfied by construction unless the wheels of one release are built from different inputs.
Tools consuming variant metadata MAY assume that these requirements are met, and are not required to verify it. Where a tool does establish that they are not met, the response described in implementation requirements applies.
Where a user draws wheels for the same package from more than one source, no publisher is in a position to guarantee consistency with the others. Ensuring that the sources being combined are consistent is then the responsibility of the user. Tools are not required to detect or resolve inconsistencies between sources; installing wheels from multiple sources (non-normative) discusses what they can reasonably do instead.
Variant ordering
This specification defines an ordering between different wheels based on the presence of variant metadata.
For the purpose of ordering, the combined variant metadata for all candidate variant wheels MUST be obtained. It can be sourced either from the index-level metadata file, or from the individual wheels, combined as specified in the variant metadata section. Both sources yield the same result, since they are required to be consistent, and tools SHOULD prefer the index-level metadata file where it is available, as obtaining the data from it is considerably cheaper.
Variant properties from all the eligible variant wheels are grouped into features, and features into namespaces. For every namespace, the tool MUST obtain a list of compatible features, and for every feature, a list of compatible values. The method of obtaining these lists will be defined in a subsequent PEP. The items in these lists will be provided in specific order that will impact variant wheel ordering.
The compatible wheels corresponding to a particular combination of package name, version and build number MUST be grouped by their variant label, and a separate group of non-variant wheels MUST be formed. The groups of variant wheels MUST then be ordered according to the following algorithm:
- Construct the ordered list of namespaces by copying the value of the
default-priorities.namespacekey from the combined variant metadata. This isnamespace_orderin the example. - For every namespace, take the ordered list of compatible feature
names obtained previously. This is
feature_orderin the example. - For every feature, take the ordered list of compatible values obtained
previously. This is
value_orderin the example. - For every group, determine the most preferred value corresponding to
every variant feature present in the variant properties corresponding
to the group. This is done by finding among the values the one that
has the lowest position in the ordered property value list. After
this step, a list of features along with their best values is
available for every variant. This is done in the
VariantWheel.best_value_properties()method in the example. - For every item in the list constructed in the previous step,
construct a sort key that is a 3-tuple consisting of
its namespace, feature name and best feature value indices in the
respective ordered lists. This is done by the
property_key()function in the example. - For every group, sort the list constructed in step 4 using the sort
keys constructed in step 5, in ascending order. This is done by the
VariantWheel.sorted_properties()method in the example. - To order groups, compare their sorted lists from step 6. If the
sort keys at the first position are different, the group with the
lower key is sorted earlier. If they are the same, compare the keys
at the second position, and so on, until either a tie-breaker is
found or the list in one of the groups is exhausted. In the latter
case, the group with more keys is sorted earlier. As a fallback,
if both groups have the same number of keys, they are ordered
lexically by the variant label, ascending. This is done by the
ultimate step of the example algorithm, with the comparison function
being implemented as
VariantWheel.__lt__().
The algorithm sorts the group of null variant wheels last, as they feature no variant properties. The group of non-variant wheels MUST be placed after all the other groups.
Within every group, the wheels MUST then be ordered according to their platform compatibility tags. After this process, the variant wheels are sorted from the most preferred to the least preferred.
The tools MAY provide options to override the default ordering, for example by specifying a preference for specific namespaces, features or properties. The tools MAY also provide options to exclude specific variants, or to select a particular variant. These options operate on the wheels that were found compatible, so they MAY reorder or narrow that set, but MUST NOT cause a wheel to be selected whose properties the target system does not support. Installing a variant wheel for a system other than the one being installed to is instead a matter of overriding which properties are considered supported, which is out of scope for this PEP.
Alternatively, the sort algorithm for variant wheels could be described using the following pseudocode. For simplicity, this code does not account for non-variant wheels or the subsequent ordering by platform compatibility tags.
from typing import Self
def get_compatible_feature_names(namespace: str) -> list[str]:
"""Get an ordered list of compatible features"""
...
def get_compatible_feature_values(namespace: str, feature_name: str) -> list[str]:
"""Get an ordered list of compatible values"""
...
# default-priorities dict from combined variant metadata
default_priorities = {
"namespace": [...], # : list[str]
}
# 1. Obtain the ordered list of namespaces from the variant metadata.
namespace_order = default_priorities["namespace"]
# 2. Obtain the ordered lists of features.
feature_order = {
namespace: get_compatible_feature_names(namespace)
for namespace in namespace_order
}
# 3. Obtain the ordered lists of feature values.
value_order = {
namespace: {
feature_name: get_compatible_feature_values(namespace, feature_name)
for feature_name in feature_order[namespace]
} for namespace in namespace_order
}
def best_value_property(namespace: str, feature_name: str, feature_values: str) -> str:
"""Helper function to determine the best value for given feature"""
for best_value in value_order[namespace][feature_name]:
if best_value in feature_values:
return best_value
assert False, "No feature value supported, wheel should have been filtered out"
def property_key(prop: tuple[str, str, str]) -> tuple[int, int, int]:
"""Construct a sort key for variant property (akin to step 5.)"""
namespace, feature_name, feature_value = prop
return (
namespace_order.index(namespace),
feature_order[namespace].index(feature_name),
value_order[namespace][feature_name].index(feature_value),
)
class VariantWheel:
"""Example class exposing properties of a variant wheel"""
label: str
# {namespace: {feature_name: [feature_values]}}, as in variant.json
properties: dict[str, dict[str, list[str]]]
def best_value_properties(self: Self) -> list[tuple[str, str, str]]:
"""Determine the most preferred values for every feature, step 4."""
return [
(
namespace,
feature_name,
best_value_property(namespace, feature_name, feature_values),
)
for namespace, features in self.properties.items()
for feature_name, feature_values in features.items()
]
def sorted_properties(self: Self) -> list[tuple[str, str, str]]:
"""Sort the list of features with their best values (step 6.)"""
return sorted(self.best_value_properties(), key=property_key)
def __lt__(self: Self, other: Self) -> bool:
"""Variant comparison function for sorting (part of step 7.)"""
self_properties = self.sorted_properties()
other_properties = other.sorted_properties()
# Proceed from the first to the last common sort best-value property.
# If any of them are different, the variant with better property wins.
for self_prop, other_prop in zip(self_properties, other_properties):
if self_prop != other_prop:
return property_key(self_prop) < property_key(other_prop)
# If the best-value properties of one variant are a subset of another,
# the one with more properties wins.
if len(self_properties) != len(other_properties):
return len(self_properties) > len(other_properties)
# If two variants have exactly the same properties, fall back to
# sorting on variant label (they must be unique).
return self.label < other.label
# A list of variant wheels to sort.
variant_wheels: list[VariantWheel] = [...]
# 7. Order variant wheels by comparing their sorted properties
# (see VariantWheel.__lt__())
variant_wheels.sort()
Environment markers
Four new environment markers are introduced in dependency specifications. Unlike the markers defined by the Dependency specifiers specification, their values are not the same for every wheel: they are scoped to the variant properties that the wheel being processed was built for. They MUST be obtained as described in evaluating variant markers. These are:
variant_label: a string, expressing the exact variant label of the wheel being processed. For non-variant wheels, it is an empty string.variant_properties: a set of allnamespace :: feature :: valuetuples of the properties corresponding to the variant label that are compatible with the target system. For non-variant wheels, it is an empty set.variant_features: a set of allnamespace :: featurepairs corresponding to the properties invariant_properties.variant_namespaces: a set of all namespaces of all the properties invariant_properties.
variant_label is a String field, while variant_properties,
variant_features and variant_namespaces are Set of String
fields. The operators available for each, and their semantics, are those
defined for the respective field types in
Dependency specifiers.
Implementations MUST ignore differences in whitespace around the ::
separators when matching features and properties.
Evaluating variant markers
The variant markers MUST only be used in dependency specifiers, and they MUST NOT take part in selecting a wheel: they gate the individual dependency specifiers of a wheel that has already been selected. They MUST be evaluated only once variant wheel selection, as described in variant ordering, has taken place.
Their values MUST be determined as follows:
variant_labelis the variant label of the selected wheel, as found in its filename.- The properties that the
variantsdictionary of the variant metadata maps to that label are taken, and expanded intonamespace :: feature :: valuetriples for every listed feature value. Either the variant metadata contained in the wheel itself or the index-level metadata MAY be used for this, as the consistency requirements guarantee that the two agree. - That set is filtered to the variant properties that the target system
supports, as already determined during variant wheel selection.
variant_propertiesis the result. Since a wheel can only be selected if the target system supports it, and that requires at least one supported value for every feature the wheel declares, this step never removes a feature entirely. variant_featuresandvariant_namespacesare derived fromvariant_properties.
For non-variant wheels, variant_label is an empty string and the
three set-valued markers are empty sets. No variant metadata is needed
in order to evaluate variant markers for such wheels.
Example
The following dependency specifiers illustrate the four markers and the operators permitted with each of them:
# satisfied by the variant "foobar"
dep1; variant_label == "foobar"
# satisfied by any wheel other than the null variant
# (including the non-variant wheel)
dep2; variant_label != "null"
# satisfied by the non-variant wheel
dep3; variant_label == ""
# satisfied by any "foo :: * :: *" property
dep4; "foo" in variant_namespaces
# satisfied by any "foo :: bar :: *" property
dep5; "foo :: bar" in variant_features
# satisfied only by "foo :: bar :: baz" property
dep6; "foo :: bar :: baz" in variant_properties
# equivalent
dep7; "foo::bar::baz" in variant_properties
The filtering in step 3. is only observable where a variant feature lists multiple values, of which the target system needs to support just one (see variant properties). Consider a wheel whose properties include both of:
nvidia :: sm_arch :: 120_real
nvidia :: sm_arch :: 110_real
On a system that provides both architectures, variant_properties
contains both properties. On a system that provides only the former, it
contains nvidia :: sm_arch :: 120_real alone, and a dependency
specifier testing for nvidia :: sm_arch :: 110_real is therefore not
satisfied.
Integration with pylock.toml
Variant wheels can be listed in pylock.toml file in the same manner
as wheels with different Platform compatibility tags: either all variant
(and non-variant) wheels can be listed, or a subset of them.
A new [packages.variants-json] subtable is added to the file. It
MUST inline combined variant metadata, following the same format as the
index-level metadata file, converting the JSON structure into the
respective TOML types. The $schema key MUST be preserved to
facilitate versioning. The tools MAY remove the entries of the
variants dictionary whose labels do not occur among the wheels
listed for the package, along with any namespaces that are thereby left
unused in default-priorities.namespace. The entry for every label
that does occur MUST be retained in full, as evaluating variant
markers requires the complete set of properties corresponding to the
selected label.
If variant wheels are listed, the tool SHOULD resolve variants to select the best wheel file.
Variant environment markers occurring in the dependency specifiers of
a locked package are evaluated in the context of the wheel selected for
that package’s entry, as described in evaluating variant markers. No
further context is needed in the lock file: the markers are evaluated
only once that wheel has been selected, and every package entry resolves
its own wheel. Since variant markers may only be used in dependency
specifiers, they cannot occur in packages.marker or in the top-level
environments key, neither of which is scoped to a selected wheel.
Proposed specification update
The proposed text for pylock.toml Specification follows:
[packages.variants-json]
- Type: table
- Required?: no
- Functions:
- Inline variant selection metadata for the package.
- The structure of this table MUST conform to the JSON Schema.
- Tools that support variant-aware resolution MUST validate this table against the referenced schema.
- Tools that do not support variant-aware resolution MAY ignore this table but SHOULD preserve it when rewriting the lock file.
Example
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.14"
[[packages]]
name = "numpy"
version = "2.3.4"
index = "https://pypi.anaconda.org/mgorny/simple"
wheels = [
{ url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-linux_x86_64-openblas.whl", hashes = {} },
{ url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-linux_x86_64-x86_64_v4_mkl.whl", hashes = {} },
{ url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-macosx_13_0_x86_64-accelerate.whl", hashes = {} },
{ url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-macosx_13_0_x86_64-openblas.whl", hashes = {} },
]
[packages.variants-json]
"$schema" = "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json"
[packages.variants-json.default-priorities]
namespace = [ "x86_64", "aarch64", "blas_lapack" ]
[packages.variants-json.variants]
null = { }
x86_64_v3_openblas = { "blas_lapack" = { "library" = ["openblas"]}, "x86_64" = { "level" = ["v3"]} }
x86_64_v4_mkl = { "blas_lapack" = { "library" = ["mkl"]}, "x86_64" = { "level" = ["v4"]} }
Suggested implementation logic for tools (non-normative)
Installing a package from an index
When asked to install a version of a package from an index, the proposed behavior would be to:
- Query the remote index for the package in question.
- Initially select a package version meeting the version constraints (this does not need to take variant metadata into account).
- Filter available wheels based on Platform Compatibility Tags.
- Determine if any of the remaining wheels are variant wheels. If not, proceed as with non-variant wheels.
- If any wheels feature a variant label, obtain the combined variant
metadata. Normally this means downloading the index-level
metadata file,
{name}-{version}-variants.json. If the source does not provide that file, the combined metadata can instead be read from the candidate wheels. Only one wheel per distinct variant label needs to be inspected, and only the variant metadata file within it, rather than the whole wheel. Where this is still too expensive, a tool may treat the variant wheels as incompatible and proceed with the non-variant wheels instead. - Map the variant labels into sets of variant properties using the combined variant metadata. If any of the labels present in wheel filenames are missing from it, assume that the respective wheels are incompatible.
- Obtain the ordered lists of compatible variant properties. The mechanism for this will be specified in a subsequent PEP.
- Filter and order variants based on the lists of compatible properties, per variant ordering, and select the most preferred variant. If no variant wheel matched, use the non-variant wheels by their rules.
- If multiple wheels for a given version share the same variant label, order them by Platform compatibility tags and build number, and select the best wheel.
- Read the dependencies of the selected wheel, and evaluate the environment markers occurring in them, using the label of the selected wheel and those of its variant properties that the target system supports, as described in evaluating variant markers.
Note that steps 4. through 8. are introduced specifically for variant wheels. The remaining steps correspond to the current installer behavior. Step 10. is modified through the presence of new environment markers.
The same algorithm applies to sources other than an index, such as a local directory of wheels.
Installing a specific local wheel
When asked to install a local wheel file, the proposed behavior would be to:
- If no variant label is present in the filename, proceed as with non-variant wheels.
- Verify the wheel compatibility via Platform compatibility tags.
- Read the variant metadata from
*.dist-info/variant.jsoninside the wheel file. - Obtain the ordered lists of compatible variant properties. The mechanism for this will be specified in a subsequent PEP.
- Verify the wheel compatibility via compatible properties.
- Read the dependencies of the wheel, and evaluate the environment markers occurring in them, using the label of the wheel and those of its variant properties that the target system supports, as described in evaluating variant markers.
Publishing variant wheels on an index
Variant wheels are uploaded to an index just like regular wheels.
There are two possible approaches to publishing the index-level
{name}-{version}-variants.json file for every package version:
it can either be prepared and uploaded by the user, or it can be
generated automatically by the index.
If the index is responsible for generating the file, it should use some mechanism to defer publishing it until the release is fully uploaded (for example, PEP 694).
To generate the {name}-{version}-variants.json file, take the
*.dist-info/variant.json files of all the variant wheels for a given
package version and combine them, as specified for the individual keys
in the default priorities and variants sections. The result does
not depend on the order in which the wheels are processed.
Installation example (non-normative)
Let’s say that PyTorch publishes a number of variant wheels:
torch-2.13.0-{py}-{abi}-{platform}-cuda12.6.whl
^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-cuda13.0.whl
^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-cuda13.2.whl
^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-rocm7.2.whl
^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-null.whl # CPU-only
^^^^
The highlighted filename parts are the variant label.
Each of these wheels carries a variant metadata file that contains:
{
"$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",
"default-priorities": {
"namespace": ["nvidia", "amd"]
},
"variants": {
// ...
}
}
In every wheel, the variants dictionary contains a single key that
is the variant label and whose value lists all properties corresponding
to that label. For example, the cuda* variant wheels contain
properties expressing the compatibility with NVIDIA GPUs, whereas
rocm* variant wheels the compatibility with AMD GPUs. The null
variant has no properties.
In addition to these variant wheels, a torch-2.13.0-variants.json
file is published with the variant metadata merged from individual
wheels. It has the same contents as the example, except that the
variants dictionary includes all variant labels and their
properties.
When a package manager is requested to install torch, in order:
- The index is queried to determine available wheels. It is established that 2.13.0 is the newest version and it is selected.
- The available 2.13.0 wheels are filtered by Platform compatibility tags. Only wheels that are compatible with the current system remain.
- The
torch-2.13.0-variants.jsonfile is found in the index response and it is downloaded. Its contents are read to determine the mapping from variant labels to sets of variant properties, as well as the namespace preference order. - The lists of compatible features and feature values are obtained for
all namespaces that are used in the
variantsdictionary. Wheels with variant labels corresponding to properties that aren’t on these lists are incompatible and are filtered out.For example:
- The
cuda*labels map to anvidia :: cuda_version_lower_boundproperty whose value specifies the minimum CUDA driver version, andnvidia :: sm_archproperties whose values list supported GPUs. The installer queries the driver (if available) to determine whether a compatible runtime and one of the compatible GPUs are available. If it cannot find the driver, a compatible runtime version or a compatible GPU, the wheels are removed from the list. - Similarly, the
rocm*labels map to aamd :: rocm_versionproperty that specifies the supported ROCm version andamd :: gfx_archproperties that list supported GPUs. The installer queries the appropriate driver in a similar manner as before. If it cannot find the driver, a compatible runtime version or a compatible GPU, the wheels are removed from the list. - The
nulllabel always corresponds to an empty property set, and it is therefore always compatible.
On a system with a compatible NVIDIA GPU and a CUDA runtime, at least one of the
cuda*wheels and thenullwheels will remain on the list. - The
- If variant wheels with multiple different labels remain on the list,
the results are sorted per the algorithm in variant ordering.
The most preferred label is selected.
For example, in this case the
cuda*wheels are ordered by their properties, using the lists obtained in step 4. The wheels for CUDA 13 will sort before the ones for CUDA 12, as newer CUDA versions are preferred. Thenullwheel always sorts last, so it would be selected only if none of the GPU wheels were compatible. - If at this point multiple wheels with the same label remain on the
list, the final selection is performed based on Platform
compatibility tags. This is a rare occurrence and it does not apply
here.
It could happen, for example, if the same wheel variant was provided both with
abi3andcp315tags. When installing for Python 3.15, the installer would choose between these two based on the tag. - The metadata for the selected wheel is processed. The variant
properties corresponding to the wheel, narrowed to those the system
was found to support in step 4, are used to process environment
markers. This results in additional CUDA-related dependencies being
selected.
Suppose the wheel also depends on a library that supports only one of the architectures the wheel supports:
fast-gemm; "nvidia :: sm_arch :: 120_real" in variant_properties
On a system with an older GPU,
120_realis not among the supported properties found in step 4, so the narrowing removes it and this dependency is not selected. - The wheel is downloaded and installed.
Installing wheels from multiple sources (non-normative)
As of the time of writing, there are no accepted standards addressing
the support for installing packages from multiple sources, and the
existing tools (such as pip and uv) disagree on the exact
behavior. This problem is described in more detail in the informational
PEP 766. Variant wheels expand the problem scope. The consistency
requirements that make variant metadata combinable hold within a single
project, and nothing obliges independent publishers to meet them with
respect to one another: the same variant label may map to different
properties, and namespace orderings chosen independently need not be
extensions of one another. Establishing whether the metadata from two
sources happens to be combinable is possible, but the cost of doing so
in the general case is prohibitive, and there is no correct answer when
it is not. For these reasons, the specification does not attempt to
standardize a behavior, but instead considers it implementation-defined
and provides a few non-normative suggestions on the possible solutions.
It is entirely valid for tools not to support this behavior, either by not providing support for using multiple sources at all, or by rejecting to proceed if more than one of the sources includes variant wheels.
When processing variant wheels from different sources, it is recommended to consider their variant metadata in isolation. Matching variant labels or namespaces do not establish that they have the same meaning across sources.
A tool that searches sources in priority order (for example, the “index priority” in PEP 766) can order variants from one source at a time using the variant ordering algorithm, and proceed to the next source only if the current one has no viable candidates. No cross-source metadata merge is necessary.
A tool that collates candidates from all sources before selecting among them (for example, “version priority” in PEP 766) must compare wheels from different sources directly. For a package version, if exactly one source provides compatible variant wheels, those variants can be selected ahead of non-variant wheels, as generally variant wheels are preferred over non-variant wheels. If multiple sources provide compatible variants, their metadata can be combined unambiguously only when the metadata is consistent as specified in the sections corresponding to the individual metadata keys.
When metadata cannot be combined unambiguously, there is no uniquely correct global ordering. Valid tool-specific choices include:
- refusing to install with an error
- printing a warning and ignoring variant wheels, falling back to selection among non-variant wheels
- using a deterministic criterion for selecting among multiple compatible variant wheels, for example by preferring the wheel from the index that came earlier in the option arguments
- requesting additional input from the user
These choices can produce a valid installation without guaranteeing a globally optimal selection. Silently fabricating a combined order or resolving conflicting label mappings is technically possible, but discouraged: it fabricates semantics that no source declared.
Rationale
This PEP is part of a larger variant wheel design that was originally proposed as PEP 817. However, due to its complexity, we decided to split it into smaller parts that build one upon another. This PEP is the first in the series, providing foundations including the file format along with necessary metadata, index support and basic tool algorithms. Aspects such as providing actual variant properties or building wheels are deferred into subsequent PEPs.
Variant wheels use structured variant properties to express multidimensional wheel compatibility matrices. Properties are organized in namespaces that can be defined and governed independently. The key-value structure makes the properties more flexible: adding a new compatibility axis can be done by adding a new key. It can support both AND-style dependencies (for example, a CPU plugin could define multiple keys corresponding to different instructions sets, all of which are used in the package and therefore must be supported) and OR-style dependencies (for example, a GPU plugin can define a single key listing multiple GPU types, indicating that all of them are supported by the package, and therefore the users needs to own only one of them).
The specification does not impose any formal limits on the number of properties expressed, and specifically accounts for the possibility of property sets being very long (for example, a long list of GPUs or CPU extension sets). To avoid wheel filenames becoming hard to comprehend because of excess of information and potentially causing technical issues because of their length, the property lists are stored inside the wheel and mapped to a short label that is chosen by the package maintainer and intended to be human-readable.
Variant metadata is stored in an additional JSON format file rather than
being added to the Core metadata specifications. It is
versioned independently, and tools that are not specifically concerned
about variant metadata can ignore its compatibility rules. Its
versioning is similar in spirit to that of Core Metadata. JSON provides
a more convenient format for structured data, as well as more natural
conversion from TOML (so that the data can be sourced from
pyproject.toml).
Wheel filenames alone do not provide sufficient metadata to drive variant wheel selection. To avoid tools having to fetch the variant metadata straight from multiple wheel files, the metadata from wheels for every package version is combined and republished. This metadata is scoped to a single package version to permit variants changing in the future version.
The index support aims to account for three scenarios:
- An index implementation that cannot embed additional metadata as part of file list responses. For example, this covers installing straight from a directory listing created by a webserver. To account for this scenario, index-level metadata is published as a plain JSON file that can be generated by the package maintainer and placed alongside wheels.
- An index implementation that has more complete wheel support but does
not wish to implement full variant wheel support immediately. The
index needs only to permit the user to upload said JSON file. To
account for minimalistic implementation, the specification permits
the index to treat said file similarly to a wheel, including
publishing attributes such as
yanked, as long as their values do not prevent clients from working. - An index implementation that implements complete wheel variant support. Such an index will parse uploaded variant wheels, and dynamically create the index-level metadata. The JSON file path would then be treated as an API endpoint rather than an actual file.
Since JSON format does not feature a set type, sets in the metadata are represented as sorted lists. Sorting ensures reproducibility and makes it possible to use equality comparison over whole dictionaries without having to convert specific fields back to sets after deserialization.
The variant ordering algorithm has been proposed with the assumption that variant properties take precedence over Platform compatibility tags, as they are primarily used to express user preferences. This accounts for possible divergence of platform tags, e.g. because a CUDA variant may require a different minimal libc version, in which case the selection should be driven by the desired CUDA preference rather than incidental platform tag difference.
While a future PEP will define how variant properties are provided, a baseline assumption is made that the compatible properties will be provided in specific order corresponding to their preference. This makes it possible to use a generic sorting algorithm, and later define properties as data without having to change the algorithm.
A future PEP will define how the ordering for features and values is provided. However, namespaces are governed independently and considered on equal footing, and therefore there will be no standard ordering for them. Instead, the ordering of namespaces will be explicitly stated in the variants metadata, which in turn will be provided by the package maintainer as part of the build process.
In the vast majority of real use cases, ordering based on properties will suffice. However, in a pathological case two different variant wheels may end up with equal sort keys. To provide reproducible results in this case, fallback sorting on variant label is performed.
A concept of null variant is introduced that is distinct from non-variant wheels to facilitate a transition period. This variant is always supported by tools implementing this PEP, and takes precedence over non-variant wheel. It can therefore be used to provide a distinct fallback for the cases of no other variant being supported and variant wheels being unsupported altogether. For example, PyTorch could provide a much smaller null variant that is used when no GPU is supported, and a fallback non-variant wheel built for the default CUDA version.
pylock.toml integration inlines the variant metadata to keep the
file standalone. This can avoid the additional network call that would
be required to fetch the file, and avoids having to pin to a specific
hash that could cause problems if the file changed on the index, either
due to the variant metadata being updated or being generated in a way
that does not guarantee stable bytewise output.
Variant environment markers
Variant properties take part in installing a variant wheel at two distinct points, and only the second of them concerns markers. An installer first selects a package version, filters the wheels for that version by Platform compatibility tags, and then filters and orders the remaining variant wheels using their variant properties, checked against the properties that the target system supports; tools may override the resulting choice. Only afterwards are the dependencies of the selected wheel read, and the variant markers occurring in them evaluated.
Filtering and ordering wheels is therefore driven by variant properties, not by markers. Markers never gate the selection of a wheel; they only gate individual dependency specifiers, and they are evaluated only once a wheel has been selected. Were it otherwise, a marker would have to be evaluated before the wheel whose properties it refers to was known.
The values of the three set-valued markers are filtered to the variant
properties that the target system supports. A wheel lists every value it
runs on, so without that step a dependency gated on one of them would be
installed wherever the wheel runs. A wheel built for GPU architectures
from 80_real to 120_real may depend on a library that supports
only 120_real, much as a dependency that supports a single CPU
architecture is gated on platform_machine. Where a dependency does
exist for every value of a feature, it can instead be published as a
variant package and depended upon unconditionally, leaving the choice to
variant ordering.
Because of this filtering, the variant markers do not depart from the
established meaning of an environment marker. Every property in
variant_properties is by construction supported by the target
system, so the three set-valued markers describe the environment, just
as the markers defined in Dependency specifiers do.
What is specific to variant wheels is the vocabulary rather than the
semantics. The existing markers expose a fixed set of environment
attributes to every wheel alike, whereas a variant property has to be
declared by the wheel before it can be observed at all: the wheel’s
variant metadata determines which part of the environment its
dependency specifiers are able to see. variant_label is the
exception, as it names the selected variant and says nothing about the
environment beyond the fact that this variant was deemed compatible.
Three consequences of this design are worth noting:
- Filtering never removes an entire feature or namespace, since a wheel
can only be selected if the target system supports at least one value
for every feature it declares (see variant properties).
variant_featuresandvariant_namespacestherefore always list every feature and namespace the wheel was built for. This is why the overrides permitted in variant ordering may not reach past the compatibility filter: a wheel selected in spite of being unsupported could have its properties filtered away, and the dependencies gated on them would silently disappear. - For the null variant,
variant_labelis"null"and the three set-valued markers are empty sets, as the null variant has zero properties.variant_labelis consequently the only marker that distinguishes a null variant from a non-variant wheel. - A marker referring to a property, feature or namespace that the wheel does not declare cannot be satisfied in any environment, since filtering only ever removes properties. Such markers can therefore be resolved at build time, which is what makes the partial evaluation described in Backwards Compatibility possible.
Backwards Compatibility
Variant wheels add an additional variant label component to the wheel filename. A complete filename verification step should reject such wheels:
- If both the build tag and the variant label are present, the filename
contains too many components. Example:
numpy-2.3.2-1-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl ^^^^^^^^^^ - If only the variant label is present, the Python tag at third position
will be misinterpreted as a build number. Since the build number must
start with a digit, the filename is considered invalid. Example:
numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl ^^^^^
Currently, no Python tags start with a digit. To guarantee unambiguity, the specification enforces that going forward. Tools commonly used to install wheels at the time of writing implemented a verification algorithm of that kind, making it possible to publish variant wheels on an index alongside non-variant wheels without risk of them being installed accidentally.
Tools that do not perform full filename verification will consume some or all variant wheels as regular wheels. This may cause unexpected behavior or breakage if the tool in question needs to specially account for variant wheels.
The libraries for processing wheel files and their consumers will need to be updated to handle the new filename component and possibly the new metadata. For example, there is an open discussion in packaging project how to adapt the parse_wheel_filename() function.
The addition of the variant label increases the filename length. On platforms with a low total path length limit such as Windows, long filenames are a concern. However, given that the name and version components are already unrestricted, we do not set a specific limit in this PEP. Others, such as PyPI, may set a limit for total filename length.
Aside from this explicit incompatibility, the specification makes
minimal and non-intrusive changes to the binary package format. The
variant metadata is stored in a separate file in the .dist-info
directory. Tools that are not directly concerned with variants need only
to update their filename verification algorithm (if there is one) and
preserve the contents of said directory.
If the new environment markers are used in wheel dependencies, these wheels will be incompatible with existing tools. For example, upon meeting these markers in a dependency from an index, pip will backtrack and use an older dependency version (if possible). This is a general problem with the design of environment markers, and not specific to wheel variants. It is possible to work around it by partially evaluating environment markers at build time, and removing the markers or dependencies specific to variant wheels from the non-variant wheel.
Security Implications
The presence of variant wheels may lead to some of the variants being subject to less scrutiny than others, and as such becoming easier attack targets. Particularly, once variant wheel support becomes commonplace, the non-variant wheels for some packages may be only consumed by users with outdated tools. However, such attacks assume that the package publishing workflow is already compromised, in which case more plausible attack vectors are available, for example via modifying compiled extensions.
How to Teach This
This PEP is oriented at tool authors. Its changes will be integrated into Binary distribution format and other PyPA specifications. Teaching variants to end users will be covered in a subsequent PEP, as user experience details are addressed.
Reference Implementation
The variantlib project contains a reference implementation of a complete variant wheel solution. It is compliant with this PEP, but also goes beyond it, providing example solutions to some of the deferred items.
A client for installing variant wheels is implemented in a uv branch.
Rejected Ideas
Predictable variant labels
The specification proposes that variant labels are arbitrary, and variant properties are mapped to them via a variant metadata file rather than expressed directly in them. While it could be technically possible to create variant labels from variant properties, this would either require permitting very long filenames that will cause issues with some platforms, or imposing arbitrary limits on variant property counts, making the specification less suitable for addressing multidimensional compatibility matrices.
An alternative approach was to use a hash of variant properties. While such an approach is technically valid and can provide short unique labels for arbitrarily large variant property sets, it makes the labels opaque and therefore difficult to read or reason about.
Variant label as part of Platform compatibility tag
The specification adds the variant label as a separate component,
therefore breaking compatibility with existing tools. It could be
technically possible to preserve partial compatibility by appending it
to one of the Platform compatibility tags instead, in which case
installers would reject the wheel based on platform (or Python
interpreter) incompatibility, while other tools could still use it.
However, the authors decided it safer to break the backwards
compatibility. Additionally, reusing tags posed a potential risk of
wheel labels being incorrectly combined with compressed tag sets. For
example, a manylinux_2_27_x86_64.manylinux_2_28_x86_64+x86_64_v3 tag
would be incorrectly deemed compatible because of the
manylinux_2_27_x86_64 part.
Removing ordering information from wheel files
The specification proposes that all the data needed to order wheel
variants is stored within the variant metadata (the default
priorities dictionary). This data is expected to originate from a
common source per project (a subsequent PEP will propose an integration
within pyproject.toml file) and to be copied into every variant
wheel at build time, and afterwards into the index-level metadata
file.
It has been argued that this makes the ordering data a wheel-level property which, once inserted into a particular wheel, says something about other wheels. That is not the case. The data is project-level metadata that is copied into the wheel, and like the other project metadata carried there, it does not reference other wheels. The ordering data can specify namespaces for which no variant wheels exist in a particular release, and nothing in the format depends on the presence of any specific other wheel.
Furthermore, this design specifically ensures that the index-level metadata file is a cache rather than a first-order data source. Since all the data is stored in the wheels:
- It is possible to generate the index-level metadata file based on available wheels alone, without any additional input data. Notably, this empowers indexes to generate it automatically without requiring any changes to the tools or workflows used to upload wheels.
- It is possible to select across multiple wheels even in absence of index-level metadata file, for example when installing from a local directory.
There is indeed a real risk that two wheels built at different times and with different tooling may end up having inconsistent metadata. However, the specification requires consistency and makes the publisher of the package version responsible for it, as described in metadata consistency.
It has also been suggested that detaching the ordering data from variant metadata would make it possible for tools to accept an override of that data in a standard format. However, there is no relation between the two; such a format can be introduced either way, for example using a subset of variant metadata.
Out of scope
The following problems are deferred to subsequent PEPs in the series:
- governance of variant namespaces
- determining which variant properties are compatible with the system
- overriding the compatibility detection using static data
- building variant wheels
Open Issues
These questions must be resolved before this PEP can be accepted.
Use of variant environment markers
The design of the variant environment markers is not yet settled. The same effect can be achieved through Dynamic dependencies; the open question is whether markers are the right mechanism for obtaining it while keeping dependency metadata static across a release. This is under discussion in this thread. The specification reflects the current design.
Acknowledgements
This work would not have been possible without the contributions and feedback of many people in the Python packaging community. In particular, we would like to credit the following individuals for their help in shaping this PEP (in alphabetical order):
Alban Desmaison, Bradley Dice, Chris Gottbrath, Dmitry Rogozhkin, Emma Smith, Geoffrey Thomas, Henry Schreiner, Jeff Daily, Jeremy Tanner, Jithun Nair, Keith Kraus, Leo Fang, Mike McCarty, Nikita Shulga, Paul Ganssle, Philip Hyunsu Cho, Robert Maynard, Vyas Ramasubramani, and Zanie Blue.
Change History
- 10-Aug-2026
- Decoupled most of the specification from index-level metadata, clarifying that it is only an optimization for scenarios where wheels are published on an index.
- Added non-normative guidance for installing variant wheels from multiple sources.
- Added an explicit “Implementation requirements” section.
- Clarified the scope of the individual variant metadata keys, and stated the consistency requirements for each of them alongside.
- Added “Removing ordering information from wheel files” to rejected ideas.
- Removed
default-priorities.featureanddefault-priorities.property. - Made schema versioning use semantic versioning, with its backwards compatibility implications.
- Improve environment marker content. Make
variant_propertiesmarker use variant properties compatible with the system rather than all the properties specified in the metadata. - Update pylock.toml section to explain environment marker usage.
- Various smaller fixes for language and design consistency.
- 11-May-2026
- Added replacing platform compatibility tags entirely to rejected ideas.
- Clarified interpretation of sorting algorithm and index support.
- 06-Apr-2026
- Added a formal requirement that Python tags must not start with a digit.
- Expanded backwards compatibility concerns regarding tools that do not perform full filename verification.
- 09-Mar-2026
- Clarified that feature values in
variantsdictionary are sets, and that they ought to be sorted when serializing. - Changed the rule for merging variant metadata to state that the result must be the same irrespective of wheel order. This conveys the goal of avoiding ambiguous results clearer.
- Clarified that feature values in
- 17-Feb-2026
- Initial version, split from PEP 817 draft.
- Corrected the variant ordering algorithm to order variants per the best value that is compatible with the system, for every feature, rather than all compatible values, and add a fallback to ordering on variant label.
- Removed the variant label length limitation.
- Changed
pylock.tomlintegration to inline variant metadata rather than storing a URL and a hash.
Appendices
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.