From a944e55cb40c2c23381cf89b288c41138e4205e0 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 7 Apr 2026 21:51:07 +0200 Subject: [PATCH 1/4] Decouple default glibc from MANYLINUX_TAGS maximum The test_manylinux_tags test incorrectly asserted that the default glibc version must equal the maximum of MANYLINUX_TAGS. This forced contributors to bump the default glibc whenever adding a new tag, even though these are independent concerns: the default glibc is a conservative policy for the target system, while MANYLINUX_TAGS entries are capabilities available via --virtual-package-spec. Relax the assertion to set inclusion (default glibc versions must be covered by MANYLINUX_TAGS) and remove the misleading "keep in sync" comments that guided contributors toward the wrong invariant. Made-with: Cursor --- conda_lock/default-virtual-packages.yaml | 3 --- conda_lock/pypi_solver.py | 2 -- tests/test_conda_lock.py | 8 +++++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/conda_lock/default-virtual-packages.yaml b/conda_lock/default-virtual-packages.yaml index dcc05b0d1..bf77b72f0 100644 --- a/conda_lock/default-virtual-packages.yaml +++ b/conda_lock/default-virtual-packages.yaml @@ -4,7 +4,6 @@ subdirs: __unix: "0" __linux: "5.10" __archspec: "1 x86_64" - # NOTE: Keep this in sync with the MANYLINUX_TAGS maximum in pypi_solver.py __glibc: "2.28" __cuda: "11.4" linux-aarch64: @@ -12,7 +11,6 @@ subdirs: __unix: "0" __linux: "5.10" __archspec: "1 aarch64" - # NOTE: Keep this in sync with the MANYLINUX_TAGS maximum in pypi_solver.py __glibc: "2.28" __cuda: "11.4" linux-ppc64le: @@ -20,7 +18,6 @@ subdirs: __unix: "0" __linux: "5.10" __archspec: "1 ppc64le" - # NOTE: Keep this in sync with the MANYLINUX_TAGS maximum in pypi_solver.py __glibc: "2.28" __cuda: "11.4" osx-64: diff --git a/conda_lock/pypi_solver.py b/conda_lock/pypi_solver.py index 846b2d28c..be58ba4a6 100644 --- a/conda_lock/pypi_solver.py +++ b/conda_lock/pypi_solver.py @@ -58,8 +58,6 @@ # NB: in principle these depend on the glibc on the machine creating the conda env. # We use tags supported by manylinux Docker images, which are likely the most common # in practice, see https://github.com/pypa/manylinux/blob/main/README.rst#docker-images. -# NOTE: -# Keep the max in sync with the default value used in default-virtual-packages.yaml. MANYLINUX_TAGS = ["1", "2010", "2014", "_2_17", "_2_18", "_2_24", "_2_28"] # This needs to be updated periodically as new macOS versions are released. diff --git a/tests/test_conda_lock.py b/tests/test_conda_lock.py index d4f053c8e..cbf99e49e 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -3258,15 +3258,17 @@ def test_manylinux_tags(): assert versions[0] == Version("2.17") assert versions == sorted(versions) - # Verify that the default repodata uses the highest glibc version + # Verify that the default glibc versions are covered by MANYLINUX_TAGS. + # (The default may be lower than the max tag; higher tags are available + # via --virtual-package-spec.) default_repodata = default_virtual_package_repodata() glibc_versions_in_default_repodata: set[Version] = { Version(package.version) for package in default_repodata.packages_by_subdir if package.name == "__glibc" } - max_glibc_version_from_manylinux_tags = versions[-1] - assert glibc_versions_in_default_repodata == {max_glibc_version_from_manylinux_tags} + manylinux_glibc_versions = set(versions) + assert glibc_versions_in_default_repodata <= manylinux_glibc_versions def test_pip_respects_glibc_version( From 254242926a024aef56cc5c74cd72b486fcd65b19 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 7 Apr 2026 22:07:23 +0200 Subject: [PATCH 2/4] Document virtual package version tradeoff Explain in default-virtual-packages.yaml and README.md that each virtual package version acts as an upper bound on candidate packages and a lower bound on compatible target systems. Made-with: Cursor --- README.md | 9 +++++++++ conda_lock/default-virtual-packages.yaml | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/README.md b/README.md index cb8f30a02..96828d11d 100644 --- a/README.md +++ b/README.md @@ -248,6 +248,15 @@ Conda makes use of [virtual packages](https://conda.io/projects/conda/en/latest/ runtime to gate dependency on system features. Due to these not generally existing on your local execution platform conda-lock will inject them into the solution environment with a reasonable guess at what a default system configuration should be. +Each virtual package version represents an assumed minimum system capability. The solver +excludes any package that requires a newer version, so these act as upper bounds on which +packages are considered. Conversely, they act as lower bounds on the systems where the +resulting lockfile can be installed. + +There is a tradeoff: increasing a version widens the set of candidate packages but narrows +the set of compatible target systems. If a package you need is being filtered out, increase the +relevant version. If the lockfile is incompatible with your target system, decrease it. + If you want to override which virtual packages are injected you can create a file like ```yaml diff --git a/conda_lock/default-virtual-packages.yaml b/conda_lock/default-virtual-packages.yaml index bf77b72f0..b31add736 100644 --- a/conda_lock/default-virtual-packages.yaml +++ b/conda_lock/default-virtual-packages.yaml @@ -1,3 +1,19 @@ +# Default virtual packages used when no --virtual-package-spec is provided. +# +# Each version represents the assumed minimum system capability. The solver +# filters out any package that requires a newer version, so these act as upper +# bounds on which packages are considered. Conversely, they act as lower bounds +# on the systems where the resulting lockfile can be installed. +# +# For example, with __glibc: "2.28", packages requiring glibc > 2.28 are +# excluded from the lockfile, and the lockfile is installable on any system +# with glibc >= 2.28. +# +# Tradeoff: increasing a version widens the set of candidate packages but +# narrows the set of compatible target systems. If a package you need is being +# filtered out, increase the version. If the lockfile is incompatible with your +# target system, decrease the version. To override these defaults, create a +# virtual-packages.yml file (see README.md). subdirs: linux-64: packages: From 5ff5edfd13518a915d29adfe52c9295eb74bdc4c Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 7 Apr 2026 22:11:25 +0200 Subject: [PATCH 3/4] Rewrite virtual package docs in plain language Replace the technical jargon about "injecting" and "gating on system features" with a clearer explanation of what virtual packages are, what the version numbers mean, and how to adjust them. Made-with: Cursor --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 96828d11d..b26c90dc3 100644 --- a/README.md +++ b/README.md @@ -244,20 +244,21 @@ conda-lock install --auth-file auth.json conda-linux-64.lock ### --virtual-package-spec -Conda makes use of [virtual packages](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-virtual.html) that are available at -runtime to gate dependency on system features. Due to these not generally existing on your local execution platform conda-lock will inject -them into the solution environment with a reasonable guess at what a default system configuration should be. +Conda uses [virtual packages](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-virtual.html) to describe system-level +features like the glibc version, macOS version, or CUDA version. Since conda-lock generates +lockfiles independently of a target system, it assumes a default set of virtual package versions +that represent a reasonable minimum system configuration. -Each virtual package version represents an assumed minimum system capability. The solver -excludes any package that requires a newer version, so these act as upper bounds on which -packages are considered. Conversely, they act as lower bounds on the systems where the -resulting lockfile can be installed. +Each virtual package version acts as an upper bound on which packages are considered by +the solver (packages requiring a newer version are excluded) and as a lower bound on +compatible target systems (the lockfile is installable on systems that meet or exceed +these versions). There is a tradeoff: increasing a version widens the set of candidate packages but narrows the set of compatible target systems. If a package you need is being filtered out, increase the relevant version. If the lockfile is incompatible with your target system, decrease it. -If you want to override which virtual packages are injected you can create a file like +To override the defaults, create a `virtual-packages.yml` file like ```yaml # virtual-packages.yml From 3afd8e516a394568f646d9c6001936cfbb9ea695 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 7 Apr 2026 22:18:47 +0200 Subject: [PATCH 4/4] Update virtual package docs in docs/flags.md Apply the same documentation improvements to the docs site version of the --virtual-package-spec section. Made-with: Cursor --- docs/flags.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/flags.md b/docs/flags.md index 0fd816bc3..e0d17807b 100644 --- a/docs/flags.md +++ b/docs/flags.md @@ -135,11 +135,21 @@ When the input_hash of the input files, channels match those present in a given ## --virtual-package-spec -Conda makes use of [virtual packages](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-virtual.html) that are available at -runtime to gate dependency on system features. Due to these not generally existing on your local execution platform conda-lock will inject -them into the solution environment with a reasonable guess at what a default system configuration should be. +Conda uses [virtual packages](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-virtual.html) to describe system-level +features like the glibc version, macOS version, or CUDA version. Since conda-lock generates +lockfiles independently of a target system, it assumes a default set of virtual package versions +that represent a reasonable minimum system configuration. -If you want to override which virtual packages are injected you can create a virtual package spec file +Each virtual package version acts as an upper bound on which packages are considered by +the solver (packages requiring a newer version are excluded) and as a lower bound on +compatible target systems (the lockfile is installable on systems that meet or exceed +these versions). + +There is a tradeoff: increasing a version widens the set of candidate packages but narrows +the set of compatible target systems. If a package you need is being filtered out, increase the +relevant version. If the lockfile is incompatible with your target system, decrease it. + +To override the defaults, create a virtual package spec file ```{.yaml title="virtual-packages.yml"} subdirs: