diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 3d110b05cbc..4f32d3a9c5c 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -1472,9 +1472,9 @@ impl ResolverState Result, ResolveError> { // This only applies to universal resolutions. - if env.marker_environment().is_some() { + let Some(fork_markers) = env.fork_markers() else { return Ok(None); - } + }; // If the package is already compatible with all environments (as is the case for // packages that include a source distribution), we don't need to fork. @@ -1491,8 +1491,13 @@ impl ResolverState= 25. This avoids introducing forks for unrelated wheel tags. + let coverage = dist.implied_markers().and(fork_markers); + let split = marker.restrict(marker.or(coverage)); + let Some((left, right)) = fork_version_by_marker(env, split) else { return Ok(Some(ResolverVersion::Unavailable( candidate.version().clone(), UnavailableVersion::IncompatibleDist(IncompatibleDist::Wheel( diff --git a/crates/uv/tests/lock/lock.rs b/crates/uv/tests/lock/lock.rs index 06246df9179..9894ce4c7eb 100644 --- a/crates/uv/tests/lock/lock.rs +++ b/crates/uv/tests/lock/lock.rs @@ -38121,9 +38121,9 @@ fn lock_intel_mac() -> Result<()> { revision = 3 requires-python = ">=3.11" resolution-markers = [ - "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'darwin')", - "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform != 'darwin')", - "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform == 'win32')", + "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform == 'win32')", + "platform_machine == 'x86_64' and sys_platform != 'linux' and sys_platform != 'win32'", ] required-markers = [ "platform_machine == 'x86_64' and sys_platform == 'darwin'", @@ -38343,8 +38343,8 @@ fn lock_intel_mac() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" }, - { name = "torch", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform != 'darwin'" }, + { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and sys_platform != 'linux' and sys_platform != 'win32'" }, + { name = "torch", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine != 'x86_64' or sys_platform == 'linux' or sys_platform == 'win32'" }, ] [package.metadata] @@ -38376,7 +38376,7 @@ fn lock_intel_mac() -> Result<()> { version = "2.2.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'x86_64' and sys_platform != 'linux' and sys_platform != 'win32'", ] dependencies = [ { name = "filelock" }, @@ -38396,8 +38396,8 @@ fn lock_intel_mac() -> Result<()> { version = "2.5.1" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform != 'darwin')", - "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform != 'darwin')", + "(python_full_version >= '3.12' and platform_machine != 'x86_64') or (python_full_version >= '3.12' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform == 'win32')", + "(python_full_version < '3.12' and platform_machine != 'x86_64') or (python_full_version < '3.12' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform == 'win32')", ] dependencies = [ { name = "filelock" }, @@ -42457,8 +42457,8 @@ fn lock_required_environment_python_fork() -> Result<()> { revision = 3 requires-python = ">=3.12, <3.14" resolution-markers = [ - "(python_full_version >= '3.13' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and sys_platform != 'linux')", - "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "python_full_version >= '3.13' and sys_platform == 'win32'", + "python_full_version >= '3.13' and sys_platform != 'win32'", "python_full_version < '3.13'", ] supported-markers = [ @@ -42477,7 +42477,7 @@ fn lock_required_environment_python_fork() -> Result<()> { version = "1.0.0" source = { registry = "http://[LOCALHOST]/simple/" } resolution-markers = [ - "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'", + "python_full_version >= '3.13' and sys_platform != 'win32'", ] wheels = [ { url = "http://[LOCALHOST]/files/a-1.0.0-cp312-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:[SHA256:a-1.0.0-cp312-abi3-manylinux_2_17_x86_64.whl]", upload-time = "2024-03-24T00:00:00Z" }, @@ -42488,7 +42488,7 @@ fn lock_required_environment_python_fork() -> Result<()> { version = "2.0.0" source = { registry = "http://[LOCALHOST]/simple/" } resolution-markers = [ - "(python_full_version >= '3.13' and platform_machine != 'x86_64') or (python_full_version >= '3.13' and sys_platform != 'linux')", + "python_full_version >= '3.13' and sys_platform == 'win32'", "python_full_version < '3.13'", ] wheels = [ @@ -42501,8 +42501,8 @@ fn lock_required_environment_python_fork() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "a", version = "1.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "a", version = "2.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version < '3.13' or platform_machine != 'x86_64' or sys_platform != 'linux'" }, + { name = "a", version = "1.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version >= '3.13' and sys_platform != 'win32'" }, + { name = "a", version = "2.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version < '3.13' or sys_platform == 'win32'" }, ] [package.metadata] @@ -42514,6 +42514,7 @@ fn lock_required_environment_python_fork() -> Result<()> { } /// A required Darwin release must have a compatible wheel, without removing newer wheels. +/// The newer version must not be selected between the baseline and its minimum Darwin release. #[cfg(feature = "test-universal")] #[test] fn lock_required_environment_macos_release() -> Result<()> { @@ -42567,8 +42568,8 @@ fn lock_required_environment_macos_release() -> Result<()> { revision = 3 requires-python = ">=3.12" resolution-markers = [ - "(platform_machine == 'arm64' and platform_release < '24' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release > '24' and sys_platform == 'darwin')", - "platform_machine == 'arm64' and platform_release == '24' and sys_platform == 'darwin'", + "platform_machine == 'arm64' and platform_release >= '25' and sys_platform == 'darwin'", + "platform_machine == 'arm64' and platform_release < '25' and sys_platform == 'darwin'", ] supported-markers = [ "platform_machine == 'arm64' and sys_platform == 'darwin'", @@ -42585,7 +42586,7 @@ fn lock_required_environment_macos_release() -> Result<()> { version = "1.0.0" source = { registry = "http://[LOCALHOST]/simple/" } resolution-markers = [ - "platform_machine == 'arm64' and platform_release == '24' and sys_platform == 'darwin'", + "platform_machine == 'arm64' and platform_release < '25' and sys_platform == 'darwin'", ] wheels = [ { url = "http://[LOCALHOST]/files/a-1.0.0-py3-none-macosx_14_0_arm64.whl", hash = "sha256:[SHA256:a-1.0.0-py3-none-macosx_14_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, @@ -42597,7 +42598,7 @@ fn lock_required_environment_macos_release() -> Result<()> { version = "2.0.0" source = { registry = "http://[LOCALHOST]/simple/" } resolution-markers = [ - "(platform_machine == 'arm64' and platform_release < '24' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_release > '24' and sys_platform == 'darwin')", + "platform_machine == 'arm64' and platform_release >= '25' and sys_platform == 'darwin'", ] wheels = [ { url = "http://[LOCALHOST]/files/a-2.0.0-py3-none-macosx_26_0_arm64.whl", hash = "sha256:[SHA256:a-2.0.0-py3-none-macosx_26_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, @@ -42608,8 +42609,8 @@ fn lock_required_environment_macos_release() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "a", version = "1.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "platform_release == '24'" }, - { name = "a", version = "2.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "platform_release < '24' or platform_release > '24'" }, + { name = "a", version = "1.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "platform_release < '25'" }, + { name = "a", version = "2.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "platform_release >= '25'" }, ] [package.metadata] @@ -42645,13 +42646,132 @@ fn lock_required_environment_macos_release() -> Result<()> { uv_snapshot!(filters, context.lock().arg("--index-url").arg(server.index_url()), @" exit_code: 1 (failure) ----- stderr ----- - error: No solution found when resolving dependencies for split (markers: python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release == '24' and sys_platform == 'darwin') + error: No solution found when resolving dependencies for split (markers: python_full_version >= '3.12' and platform_machine == 'arm64' and platform_release < '25' and sys_platform == 'darwin') cause: Because only a==2.0.0 is available and a==2.0.0 has no `platform_machine == 'arm64' and sys_platform == 'darwin'`-compatible wheels, we can conclude that all versions of a cannot be used. And because your project depends on a, we can conclude that your project's requirements are unsatisfiable. "); Ok(()) } +/// Wheels for another Python version must not determine the Darwin release split in this fork. +#[cfg(feature = "test-universal")] +#[test] +fn lock_required_environment_macos_release_python_fork() -> Result<()> { + let scenario = toml::from_str::(indoc! {r#" + name = "required-environment-macos-release-python-fork" + + [root] + + [expected] + satisfiable = true + + [packages.a.versions."1.0.0"] + sdist = false + wheel_tags = ["cp312-cp312-macosx_14_0_arm64", "cp313-cp313-macosx_14_0_arm64"] + + [packages.a.versions."2.0.0"] + sdist = false + wheel_tags = ["cp312-cp312-macosx_14_0_arm64", "cp313-cp313-macosx_26_0_arm64"] + "#})?; + let server = PackseServer::from_scenario(&scenario); + let context = uv_test::test_context!("3.12").with_filters( + server + .files() + .map(|(filename, hash)| (hash.to_owned(), format!("[SHA256:{filename}]"))), + ); + context + .temp_dir + .child("pyproject.toml") + .write_str(indoc! {r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12,<3.14" + dependencies = ["a"] + + [tool.uv] + environments = [ + "sys_platform == 'darwin' and platform_machine == 'arm64' and python_version < '3.13'", + "sys_platform == 'darwin' and platform_machine == 'arm64' and python_version >= '3.13'", + ] + required-environments = ["sys_platform == 'darwin' and platform_machine == 'arm64' and platform_release == '24.0.0'"] + "#})?; + + uv_snapshot!(context.filters(), context.lock().arg("--index-url").arg(server.index_url()), @" + exit_code: 0 (success) + ----- stderr ----- + Resolved 3 packages in [TIME] + "); + + insta::with_settings!({ filters => context.filters() }, { + assert_snapshot!(context.read("uv.lock"), @r#" + version = 1 + revision = 3 + requires-python = ">=3.12, <3.14" + resolution-markers = [ + "python_full_version >= '3.13' and platform_machine == 'arm64' and platform_release >= '25' and sys_platform == 'darwin'", + "python_full_version >= '3.13' and platform_machine == 'arm64' and platform_release < '25' and sys_platform == 'darwin'", + "python_full_version < '3.13' and platform_machine == 'arm64' and sys_platform == 'darwin'", + ] + supported-markers = [ + "python_full_version < '3.13' and platform_machine == 'arm64' and sys_platform == 'darwin'", + "python_full_version >= '3.13' and platform_machine == 'arm64' and sys_platform == 'darwin'", + ] + required-markers = [ + "platform_machine == 'arm64' and platform_release == '24' and sys_platform == 'darwin'", + ] + + [options] + exclude-newer = "2024-03-25T00:00:00Z" + + [[package]] + name = "a" + version = "1.0.0" + source = { registry = "http://[LOCALHOST]/simple/" } + resolution-markers = [ + "python_full_version >= '3.13' and platform_machine == 'arm64' and platform_release < '25' and sys_platform == 'darwin'", + ] + wheels = [ + { url = "http://[LOCALHOST]/files/a-1.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:[SHA256:a-1.0.0-cp312-cp312-macosx_14_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, + { url = "http://[LOCALHOST]/files/a-1.0.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:[SHA256:a-1.0.0-cp313-cp313-macosx_14_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, + ] + + [[package]] + name = "a" + version = "2.0.0" + source = { registry = "http://[LOCALHOST]/simple/" } + resolution-markers = [ + "python_full_version >= '3.13' and platform_machine == 'arm64' and platform_release >= '25' and sys_platform == 'darwin'", + "python_full_version < '3.13' and platform_machine == 'arm64' and sys_platform == 'darwin'", + ] + wheels = [ + { url = "http://[LOCALHOST]/files/a-2.0.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:[SHA256:a-2.0.0-cp312-cp312-macosx_14_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, + { url = "http://[LOCALHOST]/files/a-2.0.0-cp313-cp313-macosx_26_0_arm64.whl", hash = "sha256:[SHA256:a-2.0.0-cp313-cp313-macosx_26_0_arm64.whl]", upload-time = "2024-03-24T00:00:00Z" }, + ] + + [[package]] + name = "project" + version = "0.1.0" + source = { virtual = "." } + dependencies = [ + { name = "a", version = "1.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version >= '3.13' and platform_release < '25'" }, + { name = "a", version = "2.0.0", source = { registry = "http://[LOCALHOST]/simple/" }, marker = "python_full_version < '3.13' or platform_release >= '25'" }, + ] + + [package.metadata] + requires-dist = [{ name = "a" }] + "#); + }); + + uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--index-url").arg(server.index_url()), @" + exit_code: 0 (success) + ----- stderr ----- + Resolved 3 packages in [TIME] + "); + + Ok(()) +} + /// A direct wheel must support the required platform within the current architecture fork. #[cfg(feature = "test-universal")] #[test] @@ -42783,7 +42903,7 @@ fn lock_required_environment_cycle_reports_resolution_error() -> Result<()> { @" exit_code: 1 (failure) ----- stderr ----- - error: No solution found when resolving dependencies for split (markers: platform_machine == 'arm64') + error: No solution found when resolving dependencies for split (markers: platform_machine != 'ppc64') cause: Because a==1.0.0 has no `platform_machine == 'arm64'`-compatible wheels and only a==1.0.0 is available, we can conclude that all versions of a cannot be used. And because pkg-a depends on a and your workspace requires pkg-a, we can conclude that your workspace's requirements are unsatisfiable. " diff --git a/crates/uv/tests/pip_compile/pip_compile.rs b/crates/uv/tests/pip_compile/pip_compile.rs index cdf1a468696..60fec90f796 100644 --- a/crates/uv/tests/pip_compile/pip_compile.rs +++ b/crates/uv/tests/pip_compile/pip_compile.rs @@ -15492,7 +15492,7 @@ fn universal_required_environment() -> Result<()> { .env_remove(EnvVars::UV_EXCLUDE_NEWER), @" exit_code: 1 (failure) ----- stderr ----- - error: No solution found when resolving dependencies for split (markers: platform_machine == 'arm64') + error: No solution found when resolving dependencies for split (markers: platform_machine != 'ppc64') cause: Because a==1.0.0 has no `platform_machine == 'arm64'`-compatible wheels and only a==1.0.0 is available, we can conclude that all versions of a cannot be used. And because project depends on a, we can conclude that your requirements are unsatisfiable. ");