Skip to content

Overlapping variant markers are incompatible with universal resolution #64

Description

@konstin

Poetry, pdm (https://pdm-project.org/latest/usage/lock-targets/) and uv (https://docs.astral.sh/uv/reference/resolver-internals/) perform a universal resolution that works on all platforms. This is in contrast to pip, which only resolves for the current platform.

pip evaluates the markers on the requirements and ignores all that don't match the current platform. Universal resolution requires that for each (supported) possible set of markers, we can determine the subset of packages from the lockfile to install. Python packages or dependency trees can has incompatible requirements, as long they are for different markers. There's a more detailed explanation in https://docs.astral.sh/uv/reference/resolver-internals/, the short version is that we have to split the resolution into two if there are conflicting markers.

[project]
name = "myproject"
requires-python = ">=3.9"
dependencies = [
    "numpy<1.25; python_version < '3.10'",
    "numpy>=1.25; python_version >= '3.10'",
    "pandas"
]
[project]
name = "myproject"
requires-python = ">=3.9"
dependencies = [
    "numpy<1.25; sys_platform == 'linux'",
    "numpy>=1.25; sys_platform == 'darwin'",
    "pandas"
]

In the first case above, we do one resolution for python_version < '3.10' and one for python_version >= '3.10', resolving different numpy versions. In the second case, we perform one resolution for linux, one for darwin and one for not(linux or darwin). (You can run both of these examples with uv. The real forks are more complex, but the lockfile still shows the different version and their disjoint platform markers). In each of these so-called forks, there is only one version of a package. Forks don't overlap and all forks together are a universal resolution. We ensure those two properties so that at install time, we only need to determine the current environment and get a consistent set of packages to install.

Now consider the following requirements specification:

Requires-Dist: nvidia-cublas==12.6.4.1; platform_system == "Linux" and platform_machine == "x86_64" and "nvidia :: ctk :: 12.6" in variant_properties
Requires-Dist: nvidia-cublas==12.8.4.1; platform_system == "Linux" and platform_machine == "x86_64" and "nvidia :: ctk :: 12.8" in variant_properties
Requires-Dist: nvidia-cublas==12.9.1.4; platform_system == "Linux" and platform_machine == "x86_64" and "nvidia :: ctk :: 12.9" in variant_properties

If we try to perform a universal resolution, we run into a conflict between nvidia-cublas==12.6.4.1 and nvidia-cublas==12.8.4.1, since "nvidia :: ctk :: 12.6" in variant_properties and "nvidia :: ctk :: 12.8" in variant_properties is a reasonable environment in the eyes of a resolver. With our knowledge about the nvidia provider, we know that those markers are disjoint and there is no conflict.

There are different general strategies we could apply: One is that a resolver needs to allow overlapping forks and ensure at install time, that there is no overlap. The other is that a provider needs to communicate that markers are disjoint, e.g. it could state in variants.json that nvidia :: ctk always only has a single value. The third would be that neither of them changes and we push the problem down to users, so that users have to avoid conflicting versions or write something like:

Requires-Dist: nvidia-cublas==12.6.4.1; "nvidia :: ctk :: 12.6"     in variant_properties and "nvidia :: ctk :: 12.8" not in variant_properties and "nvidia :: ctk :: 12.9" not in variant_properties
Requires-Dist: nvidia-cublas==12.8.4.1; "nvidia :: ctk :: 12.6" not in variant_properties and "nvidia :: ctk :: 12.8"     in variant_properties and "nvidia :: ctk :: 12.9" not in variant_properties
Requires-Dist: nvidia-cublas==12.9.1.4; "nvidia :: ctk :: 12.6" not in variant_properties and "nvidia :: ctk :: 12.8" not in variant_properties and "nvidia :: ctk :: 12.9"     in variant_properties

A fourth, rather narrow optiona is to add more syntax:

Requires-Dist: nvidia-cublas==12.6.4.1; ["nvidia :: ctk :: 12.6"] == variant_properties
Requires-Dist: nvidia-cublas==12.8.4.1; ["nvidia :: ctk :: 12.8"] == variant_properties
Requires-Dist: nvidia-cublas==12.9.1.4; ["nvidia :: ctk :: 12.9"] == variant_properties

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions