diff --git a/.python-versions b/.python-versions index 1f8f24173..957687cb4 100644 --- a/.python-versions +++ b/.python-versions @@ -5,7 +5,8 @@ 3.9.21 3.8.20 # The following are required for packse scenarios -3.8.18 -3.8.12 +3.9.20 +3.9.18 +3.9.12 # The following is needed for `==3.13` request tests 3.13.0 diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 48e36468a..8c65c7e86 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -32,7 +32,7 @@ use uv_static::EnvVars; // Exclude any packages uploaded after this date. static EXCLUDE_NEWER: &str = "2024-03-25T00:00:00Z"; -pub const PACKSE_VERSION: &str = "0.3.46"; +pub const PACKSE_VERSION: &str = "0.3.47"; pub const DEFAULT_PYTHON_VERSION: &str = "3.12"; /// Using a find links url allows using `--index-url` instead of `--extra-index-url` in tests diff --git a/crates/uv/tests/it/lock_scenarios.rs b/crates/uv/tests/it/lock_scenarios.rs index 0b7af71a2..bc49fa728 100644 --- a/crates/uv/tests/it/lock_scenarios.rs +++ b/crates/uv/tests/it/lock_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi"))] #![allow(clippy::needless_raw_string_hashes)] @@ -24,7 +24,7 @@ use crate::common::{TestContext, packse_index_url, uv_snapshot}; /// ```text /// wrong-backtracking-basic /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-1.0.0 @@ -43,47 +43,61 @@ use crate::common::{TestContext, packse_index_url, uv_snapshot}; /// │ └── satisfied by b-2.0.9 /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ └── requires too-old /// │ │ └── satisfied by too-old-1.0.0 /// │ ├── b-2.0.0 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.1 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.2 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.3 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.4 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.5 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.6 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.7 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.8 -/// │ │ └── requires a==1.0.0 -/// │ │ └── satisfied by a-1.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-2.0.9 -/// │ └── requires a==1.0.0 -/// │ └── satisfied by a-1.0.0 +/// │ ├── requires a==1.0.0 +/// │ │ └── satisfied by a-1.0.0 +/// │ └── requires python>=3.8 /// └── too-old /// └── too-old-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn wrong_backtracking_basic() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -106,14 +120,14 @@ fn wrong_backtracking_basic() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 3 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -178,6 +192,209 @@ fn wrong_backtracking_basic() -> Result<()> { Ok(()) } +/// There are three packages, `a`, `b` and `b-inner`. Unlike wrong-backtracking-basic, `b` depends on `b-inner` and `a` and `b-inner` conflict, to add a layer of indirection. +/// +/// We select `a` with `a==2.0.0` first, then `b`, and then `b-inner`, but `a==2.0.0` conflicts with all new versions of `b-inner`, so we backtrack through versions of `b-inner`. +/// +/// We need to detect this conflict and prioritize `b` and `b-inner` over `a` instead of backtracking down to the too old version of `b-inner==1.0.0` that doesn't depend on `a` anymore. +/// +/// ```text +/// wrong-backtracking-indirect +/// ├── environment +/// │ └── python3.12 +/// ├── root +/// │ ├── requires a +/// │ │ ├── satisfied by a-1.0.0 +/// │ │ └── satisfied by a-2.0.0 +/// │ └── requires b +/// │ └── satisfied by b-1.0.0 +/// ├── a +/// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ └── a-2.0.0 +/// │ └── requires python>=3.8 +/// ├── b +/// │ └── b-1.0.0 +/// │ ├── requires b-inner +/// │ │ ├── satisfied by b-inner-1.0.0 +/// │ │ ├── satisfied by b-inner-2.0.0 +/// │ │ ├── satisfied by b-inner-2.0.1 +/// │ │ ├── satisfied by b-inner-2.0.2 +/// │ │ ├── satisfied by b-inner-2.0.3 +/// │ │ ├── satisfied by b-inner-2.0.4 +/// │ │ ├── satisfied by b-inner-2.0.5 +/// │ │ ├── satisfied by b-inner-2.0.6 +/// │ │ ├── satisfied by b-inner-2.0.7 +/// │ │ ├── satisfied by b-inner-2.0.8 +/// │ │ └── satisfied by b-inner-2.0.9 +/// │ └── requires python>=3.8 +/// ├── b-inner +/// │ ├── b-inner-1.0.0 +/// │ │ ├── requires python>=3.8 +/// │ │ └── requires too-old +/// │ │ └── satisfied by too-old-1.0.0 +/// │ ├── b-inner-2.0.0 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.1 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.2 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.3 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.4 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.5 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.6 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.7 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ ├── b-inner-2.0.8 +/// │ │ ├── requires a==1.0.0 +/// │ │ │ └── satisfied by a-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ └── b-inner-2.0.9 +/// │ ├── requires a==1.0.0 +/// │ │ └── satisfied by a-1.0.0 +/// │ └── requires python>=3.8 +/// └── too-old +/// └── too-old-1.0.0 +/// └── requires python>=3.8 +/// ``` +#[test] +fn wrong_backtracking_indirect() -> Result<()> { + let context = TestContext::new("3.12"); + + // In addition to the standard filters, swap out package names for shorter messages + let mut filters = context.filters(); + filters.push((r"wrong-backtracking-indirect-", "package-")); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r###" + [project] + name = "project" + version = "0.1.0" + dependencies = [ + '''wrong-backtracking-indirect-a''', + '''wrong-backtracking-indirect-b''', + ] + requires-python = ">=3.8" + "###, + )?; + + let mut cmd = context.lock(); + cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); + cmd.arg("--index-url").arg(packse_index_url()); + uv_snapshot!(filters, cmd, @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 5 packages in [TIME] + " + ); + + let lock = context.read("uv.lock"); + insta::with_settings!({ + filters => filters, + }, { + assert_snapshot!( + lock, @r#" + version = 1 + revision = 2 + requires-python = ">=3.8" + + [[package]] + name = "project" + version = "0.1.0" + source = { virtual = "." } + dependencies = [ + { name = "package-a" }, + { name = "package-b" }, + ] + + [package.metadata] + requires-dist = [ + { name = "package-a" }, + { name = "package-b" }, + ] + + [[package]] + name = "package-a" + version = "2.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_a-2.0.0.tar.gz", hash = "sha256:5891b5a45aac67b3afb90f66913d7ced2ada7cad1676fe427136b7324935bb1e" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_a-2.0.0-py3-none-any.whl", hash = "sha256:68cb37193f4b2277630ad083522f59ac0449cb1c59e943884d04cc0e2a04cba7" }, + ] + + [[package]] + name = "package-b" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + dependencies = [ + { name = "package-b-inner" }, + ] + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b-1.0.0.tar.gz", hash = "sha256:fe434964c4f01b38e86a771d4ba42daed307dc60da472943c3f3e250c0895285" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b-1.0.0-py3-none-any.whl", hash = "sha256:f35c50d6d2069807a5c25d15aa50842d5a9e27638f2fbb607e8d5ed73d2f6191" }, + ] + + [[package]] + name = "package-b-inner" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + dependencies = [ + { name = "package-too-old" }, + ] + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b_inner-1.0.0.tar.gz", hash = "sha256:e47f8b35b48d332d7d1be36b311a3f6ad59033c6e289c26bfd1dcf17c24e06b7" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b_inner-1.0.0-py3-none-any.whl", hash = "sha256:05152955d9c83408098fd49a01cdb46fec21c8b16b65303971ce0dca7b029925" }, + ] + + [[package]] + name = "package-too-old" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_too_old-1.0.0.tar.gz", hash = "sha256:1b674a931c34e29d20f22e9b92206b648769fa9e35770ab680466dbaa1335090" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_too_old-1.0.0-py3-none-any.whl", hash = "sha256:15f8fe39323691c883c3088f8873220944428210a74db080f60a61a74c1fc6b0" }, + ] + "# + ); + }); + + // Assert the idempotence of `uv lock` when resolving from the lockfile (`--locked`). + context + .lock() + .arg("--locked") + .env_remove(EnvVars::UV_EXCLUDE_NEWER) + .arg("--index-url") + .arg(packse_index_url()) + .assert() + .success(); + + Ok(()) +} + /// This test ensures that multiple non-conflicting but also /// non-overlapping dependency specifications with the same package name /// are allowed and supported. @@ -191,7 +408,7 @@ fn wrong_backtracking_basic() -> Result<()> { /// ```text /// fork-allows-non-conflicting-non-overlapping-dependencies /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=1; sys_platform == "linux" /// │ │ ├── satisfied by a-1.0.0 @@ -200,11 +417,13 @@ fn wrong_backtracking_basic() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// └── a-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -230,14 +449,14 @@ fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -309,7 +528,7 @@ fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { /// ```text /// fork-allows-non-conflicting-repeated-dependencies /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=1 /// │ │ ├── satisfied by a-1.0.0 @@ -318,11 +537,13 @@ fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// └── a-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -348,14 +569,14 @@ fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -413,7 +634,7 @@ fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { /// ```text /// fork-basic /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -421,11 +642,13 @@ fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// └── a-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_basic() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -448,14 +671,14 @@ fn fork_basic() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 3 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -533,34 +756,40 @@ fn fork_basic() -> Result<()> { /// ```text /// conflict-in-fork /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root -/// │ ├── requires a>=2; sys_platform == "linux" +/// │ ├── requires a>=2; sys_platform == "os1" /// │ │ └── satisfied by a-2.0.0 -/// │ └── requires a<2; sys_platform == "darwin" +/// │ └── requires a<2; sys_platform == "os2" /// │ └── satisfied by a-1.0.0 /// ├── a /// │ ├── a-1.0.0 /// │ │ ├── requires b /// │ │ │ └── satisfied by b-1.0.0 -/// │ │ └── requires c -/// │ │ └── satisfied by c-1.0.0 +/// │ │ ├── requires c +/// │ │ │ └── satisfied by c-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires d==1 -/// │ └── satisfied by d-1.0.0 +/// │ ├── requires d==1 +/// │ │ └── satisfied by d-1.0.0 +/// │ └── requires python>=3.8 /// ├── c /// │ └── c-1.0.0 -/// │ └── requires d==2 -/// │ └── satisfied by d-2.0.0 +/// │ ├── requires d==2 +/// │ │ └── satisfied by d-2.0.0 +/// │ └── requires python>=3.8 /// └── d /// ├── d-1.0.0 +/// │ └── requires python>=3.8 /// └── d-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn conflict_in_fork() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -573,8 +802,8 @@ fn conflict_in_fork() -> Result<()> { name = "project" version = "0.1.0" dependencies = [ - '''conflict-in-fork-a>=2; sys_platform == "linux"''', - '''conflict-in-fork-a<2; sys_platform == "darwin"''', + '''conflict-in-fork-a>=2; sys_platform == "os1"''', + '''conflict-in-fork-a<2; sys_platform == "os2"''', ] requires-python = ">=3.8" "###, @@ -583,21 +812,21 @@ fn conflict_in_fork() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- - × No solution found when resolving dependencies for split (sys_platform == 'darwin'): + × No solution found when resolving dependencies for split (sys_platform == 'os2'): ╰─▶ Because only package-b==1.0.0 is available and package-b==1.0.0 depends on package-d==1, we can conclude that all versions of package-b depend on package-d==1. And because package-c==1.0.0 depends on package-d==2 and only package-c==1.0.0 is available, we can conclude that all versions of package-b and all versions of package-c are incompatible. And because package-a==1.0.0 depends on package-b and package-c, we can conclude that package-a==1.0.0 cannot be used. - And because only the following versions of package-a{sys_platform == 'darwin'} are available: - package-a{sys_platform == 'darwin'}==1.0.0 - package-a{sys_platform == 'darwin'}>2 - and your project depends on package-a{sys_platform == 'darwin'}<2, we can conclude that your project's requirements are unsatisfiable. - "### + And because only the following versions of package-a{sys_platform == 'os2'} are available: + package-a{sys_platform == 'os2'}==1.0.0 + package-a{sys_platform == 'os2'}>2 + and your project depends on package-a{sys_platform == 'os2'}<2, we can conclude that your project's requirements are unsatisfiable. + " ); Ok(()) @@ -614,7 +843,7 @@ fn conflict_in_fork() -> Result<()> { /// ```text /// fork-conflict-unsatisfiable /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2 /// │ │ ├── satisfied by a-2.0.0 @@ -623,12 +852,15 @@ fn conflict_in_fork() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// ├── a-2.0.0 +/// │ └── requires python>=3.8 /// └── a-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_conflict_unsatisfiable() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -651,7 +883,7 @@ fn fork_conflict_unsatisfiable() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: false exit_code: 1 ----- stdout ----- @@ -659,7 +891,7 @@ fn fork_conflict_unsatisfiable() -> Result<()> { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because your project depends on package-a>=2 and package-a<2, we can conclude that your project's requirements are unsatisfiable. - "### + " ); Ok(()) @@ -682,7 +914,7 @@ fn fork_conflict_unsatisfiable() -> Result<()> { /// ```text /// fork-filter-sibling-dependencies /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==4.4.0; sys_platform == "linux" /// │ │ └── satisfied by a-4.4.0 @@ -694,22 +926,28 @@ fn fork_conflict_unsatisfiable() -> Result<()> { /// │ └── satisfied by c-1.0.0 /// ├── a /// │ ├── a-4.3.0 +/// │ │ └── requires python>=3.8 /// │ └── a-4.4.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires d==1.0.0 -/// │ └── satisfied by d-1.0.0 +/// │ ├── requires d==1.0.0 +/// │ │ └── satisfied by d-1.0.0 +/// │ └── requires python>=3.8 /// ├── c /// │ └── c-1.0.0 -/// │ └── requires d==2.0.0 -/// │ └── satisfied by d-2.0.0 +/// │ ├── requires d==2.0.0 +/// │ │ └── satisfied by d-2.0.0 +/// │ └── requires python>=3.8 /// └── d /// ├── d-1.0.0 +/// │ └── requires python>=3.8 /// └── d-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_filter_sibling_dependencies() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -734,14 +972,14 @@ fn fork_filter_sibling_dependencies() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 7 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -871,27 +1109,31 @@ fn fork_filter_sibling_dependencies() -> Result<()> { /// ```text /// fork-upgrade /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires foo /// │ ├── satisfied by foo-1.0.0 /// │ └── satisfied by foo-2.0.0 /// ├── bar /// │ ├── bar-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── bar-2.0.0 +/// │ └── requires python>=3.8 /// └── foo /// ├── foo-1.0.0 /// │ ├── requires bar==1; sys_platform == "linux" /// │ │ └── satisfied by bar-1.0.0 -/// │ └── requires bar==2; sys_platform != "linux" -/// │ └── satisfied by bar-2.0.0 +/// │ ├── requires bar==2; sys_platform != "linux" +/// │ │ └── satisfied by bar-2.0.0 +/// │ └── requires python>=3.8 /// └── foo-2.0.0 -/// └── requires bar==2 -/// └── satisfied by bar-2.0.0 +/// ├── requires bar==2 +/// │ └── satisfied by bar-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_upgrade() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -913,14 +1155,14 @@ fn fork_upgrade() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 3 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -990,7 +1232,7 @@ fn fork_upgrade() -> Result<()> { /// ```text /// fork-incomplete-markers /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1; python_version < "3.10" /// │ │ └── satisfied by a-1.0.0 @@ -1000,17 +1242,21 @@ fn fork_upgrade() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c; python_version == "3.10" -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c; python_version == "3.10" +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_incomplete_markers() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1034,14 +1280,14 @@ fn fork_incomplete_markers() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -1146,7 +1392,7 @@ fn fork_incomplete_markers() -> Result<()> { /// ```text /// fork-marker-accrue /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0; implementation_name == "cpython" /// │ │ └── satisfied by a-1.0.0 @@ -1154,18 +1400,21 @@ fn fork_incomplete_markers() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==1.0.0; sys_platform == "linux" -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c==1.0.0; sys_platform == "linux" +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c==1.0.0; sys_platform == "darwin" -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c==1.0.0; sys_platform == "darwin" +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_accrue() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1188,14 +1437,14 @@ fn fork_marker_accrue() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 4 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -1287,7 +1536,7 @@ fn fork_marker_accrue() -> Result<()> { /// ```text /// fork-marker-disjoint /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -1295,11 +1544,13 @@ fn fork_marker_accrue() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// └── a-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_disjoint() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1322,7 +1573,7 @@ fn fork_marker_disjoint() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: false exit_code: 1 ----- stdout ----- @@ -1330,7 +1581,7 @@ fn fork_marker_disjoint() -> Result<()> { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because your project depends on package-a{sys_platform == 'linux'}>=2 and package-a{sys_platform == 'linux'}<2, we can conclude that your project's requirements are unsatisfiable. - "### + " ); Ok(()) @@ -1346,7 +1597,7 @@ fn fork_marker_disjoint() -> Result<()> { /// ```text /// fork-marker-inherit-combined-allowed /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -1356,20 +1607,25 @@ fn fork_marker_disjoint() -> Result<()> { /// │ ├── a-1.0.0 /// │ │ ├── requires b>=2; implementation_name == "cpython" /// │ │ │ └── satisfied by b-2.0.0 -/// │ │ └── requires b<2; implementation_name == "pypy" -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b<2; implementation_name == "pypy" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 -/// │ │ └── requires c; sys_platform == "linux" or implementation_name == "pypy" -/// │ │ └── satisfied by c-1.0.0 +/// │ │ ├── requires c; sys_platform == "linux" or implementation_name == "pypy" +/// │ │ │ └── satisfied by c-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit_combined_allowed() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1392,14 +1648,14 @@ fn fork_marker_inherit_combined_allowed() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 6 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -1527,7 +1783,7 @@ fn fork_marker_inherit_combined_allowed() -> Result<()> { /// ```text /// fork-marker-inherit-combined-disallowed /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -1537,20 +1793,25 @@ fn fork_marker_inherit_combined_allowed() -> Result<()> { /// │ ├── a-1.0.0 /// │ │ ├── requires b>=2; implementation_name == "cpython" /// │ │ │ └── satisfied by b-2.0.0 -/// │ │ └── requires b<2; implementation_name == "pypy" -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b<2; implementation_name == "pypy" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 -/// │ │ └── requires c; sys_platform == "linux" or implementation_name == "cpython" -/// │ │ └── satisfied by c-1.0.0 +/// │ │ ├── requires c; sys_platform == "linux" or implementation_name == "cpython" +/// │ │ │ └── satisfied by c-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit_combined_disallowed() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1573,14 +1834,14 @@ fn fork_marker_inherit_combined_disallowed() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -1697,7 +1958,7 @@ fn fork_marker_inherit_combined_disallowed() -> Result<()> { /// ```text /// fork-marker-inherit-combined /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -1707,20 +1968,25 @@ fn fork_marker_inherit_combined_disallowed() -> Result<()> { /// │ ├── a-1.0.0 /// │ │ ├── requires b>=2; implementation_name == "cpython" /// │ │ │ └── satisfied by b-2.0.0 -/// │ │ └── requires b<2; implementation_name == "pypy" -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b<2; implementation_name == "pypy" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 -/// │ │ └── requires c; sys_platform == "linux" -/// │ │ └── satisfied by c-1.0.0 +/// │ │ ├── requires c; sys_platform == "linux" +/// │ │ │ └── satisfied by c-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit_combined() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1743,14 +2009,14 @@ fn fork_marker_inherit_combined() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -1865,7 +2131,7 @@ fn fork_marker_inherit_combined() -> Result<()> { /// ```text /// fork-marker-inherit-isolated /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -1873,17 +2139,20 @@ fn fork_marker_inherit_combined() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b; sys_platform == "linux" -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b; sys_platform == "linux" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 -/// │ └── requires b; sys_platform == "linux" -/// │ └── satisfied by b-1.0.0 +/// │ ├── requires b; sys_platform == "linux" +/// │ │ └── satisfied by b-1.0.0 +/// │ └── requires python>=3.8 /// └── b /// └── b-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit_isolated() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1906,14 +2175,14 @@ fn fork_marker_inherit_isolated() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 4 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2008,7 +2277,7 @@ fn fork_marker_inherit_isolated() -> Result<()> { /// ```text /// fork-marker-inherit-transitive /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -2016,23 +2285,28 @@ fn fork_marker_inherit_isolated() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// ├── c /// │ └── c-1.0.0 -/// │ └── requires d; sys_platform == "linux" -/// │ └── satisfied by d-1.0.0 +/// │ ├── requires d; sys_platform == "linux" +/// │ │ └── satisfied by d-1.0.0 +/// │ └── requires python>=3.8 /// └── d /// └── d-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit_transitive() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2055,14 +2329,14 @@ fn fork_marker_inherit_transitive() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2173,7 +2447,7 @@ fn fork_marker_inherit_transitive() -> Result<()> { /// ```text /// fork-marker-inherit /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -2181,15 +2455,18 @@ fn fork_marker_inherit_transitive() -> Result<()> { /// │ └── satisfied by a-1.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b; sys_platform == "linux" -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b; sys_platform == "linux" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// └── b /// └── b-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_inherit() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2212,14 +2489,14 @@ fn fork_marker_inherit() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 3 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2305,7 +2582,7 @@ fn fork_marker_inherit() -> Result<()> { /// ```text /// fork-marker-limited-inherit /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "linux" /// │ │ └── satisfied by a-2.0.0 @@ -2315,19 +2592,23 @@ fn fork_marker_inherit() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires c; sys_platform == "linux" -/// │ │ └── satisfied by c-1.0.0 +/// │ │ ├── requires c; sys_platform == "linux" +/// │ │ │ └── satisfied by c-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c; sys_platform == "linux" -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c; sys_platform == "linux" +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_limited_inherit() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2351,14 +2632,14 @@ fn fork_marker_limited_inherit() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2463,7 +2744,7 @@ fn fork_marker_limited_inherit() -> Result<()> { /// ```text /// fork-marker-selection /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-0.1.0 @@ -2474,16 +2755,20 @@ fn fork_marker_limited_inherit() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ ├── a-0.1.0 +/// │ │ └── requires python>=3.8 /// │ └── a-0.2.0 -/// │ └── requires b>=2.0.0 -/// │ └── satisfied by b-2.0.0 +/// │ ├── requires b>=2.0.0 +/// │ │ └── satisfied by b-2.0.0 +/// │ └── requires python>=3.8 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// └── b-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_selection() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2507,14 +2792,14 @@ fn fork_marker_selection() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 4 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2603,7 +2888,7 @@ fn fork_marker_selection() -> Result<()> { /// ```text /// fork-marker-track /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-1.3.1 @@ -2616,30 +2901,37 @@ fn fork_marker_selection() -> Result<()> { /// │ └── satisfied by b-2.7 /// ├── a /// │ ├── a-1.3.1 -/// │ │ └── requires c; implementation_name == "iron" -/// │ │ └── satisfied by c-1.10 +/// │ │ ├── requires c; implementation_name == "iron" +/// │ │ │ └── satisfied by c-1.10 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.0.0 /// │ │ ├── requires b>=2.8 /// │ │ │ └── satisfied by b-2.8 -/// │ │ └── requires c; implementation_name == "cpython" -/// │ │ └── satisfied by c-1.10 +/// │ │ ├── requires c; implementation_name == "cpython" +/// │ │ │ └── satisfied by c-1.10 +/// │ │ └── requires python>=3.8 /// │ ├── a-3.1.0 /// │ │ ├── requires b>=2.8 /// │ │ │ └── satisfied by b-2.8 -/// │ │ └── requires c; implementation_name == "pypy" -/// │ │ └── satisfied by c-1.10 +/// │ │ ├── requires c; implementation_name == "pypy" +/// │ │ │ └── satisfied by c-1.10 +/// │ │ └── requires python>=3.8 /// │ └── a-4.3.0 -/// │ └── requires b>=2.8 -/// │ └── satisfied by b-2.8 +/// │ ├── requires b>=2.8 +/// │ │ └── satisfied by b-2.8 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-2.7 +/// │ │ └── requires python>=3.8 /// │ └── b-2.8 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.10 +/// └── requires python>=3.8 /// ``` #[test] fn fork_marker_track() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2663,14 +2955,14 @@ fn fork_marker_track() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2773,7 +3065,7 @@ fn fork_marker_track() -> Result<()> { /// ```text /// fork-non-fork-marker-transitive /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0 /// │ │ └── satisfied by a-1.0.0 @@ -2781,19 +3073,23 @@ fn fork_marker_track() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c>=2.0.0; sys_platform == "linux" -/// │ └── satisfied by c-2.0.0 +/// │ ├── requires c>=2.0.0; sys_platform == "linux" +/// │ │ └── satisfied by c-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c>=2.0.0; sys_platform == "darwin" -/// │ └── satisfied by c-2.0.0 +/// │ ├── requires c>=2.0.0; sys_platform == "darwin" +/// │ │ └── satisfied by c-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_non_fork_marker_transitive() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2816,14 +3112,14 @@ fn fork_non_fork_marker_transitive() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 4 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -2908,7 +3204,7 @@ fn fork_non_fork_marker_transitive() -> Result<()> { /// ```text /// fork-non-local-fork-marker-direct /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0; sys_platform == "linux" /// │ │ └── satisfied by a-1.0.0 @@ -2916,19 +3212,23 @@ fn fork_non_fork_marker_transitive() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c<2.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<2.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c>=2.0.0 -/// │ └── satisfied by c-2.0.0 +/// │ ├── requires c>=2.0.0 +/// │ │ └── satisfied by c-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_non_local_fork_marker_direct() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2951,7 +3251,7 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: false exit_code: 1 ----- stdout ----- @@ -2960,7 +3260,7 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { × No solution found when resolving dependencies: ╰─▶ Because package-a==1.0.0 depends on package-c<2.0.0 and package-b==1.0.0 depends on package-c>=2.0.0, we can conclude that package-a{sys_platform == 'linux'}==1.0.0 and package-b{sys_platform == 'darwin'}==1.0.0 are incompatible. And because your project depends on package-a{sys_platform == 'linux'}==1.0.0 and package-b{sys_platform == 'darwin'}==1.0.0, we can conclude that your project's requirements are unsatisfiable. - "### + " ); Ok(()) @@ -2980,7 +3280,7 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { /// ```text /// fork-non-local-fork-marker-transitive /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0 /// │ │ └── satisfied by a-1.0.0 @@ -2988,19 +3288,23 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c<2.0.0; sys_platform == "linux" -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<2.0.0; sys_platform == "linux" +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c>=2.0.0; sys_platform == "darwin" -/// │ └── satisfied by c-2.0.0 +/// │ ├── requires c>=2.0.0; sys_platform == "darwin" +/// │ │ └── satisfied by c-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_non_local_fork_marker_transitive() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3023,7 +3327,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: false exit_code: 1 ----- stdout ----- @@ -3036,7 +3340,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { we can conclude that package-a==1.0.0 depends on package-c{sys_platform == 'linux'}==1.0.0. And because only package-c{sys_platform == 'darwin'}<=2.0.0 is available and package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}>=2.0.0, we can conclude that package-a==1.0.0 and package-b==1.0.0 are incompatible. And because your project depends on package-a==1.0.0 and package-b==1.0.0, we can conclude that your project's requirements are unsatisfiable. - "### + " ); Ok(()) @@ -3074,7 +3378,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { /// ```text /// fork-overlapping-markers-basic /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=1.0.0; python_version < "3.10" /// │ │ ├── satisfied by a-1.0.0 @@ -3087,12 +3391,15 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { /// │ └── satisfied by a-1.2.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// ├── a-1.1.0 +/// │ └── requires python>=3.8 /// └── a-1.2.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_overlapping_markers_basic() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3116,14 +3423,14 @@ fn fork_overlapping_markers_basic() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -3199,7 +3506,7 @@ fn fork_overlapping_markers_basic() -> Result<()> { /// ```text /// preferences-dependent-forking-bistable /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires cleaver /// │ ├── satisfied by cleaver-2.0.0 @@ -3210,6 +3517,7 @@ fn fork_overlapping_markers_basic() -> Result<()> { /// │ │ │ └── satisfied by fork-sys-platform-1.0.0 /// │ │ ├── requires fork-sys-platform==2; sys_platform != "linux" /// │ │ │ └── satisfied by fork-sys-platform-2.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ ├── requires reject-cleaver2==1; os_name == "posix" /// │ │ │ └── satisfied by reject-cleaver2-1.0.0 /// │ │ └── requires reject-cleaver2-proxy @@ -3220,6 +3528,7 @@ fn fork_overlapping_markers_basic() -> Result<()> { /// │ │ └── satisfied by fork-if-not-forked-3.0.0 /// │ ├── requires fork-if-not-forked-proxy; sys_platform != "linux" /// │ │ └── satisfied by fork-if-not-forked-proxy-1.0.0 +/// │ ├── requires python>=3.8 /// │ ├── requires reject-cleaver1==1; sys_platform == "linux" /// │ │ └── satisfied by reject-cleaver1-1.0.0 /// │ └── requires reject-cleaver1-proxy @@ -3230,39 +3539,53 @@ fn fork_overlapping_markers_basic() -> Result<()> { /// │ │ │ └── satisfied by fork-os-name-1.0.0 /// │ │ ├── requires fork-os-name==2; os_name != "posix" /// │ │ │ └── satisfied by fork-os-name-2.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ └── requires reject-cleaver1-proxy /// │ │ └── satisfied by reject-cleaver1-proxy-1.0.0 /// │ ├── fork-if-not-forked-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── fork-if-not-forked-3.0.0 +/// │ └── requires python>=3.8 /// ├── fork-if-not-forked-proxy /// │ └── fork-if-not-forked-proxy-1.0.0 -/// │ └── requires fork-if-not-forked!=3 -/// │ ├── satisfied by fork-if-not-forked-1.0.0 -/// │ └── satisfied by fork-if-not-forked-2.0.0 +/// │ ├── requires fork-if-not-forked!=3 +/// │ │ ├── satisfied by fork-if-not-forked-1.0.0 +/// │ │ └── satisfied by fork-if-not-forked-2.0.0 +/// │ └── requires python>=3.8 /// ├── fork-os-name /// │ ├── fork-os-name-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── fork-os-name-2.0.0 +/// │ └── requires python>=3.8 /// ├── fork-sys-platform /// │ ├── fork-sys-platform-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── fork-sys-platform-2.0.0 +/// │ └── requires python>=3.8 /// ├── reject-cleaver1 /// │ ├── reject-cleaver1-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── reject-cleaver1-2.0.0 +/// │ └── requires python>=3.8 /// ├── reject-cleaver1-proxy /// │ └── reject-cleaver1-proxy-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires reject-cleaver1==2; sys_platform != "linux" /// │ └── satisfied by reject-cleaver1-2.0.0 /// ├── reject-cleaver2 /// │ ├── reject-cleaver2-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── reject-cleaver2-2.0.0 +/// │ └── requires python>=3.8 /// └── reject-cleaver2-proxy /// └── reject-cleaver2-proxy-1.0.0 +/// ├── requires python>=3.8 /// └── requires reject-cleaver2==2; os_name != "posix" /// └── satisfied by reject-cleaver2-2.0.0 /// ``` #[test] fn preferences_dependent_forking_bistable() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3284,14 +3607,14 @@ fn preferences_dependent_forking_bistable() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 8 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -3454,7 +3777,7 @@ fn preferences_dependent_forking_bistable() -> Result<()> { /// ```text /// preferences-dependent-forking-conflicting /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires bar /// │ │ ├── satisfied by bar-1.0.0 @@ -3467,9 +3790,12 @@ fn preferences_dependent_forking_bistable() -> Result<()> { /// │ └── satisfied by foo-2.0.0 /// ├── bar /// │ ├── bar-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── bar-2.0.0 +/// │ └── requires python>=3.8 /// ├── cleaver /// │ ├── cleaver-2.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ ├── requires reject-cleaver-2 /// │ │ │ └── satisfied by reject-cleaver-2-1.0.0 /// │ │ ├── requires unrelated-dep==1; sys_platform == "linux" @@ -3479,25 +3805,32 @@ fn preferences_dependent_forking_bistable() -> Result<()> { /// │ └── cleaver-1.0.0 /// │ ├── requires bar==1; sys_platform != "linux" /// │ │ └── satisfied by bar-1.0.0 -/// │ └── requires foo==1; sys_platform == "linux" -/// │ └── satisfied by foo-1.0.0 +/// │ ├── requires foo==1; sys_platform == "linux" +/// │ │ └── satisfied by foo-1.0.0 +/// │ └── requires python>=3.8 /// ├── foo /// │ ├── foo-1.0.0 -/// │ │ └── requires bar==2 -/// │ │ └── satisfied by bar-2.0.0 +/// │ │ ├── requires bar==2 +/// │ │ │ └── satisfied by bar-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── foo-2.0.0 +/// │ └── requires python>=3.8 /// ├── reject-cleaver-2 /// │ └── reject-cleaver-2-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires unrelated-dep==3 /// │ └── satisfied by unrelated-dep-3.0.0 /// └── unrelated-dep /// ├── unrelated-dep-1.0.0 +/// │ └── requires python>=3.8 /// ├── unrelated-dep-2.0.0 +/// │ └── requires python>=3.8 /// └── unrelated-dep-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn preferences_dependent_forking_conflicting() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3521,14 +3854,14 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 6 packages in [TIME] - "### + " ); Ok(()) @@ -3544,7 +3877,7 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// ```text /// preferences-dependent-forking-tristable /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires bar /// │ │ ├── satisfied by bar-1.0.0 @@ -3557,10 +3890,12 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// │ └── satisfied by foo-2.0.0 /// ├── a /// │ └── a-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires unrelated-dep3==1; os_name == "posix" /// │ └── satisfied by unrelated-dep3-1.0.0 /// ├── b /// │ └── b-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires unrelated-dep3==2; os_name != "posix" /// │ └── satisfied by unrelated-dep3-2.0.0 /// ├── bar @@ -3570,11 +3905,14 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// │ │ │ └── satisfied by c-2.0.0 /// │ │ ├── requires d; sys_platform != "linux" /// │ │ │ └── satisfied by d-1.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ └── requires reject-cleaver-1 /// │ │ └── satisfied by reject-cleaver-1-1.0.0 /// │ └── bar-2.0.0 +/// │ └── requires python>=3.8 /// ├── c /// │ ├── c-1.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ ├── requires reject-cleaver-1 /// │ │ │ └── satisfied by reject-cleaver-1-1.0.0 /// │ │ ├── requires unrelated-dep2==1; os_name == "posix" @@ -3582,13 +3920,16 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// │ │ └── requires unrelated-dep2==2; os_name != "posix" /// │ │ └── satisfied by unrelated-dep2-2.0.0 /// │ ├── c-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── c-3.0.0 +/// │ └── requires python>=3.8 /// ├── cleaver /// │ ├── cleaver-2.0.0 /// │ │ ├── requires a /// │ │ │ └── satisfied by a-1.0.0 /// │ │ ├── requires b /// │ │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ ├── requires unrelated-dep==1; sys_platform == "linux" /// │ │ │ └── satisfied by unrelated-dep-1.0.0 /// │ │ └── requires unrelated-dep==2; sys_platform != "linux" @@ -3596,13 +3937,15 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// │ └── cleaver-1.0.0 /// │ ├── requires bar==1; sys_platform != "linux" /// │ │ └── satisfied by bar-1.0.0 -/// │ └── requires foo==1; sys_platform == "linux" -/// │ └── satisfied by foo-1.0.0 +/// │ ├── requires foo==1; sys_platform == "linux" +/// │ │ └── satisfied by foo-1.0.0 +/// │ └── requires python>=3.8 /// ├── d /// │ └── d-1.0.0 -/// │ └── requires c!=2 -/// │ ├── satisfied by c-1.0.0 -/// │ └── satisfied by c-3.0.0 +/// │ ├── requires c!=2 +/// │ │ ├── satisfied by c-1.0.0 +/// │ │ └── satisfied by c-3.0.0 +/// │ └── requires python>=3.8 /// ├── foo /// │ ├── foo-1.0.0 /// │ │ ├── requires c!=3; sys_platform == "linux" @@ -3611,35 +3954,48 @@ fn preferences_dependent_forking_conflicting() -> Result<()> { /// │ │ ├── requires c!=2; sys_platform != "linux" /// │ │ │ ├── satisfied by c-1.0.0 /// │ │ │ └── satisfied by c-3.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ └── requires reject-cleaver-1 /// │ │ └── satisfied by reject-cleaver-1-1.0.0 /// │ └── foo-2.0.0 +/// │ └── requires python>=3.8 /// ├── reject-cleaver-1 /// │ └── reject-cleaver-1-1.0.0 +/// │ ├── requires python>=3.8 /// │ ├── requires unrelated-dep2==1; sys_platform == "linux" /// │ │ └── satisfied by unrelated-dep2-1.0.0 /// │ └── requires unrelated-dep2==2; sys_platform != "linux" /// │ └── satisfied by unrelated-dep2-2.0.0 /// ├── reject-cleaver-2 /// │ └── reject-cleaver-2-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires unrelated-dep3==3 /// │ └── satisfied by unrelated-dep3-3.0.0 /// ├── unrelated-dep /// │ ├── unrelated-dep-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── unrelated-dep-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── unrelated-dep-3.0.0 +/// │ └── requires python>=3.8 /// ├── unrelated-dep2 /// │ ├── unrelated-dep2-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── unrelated-dep2-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── unrelated-dep2-3.0.0 +/// │ └── requires python>=3.8 /// └── unrelated-dep3 /// ├── unrelated-dep3-1.0.0 +/// │ └── requires python>=3.8 /// ├── unrelated-dep3-2.0.0 +/// │ └── requires python>=3.8 /// └── unrelated-dep3-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn preferences_dependent_forking_tristable() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3663,14 +4019,14 @@ fn preferences_dependent_forking_tristable() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 11 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -3882,7 +4238,7 @@ fn preferences_dependent_forking_tristable() -> Result<()> { /// ```text /// preferences-dependent-forking /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires bar /// │ │ ├── satisfied by bar-1.0.0 @@ -3895,9 +4251,12 @@ fn preferences_dependent_forking_tristable() -> Result<()> { /// │ └── satisfied by foo-2.0.0 /// ├── bar /// │ ├── bar-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── bar-2.0.0 +/// │ └── requires python>=3.8 /// ├── cleaver /// │ ├── cleaver-2.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ ├── requires reject-cleaver-2 /// │ │ │ └── satisfied by reject-cleaver-2-1.0.0 /// │ │ ├── requires unrelated-dep==1; sys_platform == "linux" @@ -3907,23 +4266,30 @@ fn preferences_dependent_forking_tristable() -> Result<()> { /// │ └── cleaver-1.0.0 /// │ ├── requires bar==1; sys_platform != "linux" /// │ │ └── satisfied by bar-1.0.0 -/// │ └── requires foo==1; sys_platform == "linux" -/// │ └── satisfied by foo-1.0.0 +/// │ ├── requires foo==1; sys_platform == "linux" +/// │ │ └── satisfied by foo-1.0.0 +/// │ └── requires python>=3.8 /// ├── foo /// │ ├── foo-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── foo-2.0.0 +/// │ └── requires python>=3.8 /// ├── reject-cleaver-2 /// │ └── reject-cleaver-2-1.0.0 +/// │ ├── requires python>=3.8 /// │ └── requires unrelated-dep==3 /// │ └── satisfied by unrelated-dep-3.0.0 /// └── unrelated-dep /// ├── unrelated-dep-1.0.0 +/// │ └── requires python>=3.8 /// ├── unrelated-dep-2.0.0 +/// │ └── requires python>=3.8 /// └── unrelated-dep-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn preferences_dependent_forking() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3947,14 +4313,14 @@ fn preferences_dependent_forking() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4076,7 +4442,7 @@ fn preferences_dependent_forking() -> Result<()> { /// ```text /// fork-remaining-universe-partitioning /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a>=2; sys_platform == "windows" /// │ │ └── satisfied by a-2.0.0 @@ -4088,18 +4454,23 @@ fn preferences_dependent_forking() -> Result<()> { /// │ │ │ └── satisfied by b-2.0.0 /// │ │ ├── requires b<2; os_name == "darwin" /// │ │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires python>=3.8 /// │ │ └── requires z; sys_platform == "windows" /// │ │ └── satisfied by z-1.0.0 /// │ └── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-2.0.0 +/// │ └── requires python>=3.8 /// └── z /// └── z-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn fork_remaining_universe_partitioning() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4122,14 +4493,14 @@ fn fork_remaining_universe_partitioning() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4275,14 +4646,14 @@ fn fork_requires_python_full_prerelease() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4360,14 +4731,14 @@ fn fork_requires_python_full() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4449,14 +4820,14 @@ fn fork_requires_python_patch_overlap() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4543,14 +4914,14 @@ fn fork_requires_python() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 1 package in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4624,14 +4995,14 @@ fn requires_python_wheels() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4686,20 +5057,22 @@ fn requires_python_wheels() -> Result<()> { /// ```text /// unreachable-package /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.0.0; sys_platform == "win32" /// │ └── satisfied by a-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b==1.0.0; sys_platform == "linux" -/// │ └── satisfied by b-1.0.0 +/// │ ├── requires b==1.0.0; sys_platform == "linux" +/// │ │ └── satisfied by b-1.0.0 +/// │ └── requires python>=3.8 /// └── b /// └── b-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn unreachable_package() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4721,14 +5094,14 @@ fn unreachable_package() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 2 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4782,7 +5155,7 @@ fn unreachable_package() -> Result<()> { /// ```text /// unreachable-wheels /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0; sys_platform == "win32" /// │ │ └── satisfied by a-1.0.0 @@ -4792,14 +5165,17 @@ fn unreachable_package() -> Result<()> { /// │ └── satisfied by c-1.0.0 /// ├── a /// │ └── a-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn unreachable_wheels() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4823,14 +5199,14 @@ fn unreachable_wheels() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 4 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); @@ -4904,12 +5280,279 @@ fn unreachable_wheels() -> Result<()> { Ok(()) } +/// Check the prioritization for virtual extra and marker packages +/// +/// ```text +/// marker-variants-have-different-extras +/// ├── environment +/// │ └── python3.12 +/// ├── root +/// │ ├── requires psycopg[binary]; platform_python_implementation != "PyPy" +/// │ │ ├── satisfied by psycopg-1.0.0 +/// │ │ └── satisfied by psycopg-1.0.0[binary] +/// │ └── requires psycopg; platform_python_implementation == "PyPy" +/// │ ├── satisfied by psycopg-1.0.0 +/// │ └── satisfied by psycopg-1.0.0[binary] +/// ├── psycopg +/// │ ├── psycopg-1.0.0 +/// │ │ ├── requires python>=3.8 +/// │ │ └── requires tzdata; sys_platform == "win32" +/// │ │ └── satisfied by tzdata-1.0.0 +/// │ └── psycopg-1.0.0[binary] +/// │ └── requires psycopg-binary; implementation_name != "pypy" +/// │ └── satisfied by psycopg-binary-1.0.0 +/// ├── psycopg-binary +/// │ └── psycopg-binary-1.0.0 +/// │ └── requires python>=3.8 +/// └── tzdata +/// └── tzdata-1.0.0 +/// └── requires python>=3.8 +/// ``` +#[test] +fn marker_variants_have_different_extras() -> Result<()> { + let context = TestContext::new("3.12"); + + // In addition to the standard filters, swap out package names for shorter messages + let mut filters = context.filters(); + filters.push((r"marker-variants-have-different-extras-", "package-")); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r###" + [project] + name = "project" + version = "0.1.0" + dependencies = [ + '''marker-variants-have-different-extras-psycopg[binary]; platform_python_implementation != "PyPy"''', + '''marker-variants-have-different-extras-psycopg; platform_python_implementation == "PyPy"''', + ] + requires-python = ">=3.8" + "### + )?; + + let mut cmd = context.lock(); + cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); + cmd.arg("--index-url").arg(packse_index_url()); + uv_snapshot!(filters, cmd, @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 4 packages in [TIME] + " + ); + + let lock = context.read("uv.lock"); + insta::with_settings!({ + filters => filters, + }, { + assert_snapshot!( + lock, @r#" + version = 1 + revision = 2 + requires-python = ">=3.8" + resolution-markers = [ + "platform_python_implementation != 'PyPy'", + "platform_python_implementation == 'PyPy'", + ] + + [[package]] + name = "package-psycopg" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + dependencies = [ + { name = "package-tzdata", marker = "sys_platform == 'win32'" }, + ] + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_psycopg-1.0.0.tar.gz", hash = "sha256:773b5a6c804e81c10cdad6340e4cb88903442108d7a1e22088d29cf61a02815d" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_psycopg-1.0.0-py3-none-any.whl", hash = "sha256:50f29a08795f6715ef9ce887be1d2188f91df3139168f2801f0320b61ec00a6c" }, + ] + + [package.optional-dependencies] + binary = [ + { name = "package-psycopg-binary", marker = "implementation_name != 'pypy' and platform_python_implementation != 'PyPy'" }, + ] + + [[package]] + name = "package-psycopg-binary" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_psycopg_binary-1.0.0.tar.gz", hash = "sha256:9939771dfe78d76e3583492aaec576719780f744b36198b1f18bb16bb5048995" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_psycopg_binary-1.0.0-py3-none-any.whl", hash = "sha256:4fb0aef60e76bc7e339d60dc919f3b6e27e49184ffdef9fb2c3f6902b23b6bd2" }, + ] + + [[package]] + name = "package-tzdata" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_tzdata-1.0.0.tar.gz", hash = "sha256:5aa31d0aec969afbc13584c3209ca2380107bdab68578f881eb2da543ac2ee8e" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/marker_variants_have_different_extras_tzdata-1.0.0-py3-none-any.whl", hash = "sha256:7466eec7ed202434492e7c09a4a7327517aec6d549aaca0436dcc100f9fcb6a5" }, + ] + + [[package]] + name = "project" + version = "0.1.0" + source = { virtual = "." } + dependencies = [ + { name = "package-psycopg" }, + { name = "package-psycopg", extra = ["binary"], marker = "platform_python_implementation != 'PyPy'" }, + ] + + [package.metadata] + requires-dist = [ + { name = "package-psycopg", marker = "platform_python_implementation == 'PyPy'" }, + { name = "package-psycopg", extras = ["binary"], marker = "platform_python_implementation != 'PyPy'" }, + ] + "# + ); + }); + + // Assert the idempotence of `uv lock` when resolving from the lockfile (`--locked`). + context + .lock() + .arg("--locked") + .env_remove(EnvVars::UV_EXCLUDE_NEWER) + .arg("--index-url") + .arg(packse_index_url()) + .assert() + .success(); + + Ok(()) +} + +/// Check the prioritization for virtual marker packages +/// +/// ```text +/// virtual-package-extra-priorities +/// ├── environment +/// │ └── python3.12 +/// ├── root +/// │ ├── requires a==1; python_version >= "3.8" +/// │ │ └── satisfied by a-1.0.0 +/// │ └── requires b; python_version >= "3.9" +/// │ ├── satisfied by b-1.0.0 +/// │ └── satisfied by b-2.0.0 +/// ├── a +/// │ ├── a-1.0.0 +/// │ │ ├── requires b==1; python_version >= "3.10" +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 +/// │ └── a-2.0.0 +/// │ ├── requires b==1; python_version >= "3.10" +/// │ │ └── satisfied by b-1.0.0 +/// │ └── requires python>=3.8 +/// └── b +/// ├── b-1.0.0 +/// │ └── requires python>=3.8 +/// └── b-2.0.0 +/// └── requires python>=3.8 +/// ``` +#[test] +fn virtual_package_extra_priorities() -> Result<()> { + let context = TestContext::new("3.12"); + + // In addition to the standard filters, swap out package names for shorter messages + let mut filters = context.filters(); + filters.push((r"virtual-package-extra-priorities-", "package-")); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r###" + [project] + name = "project" + version = "0.1.0" + dependencies = [ + '''virtual-package-extra-priorities-a==1; python_version >= "3.8"''', + '''virtual-package-extra-priorities-b; python_version >= "3.9"''', + ] + requires-python = ">=3.12" + "###, + )?; + + let mut cmd = context.lock(); + cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); + cmd.arg("--index-url").arg(packse_index_url()); + uv_snapshot!(filters, cmd, @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 3 packages in [TIME] + " + ); + + let lock = context.read("uv.lock"); + insta::with_settings!({ + filters => filters, + }, { + assert_snapshot!( + lock, @r#" + version = 1 + revision = 2 + requires-python = ">=3.12" + + [[package]] + name = "project" + version = "0.1.0" + source = { virtual = "." } + dependencies = [ + { name = "package-a" }, + { name = "package-b" }, + ] + + [package.metadata] + requires-dist = [ + { name = "package-a", marker = "python_full_version >= '3.8'", specifier = "==1" }, + { name = "package-b", marker = "python_full_version >= '3.9'" }, + ] + + [[package]] + name = "package-a" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + dependencies = [ + { name = "package-b" }, + ] + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/virtual_package_extra_priorities_a-1.0.0.tar.gz", hash = "sha256:a9f60dfd06d8c7911509013a06d7b8988be53ff8c42aac58224b0f4330089530" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/virtual_package_extra_priorities_a-1.0.0-py3-none-any.whl", hash = "sha256:009943d4a0d4e075bfe87ccccf019667face4562d7774cb17bbc1e976e5db7ff" }, + ] + + [[package]] + name = "package-b" + version = "1.0.0" + source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" } + sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/virtual_package_extra_priorities_b-1.0.0.tar.gz", hash = "sha256:79a54df14eb28687678447f5270f578f73b325f8234e620d375a87708fd7345c" } + wheels = [ + { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/virtual_package_extra_priorities_b-1.0.0-py3-none-any.whl", hash = "sha256:2aab1a3b90f215cb55b9bfde55b3c3617225ca0da726e8c9543c0727734f1df9" }, + ] + "# + ); + }); + + // Assert the idempotence of `uv lock` when resolving from the lockfile (`--locked`). + context + .lock() + .arg("--locked") + .env_remove(EnvVars::UV_EXCLUDE_NEWER) + .arg("--index-url") + .arg(packse_index_url()) + .assert() + .success(); + + Ok(()) +} + /// When a dependency is only required on a specific platform (like x86_64), omit wheels that target other platforms (like aarch64). /// /// ```text /// specific-architecture /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 @@ -4919,18 +5562,22 @@ fn unreachable_wheels() -> Result<()> { /// │ │ └── satisfied by b-1.0.0 /// │ ├── requires c; platform_machine == "aarch64" /// │ │ └── satisfied by c-1.0.0 -/// │ └── requires d; platform_machine == "i686" -/// │ └── satisfied by d-1.0.0 +/// │ ├── requires d; platform_machine == "i686" +/// │ │ └── satisfied by d-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 +/// │ └── requires python>=3.8 /// ├── c /// │ └── c-1.0.0 +/// │ └── requires python>=3.8 /// └── d /// └── d-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn specific_architecture() -> Result<()> { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4952,14 +5599,14 @@ fn specific_architecture() -> Result<()> { let mut cmd = context.lock(); cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER); cmd.arg("--index-url").arg(packse_index_url()); - uv_snapshot!(filters, cmd, @r###" + uv_snapshot!(filters, cmd, @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Resolved 5 packages in [TIME] - "### + " ); let lock = context.read("uv.lock"); diff --git a/crates/uv/tests/it/pip_compile_scenarios.rs b/crates/uv/tests/it/pip_compile_scenarios.rs index f7e583d92..d8b8e2406 100644 --- a/crates/uv/tests/it/pip_compile_scenarios.rs +++ b/crates/uv/tests/it/pip_compile_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi", unix))] @@ -67,7 +67,7 @@ fn compatible_python_incompatible_override() -> Result<()> { let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.9") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -79,7 +79,7 @@ fn compatible_python_incompatible_override() -> Result<()> { And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. hint: The `--python-version` value (>=3.9) includes Python versions that are not supported by your dependencies (e.g., package-a==1.0.0 only supports >=3.10). Consider using a higher `--python-version` value. - "### + " ); output.assert().failure(); @@ -120,7 +120,7 @@ fn incompatible_python_compatible_override_available_no_wheels() -> Result<()> { // Since there is a compatible Python version available on the system, it should be used to build the source distributions. let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.11") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -131,7 +131,7 @@ fn incompatible_python_compatible_override_available_no_wheels() -> Result<()> { ----- stderr ----- Resolved 1 package in [TIME] - "### + " ); output.assert().success().stdout(predicate::str::contains( @@ -173,7 +173,7 @@ fn incompatible_python_compatible_override_no_compatible_wheels() -> Result<()> // Since there are no compatible wheels for the package and it is not compatible with the local installation, we cannot build the source distribution to determine its dependencies. However, the source distribution includes static metadata, which we can use to determine dependencies without building the package. let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.11") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -185,7 +185,7 @@ fn incompatible_python_compatible_override_no_compatible_wheels() -> Result<()> ----- stderr ----- warning: The requested Python version 3.11 is not available; 3.9.[X] will be used to build dependencies instead. Resolved 1 package in [TIME] - "### + " ); output.assert().success(); @@ -227,7 +227,7 @@ fn incompatible_python_compatible_override_other_wheel() -> Result<()> { // Since there are no wheels for the version of the package compatible with the target and it is not compatible with the local installation, we cannot build the source distribution to determine its dependencies. However, the source distribution includes static metadata, which we can use to determine dependencies without building the package. let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.11") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -239,7 +239,7 @@ fn incompatible_python_compatible_override_other_wheel() -> Result<()> { ----- stderr ----- warning: The requested Python version 3.11 is not available; 3.9.[X] will be used to build dependencies instead. Resolved 1 package in [TIME] - "### + " ); output.assert().success(); @@ -279,7 +279,7 @@ fn incompatible_python_compatible_override_unavailable_no_wheels() -> Result<()> // Since there are no wheels for the package and it is not compatible with the local installation, we cannot build the source distribution to determine its dependencies. However, the source distribution includes static metadata, which we can use to determine dependencies without building the package. let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.11") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -291,7 +291,7 @@ fn incompatible_python_compatible_override_unavailable_no_wheels() -> Result<()> ----- stderr ----- warning: The requested Python version 3.11 is not available; 3.9.[X] will be used to build dependencies instead. Resolved 1 package in [TIME] - "### + " ); output.assert().success(); @@ -326,7 +326,7 @@ fn incompatible_python_compatible_override() -> Result<()> { let output = uv_snapshot!(filters, command(&context, python_versions) .arg("--python-version=3.11") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -338,7 +338,7 @@ fn incompatible_python_compatible_override() -> Result<()> { ----- stderr ----- warning: The requested Python version 3.11 is not available; 3.9.[X] will be used to build dependencies instead. Resolved 1 package in [TIME] - "### + " ); output.assert().success().stdout(predicate::str::contains( @@ -353,18 +353,18 @@ fn incompatible_python_compatible_override() -> Result<()> { /// ```text /// python-patch-override-no-patch /// ├── environment -/// │ └── python3.8.18 +/// │ └── python3.9.20 /// ├── root /// │ └── requires a==1.0.0 /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 -/// └── requires python>=3.8.4 +/// └── requires python>=3.9.4 /// ``` #[cfg(feature = "python-patch")] #[test] fn python_patch_override_no_patch() -> Result<()> { - let context = TestContext::new("3.8.18"); + let context = TestContext::new("3.9.20"); let python_versions = &[]; // In addition to the standard filters, swap out package names for shorter messages @@ -374,21 +374,21 @@ fn python_patch_override_no_patch() -> Result<()> { let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("python-patch-override-no-patch-a==1.0.0")?; - // Since the resolver is asked to solve with 3.8, the minimum compatible Python requirement is treated as 3.8.0. + // Since the resolver is asked to solve with 3.9, the minimum compatible Python requirement is treated as 3.9.0. let output = uv_snapshot!(filters, command(&context, python_versions) - .arg("--python-version=3.8") - , @r###" + .arg("--python-version=3.9") + , @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because the requested Python version (>=3.8) does not satisfy Python>=3.8.4 and package-a==1.0.0 depends on Python>=3.8.4, we can conclude that package-a==1.0.0 cannot be used. + ╰─▶ Because the requested Python version (>=3.9) does not satisfy Python>=3.9.4 and package-a==1.0.0 depends on Python>=3.9.4, we can conclude that package-a==1.0.0 cannot be used. And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - hint: The `--python-version` value (>=3.8) includes Python versions that are not supported by your dependencies (e.g., package-a==1.0.0 only supports >=3.8.4). Consider using a higher `--python-version` value. - "### + hint: The `--python-version` value (>=3.9) includes Python versions that are not supported by your dependencies (e.g., package-a==1.0.0 only supports >=3.9.4). Consider using a higher `--python-version` value. + " ); output.assert().failure(); @@ -401,18 +401,18 @@ fn python_patch_override_no_patch() -> Result<()> { /// ```text /// python-patch-override-patch-compatible /// ├── environment -/// │ └── python3.8.18 +/// │ └── python3.9.20 /// ├── root /// │ └── requires a==1.0.0 /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 -/// └── requires python>=3.8.0 +/// └── requires python>=3.9.0 /// ``` #[cfg(feature = "python-patch")] #[test] fn python_patch_override_patch_compatible() -> Result<()> { - let context = TestContext::new("3.8.18"); + let context = TestContext::new("3.9.20"); let python_versions = &[]; // In addition to the standard filters, swap out package names for shorter messages @@ -423,20 +423,20 @@ fn python_patch_override_patch_compatible() -> Result<()> { requirements_in.write_str("python-patch-override-patch-compatible-a==1.0.0")?; let output = uv_snapshot!(filters, command(&context, python_versions) - .arg("--python-version=3.8.0") - , @r###" + .arg("--python-version=3.9.0") + , @r" success: true exit_code: 0 ----- stdout ----- # This file was autogenerated by uv via the following command: - # uv pip compile requirements.in --cache-dir [CACHE_DIR] --python-version=3.8.0 + # uv pip compile requirements.in --cache-dir [CACHE_DIR] --python-version=3.9.0 package-a==1.0.0 # via -r requirements.in ----- stderr ----- - warning: The requested Python version 3.8.0 is not available; 3.8.18 will be used to build dependencies instead. + warning: The requested Python version 3.9.0 is not available; 3.9.20 will be used to build dependencies instead. Resolved 1 package in [TIME] - "### + " ); output.assert().success().stdout(predicate::str::contains( diff --git a/crates/uv/tests/it/pip_install_scenarios.rs b/crates/uv/tests/it/pip_install_scenarios.rs index c1c68b078..1a95b1caa 100644 --- a/crates/uv/tests/it/pip_install_scenarios.rs +++ b/crates/uv/tests/it/pip_install_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi", unix))] @@ -60,16 +60,17 @@ fn command(context: &TestContext) -> Command { /// ```text /// requires-exact-version-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==2.0.0 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn requires_exact_version_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -77,7 +78,7 @@ fn requires_exact_version_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("requires-exact-version-does-not-exist-a==2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -85,7 +86,7 @@ fn requires_exact_version_does_not_exist() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because there is no version of package-a==2.0.0 and you require package-a==2.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -99,17 +100,19 @@ fn requires_exact_version_does_not_exist() { /// ```text /// requires-greater-version-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.0.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn requires_greater_version_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -117,7 +120,7 @@ fn requires_greater_version_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("requires-greater-version-does-not-exist-a>1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -125,7 +128,7 @@ fn requires_greater_version_does_not_exist() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a<=1.0.0 is available and you require package-a>1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -139,18 +142,21 @@ fn requires_greater_version_does_not_exist() { /// ```text /// requires-less-version-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<2.0.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-2.0.0 +/// │ └── requires python>=3.8 /// ├── a-3.0.0 +/// │ └── requires python>=3.8 /// └── a-4.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn requires_less_version_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -158,7 +164,7 @@ fn requires_less_version_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("requires-less-version-does-not-exist-a<2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -166,7 +172,7 @@ fn requires_less_version_does_not_exist() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a>=2.0.0 is available and you require package-a<2.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -180,14 +186,14 @@ fn requires_less_version_does_not_exist() { /// ```text /// requires-package-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// └── root /// └── requires a /// └── unsatisfied: no versions for package /// ``` #[test] fn requires_package_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -195,7 +201,7 @@ fn requires_package_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("requires-package-does-not-exist-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -203,7 +209,7 @@ fn requires_package_does_not_exist() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because package-a was not found in the package registry and you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -217,18 +223,19 @@ fn requires_package_does_not_exist() { /// ```text /// transitive-requires-package-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 -/// └── requires b +/// ├── requires b /// └── unsatisfied: no versions for package +/// └── requires python>=3.8 /// ``` #[test] fn transitive_requires_package_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -236,7 +243,7 @@ fn transitive_requires_package_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("transitive-requires-package-does-not-exist-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -245,7 +252,7 @@ fn transitive_requires_package_does_not_exist() { × No solution found when resolving dependencies: ╰─▶ Because package-b was not found in the package registry and package-a==1.0.0 depends on package-b, we can conclude that package-a==1.0.0 cannot be used. And because only package-a==1.0.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -259,7 +266,7 @@ fn transitive_requires_package_does_not_exist() { /// ```text /// dependency-excludes-non-contiguous-range-of-compatible-versions /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-1.0.0 @@ -276,45 +283,57 @@ fn transitive_requires_package_does_not_exist() { /// │ └── satisfied by c-2.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b==1.0.0 -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b==1.0.0 +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.0.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.1.0 /// │ │ ├── requires b==2.0.0 /// │ │ │ └── satisfied by b-2.0.0 -/// │ │ └── requires d +/// │ │ ├── requires d /// │ │ └── unsatisfied: no versions for package +/// │ │ └── requires python>=3.8 /// │ ├── a-2.2.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.3.0 /// │ │ ├── requires b==2.0.0 /// │ │ │ └── satisfied by b-2.0.0 -/// │ │ └── requires d +/// │ │ ├── requires d /// │ │ └── unsatisfied: no versions for package +/// │ │ └── requires python>=3.8 /// │ ├── a-2.4.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-3.0.0 -/// │ └── requires b==3.0.0 -/// │ └── satisfied by b-3.0.0 +/// │ ├── requires b==3.0.0 +/// │ │ └── satisfied by b-3.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-3.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 -/// │ └── requires a<2.0.0 -/// │ └── satisfied by a-1.0.0 +/// │ ├── requires a<2.0.0 +/// │ │ └── satisfied by a-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 -/// └── requires a>=3.0.0 -/// └── satisfied by a-3.0.0 +/// ├── requires a>=3.0.0 +/// │ └── satisfied by a-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn dependency_excludes_non_contiguous_range_of_compatible_versions() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -327,7 +346,7 @@ fn dependency_excludes_non_contiguous_range_of_compatible_versions() { .arg("dependency-excludes-non-contiguous-range-of-compatible-versions-a") .arg("dependency-excludes-non-contiguous-range-of-compatible-versions-b<3.0.0,>=2.0.0") .arg("dependency-excludes-non-contiguous-range-of-compatible-versions-c") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -354,7 +373,7 @@ fn dependency_excludes_non_contiguous_range_of_compatible_versions() { package-b>=3.0.0 And because you require package-b>=2.0.0,<3.0.0 and package-c, we can conclude that your requirements are unsatisfiable. - "###); + "); // Only the `2.x` versions of `a` are available since `a==1.0.0` and `a==3.0.0` require incompatible versions of `b`, but all available versions of `c` exclude that range of `a` so resolution fails. assert_not_installed( @@ -379,7 +398,7 @@ fn dependency_excludes_non_contiguous_range_of_compatible_versions() { /// ```text /// dependency-excludes-range-of-compatible-versions /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-1.0.0 @@ -395,38 +414,49 @@ fn dependency_excludes_non_contiguous_range_of_compatible_versions() { /// │ └── satisfied by c-2.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b==1.0.0 -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b==1.0.0 +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.0.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.1.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.2.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.3.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-3.0.0 -/// │ └── requires b==3.0.0 -/// │ └── satisfied by b-3.0.0 +/// │ ├── requires b==3.0.0 +/// │ │ └── satisfied by b-3.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ ├── b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── b-3.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 -/// │ └── requires a<2.0.0 -/// │ └── satisfied by a-1.0.0 +/// │ ├── requires a<2.0.0 +/// │ │ └── satisfied by a-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 -/// └── requires a>=3.0.0 -/// └── satisfied by a-3.0.0 +/// ├── requires a>=3.0.0 +/// │ └── satisfied by a-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn dependency_excludes_range_of_compatible_versions() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -439,7 +469,7 @@ fn dependency_excludes_range_of_compatible_versions() { .arg("dependency-excludes-range-of-compatible-versions-a") .arg("dependency-excludes-range-of-compatible-versions-b<3.0.0,>=2.0.0") .arg("dependency-excludes-range-of-compatible-versions-c") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -466,7 +496,7 @@ fn dependency_excludes_range_of_compatible_versions() { package-b>=3.0.0 And because you require package-b>=2.0.0,<3.0.0 and package-c, we can conclude that your requirements are unsatisfiable. - "###); + "); // Only the `2.x` versions of `a` are available since `a==1.0.0` and `a==3.0.0` require incompatible versions of `b`, but all available versions of `c` exclude that range of `a` so resolution fails. assert_not_installed( @@ -491,7 +521,7 @@ fn dependency_excludes_range_of_compatible_versions() { /// ```text /// excluded-only-compatible-version /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a!=2.0.0 /// │ │ ├── satisfied by a-1.0.0 @@ -500,22 +530,28 @@ fn dependency_excludes_range_of_compatible_versions() { /// │ └── satisfied by b-2.0.0 /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b==1.0.0 -/// │ │ └── satisfied by b-1.0.0 +/// │ │ ├── requires b==1.0.0 +/// │ │ │ └── satisfied by b-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-2.0.0 -/// │ │ └── requires b==2.0.0 -/// │ │ └── satisfied by b-2.0.0 +/// │ │ ├── requires b==2.0.0 +/// │ │ │ └── satisfied by b-2.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-3.0.0 -/// │ └── requires b==3.0.0 -/// │ └── satisfied by b-3.0.0 +/// │ ├── requires b==3.0.0 +/// │ │ └── satisfied by b-3.0.0 +/// │ └── requires python>=3.8 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// ├── b-2.0.0 +/// │ └── requires python>=3.8 /// └── b-3.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn excluded_only_compatible_version() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -524,7 +560,7 @@ fn excluded_only_compatible_version() { uv_snapshot!(filters, command(&context) .arg("excluded-only-compatible-version-a!=2.0.0") .arg("excluded-only-compatible-version-b<3.0.0,>=2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -547,7 +583,7 @@ fn excluded_only_compatible_version() { package-a<2.0.0 package-a>2.0.0 and package-b>=2.0.0,<3.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); // Only `a==1.2.0` is available since `a==1.0.0` and `a==3.0.0` require incompatible versions of `b`. The user has excluded that version of `a` so resolution fails. assert_not_installed( @@ -567,16 +603,17 @@ fn excluded_only_compatible_version() { /// ```text /// excluded-only-version /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a!=1.0.0 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn excluded_only_version() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -584,7 +621,7 @@ fn excluded_only_version() { uv_snapshot!(filters, command(&context) .arg("excluded-only-version-a!=1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -595,7 +632,7 @@ fn excluded_only_version() { package-a<1.0.0 package-a>1.0.0 we can conclude that your requirements are unsatisfiable. - "###); + "); // Only `a==1.0.0` is available but the user excluded it. assert_not_installed(&context.venv, "excluded_only_version_a", &context.temp_dir); @@ -606,7 +643,7 @@ fn excluded_only_version() { /// ```text /// all-extras-required /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[all] /// │ ├── satisfied by a-1.0.0 @@ -615,6 +652,7 @@ fn excluded_only_version() { /// │ └── satisfied by a-1.0.0[extra_c] /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-1.0.0[all] /// │ │ ├── requires a[extra_b] /// │ │ │ ├── satisfied by a-1.0.0 @@ -634,12 +672,14 @@ fn excluded_only_version() { /// │ └── satisfied by c-1.0.0 /// ├── b /// │ └── b-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn all_extras_required() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -647,7 +687,7 @@ fn all_extras_required() { uv_snapshot!(filters, command(&context) .arg("all-extras-required-a[all]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -659,7 +699,7 @@ fn all_extras_required() { + package-a==1.0.0 + package-b==1.0.0 + package-c==1.0.0 - "###); + "); assert_installed( &context.venv, @@ -686,7 +726,7 @@ fn all_extras_required() { /// ```text /// extra-does-not-exist-backtrack /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra] /// │ ├── satisfied by a-2.0.0 @@ -695,17 +735,21 @@ fn all_extras_required() { /// │ └── satisfied by a-1.0.0[extra] /// ├── a /// │ ├── a-2.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-3.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-1.0.0[extra] /// │ └── requires b==1.0.0 /// │ └── satisfied by b-1.0.0 /// └── b /// └── b-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn extra_does_not_exist_backtrack() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -713,7 +757,7 @@ fn extra_does_not_exist_backtrack() { uv_snapshot!(filters, command(&context) .arg("extra-does-not-exist-backtrack-a[extra]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -724,7 +768,7 @@ fn extra_does_not_exist_backtrack() { Installed 1 package in [TIME] + package-a==3.0.0 warning: The package `package-a==3.0.0` does not have an extra named `extra` - "###); + "); // The resolver should not backtrack to `a==1.0.0` because missing extras are allowed during resolution. `b` should not be installed. assert_installed( @@ -740,7 +784,7 @@ fn extra_does_not_exist_backtrack() { /// ```text /// extra-incompatible-with-extra-not-requested /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra_c] /// │ ├── satisfied by a-1.0.0 @@ -748,6 +792,7 @@ fn extra_does_not_exist_backtrack() { /// │ └── satisfied by a-1.0.0[extra_c] /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-1.0.0[extra_b] /// │ │ └── requires b==1.0.0 /// │ │ └── satisfied by b-1.0.0 @@ -756,11 +801,13 @@ fn extra_does_not_exist_backtrack() { /// │ └── satisfied by b-2.0.0 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// └── b-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn extra_incompatible_with_extra_not_requested() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -768,7 +815,7 @@ fn extra_incompatible_with_extra_not_requested() { uv_snapshot!(filters, command(&context) .arg("extra-incompatible-with-extra-not-requested-a[extra_c]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -779,7 +826,7 @@ fn extra_incompatible_with_extra_not_requested() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0 - "###); + "); // Because the user does not request both extras, it is okay that one is incompatible with the other. assert_installed( @@ -801,7 +848,7 @@ fn extra_incompatible_with_extra_not_requested() { /// ```text /// extra-incompatible-with-extra /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra_b,extra_c] /// │ ├── satisfied by a-1.0.0 @@ -809,6 +856,7 @@ fn extra_incompatible_with_extra_not_requested() { /// │ └── satisfied by a-1.0.0[extra_c] /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-1.0.0[extra_b] /// │ │ └── requires b==1.0.0 /// │ │ └── satisfied by b-1.0.0 @@ -817,11 +865,13 @@ fn extra_incompatible_with_extra_not_requested() { /// │ └── satisfied by b-2.0.0 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// └── b-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn extra_incompatible_with_extra() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -829,7 +879,7 @@ fn extra_incompatible_with_extra() { uv_snapshot!(filters, command(&context) .arg("extra-incompatible-with-extra-a[extra_b,extra_c]") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -839,7 +889,7 @@ fn extra_incompatible_with_extra() { ╰─▶ Because only package-a[extra-b]==1.0.0 is available and package-a[extra-b]==1.0.0 depends on package-b==1.0.0, we can conclude that all versions of package-a[extra-b] depend on package-b==1.0.0. And because package-a[extra-c]==1.0.0 depends on package-b==2.0.0 and only package-a[extra-c]==1.0.0 is available, we can conclude that all versions of package-a[extra-b] and all versions of package-a[extra-c] are incompatible. And because you require package-a[extra-b] and package-a[extra-c], we can conclude that your requirements are unsatisfiable. - "###); + "); // Because both `extra_b` and `extra_c` are requested and they require incompatible versions of `b`, `a` cannot be installed. assert_not_installed( @@ -854,7 +904,7 @@ fn extra_incompatible_with_extra() { /// ```text /// extra-incompatible-with-root /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a[extra] /// │ │ ├── satisfied by a-1.0.0 @@ -863,16 +913,19 @@ fn extra_incompatible_with_extra() { /// │ └── satisfied by b-2.0.0 /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-1.0.0[extra] /// │ └── requires b==1.0.0 /// │ └── satisfied by b-1.0.0 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// └── b-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn extra_incompatible_with_root() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -881,7 +934,7 @@ fn extra_incompatible_with_root() { uv_snapshot!(filters, command(&context) .arg("extra-incompatible-with-root-a[extra]") .arg("extra-incompatible-with-root-b==2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -890,7 +943,7 @@ fn extra_incompatible_with_root() { × No solution found when resolving dependencies: ╰─▶ Because only package-a[extra]==1.0.0 is available and package-a[extra]==1.0.0 depends on package-b==1.0.0, we can conclude that all versions of package-a[extra] depend on package-b==1.0.0. And because you require package-a[extra] and package-b==2.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); // Because the user requested `b==2.0.0` but the requested extra requires `b==1.0.0`, the dependencies cannot be satisfied. assert_not_installed( @@ -910,22 +963,24 @@ fn extra_incompatible_with_root() { /// ```text /// extra-required /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra] /// │ ├── satisfied by a-1.0.0 /// │ └── satisfied by a-1.0.0[extra] /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ └── a-1.0.0[extra] /// │ └── requires b /// │ └── satisfied by b-1.0.0 /// └── b /// └── b-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn extra_required() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -933,7 +988,7 @@ fn extra_required() { uv_snapshot!(filters, command(&context) .arg("extra-required-a[extra]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -944,7 +999,7 @@ fn extra_required() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==1.0.0 - "###); + "); assert_installed( &context.venv, @@ -965,16 +1020,17 @@ fn extra_required() { /// ```text /// missing-extra /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra] /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn missing_extra() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -982,7 +1038,7 @@ fn missing_extra() { uv_snapshot!(filters, command(&context) .arg("missing-extra-a[extra]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -993,7 +1049,7 @@ fn missing_extra() { Installed 1 package in [TIME] + package-a==1.0.0 warning: The package `package-a==1.0.0` does not have an extra named `extra` - "###); + "); // Missing extras are ignored during resolution. assert_installed(&context.venv, "missing_extra_a", "1.0.0", &context.temp_dir); @@ -1004,7 +1060,7 @@ fn missing_extra() { /// ```text /// multiple-extras-required /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a[extra_b,extra_c] /// │ ├── satisfied by a-1.0.0 @@ -1012,6 +1068,7 @@ fn missing_extra() { /// │ └── satisfied by a-1.0.0[extra_c] /// ├── a /// │ ├── a-1.0.0 +/// │ │ └── requires python>=3.8 /// │ ├── a-1.0.0[extra_b] /// │ │ └── requires b /// │ │ └── satisfied by b-1.0.0 @@ -1020,12 +1077,14 @@ fn missing_extra() { /// │ └── satisfied by c-1.0.0 /// ├── b /// │ └── b-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// └── c-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn multiple_extras_required() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1033,7 +1092,7 @@ fn multiple_extras_required() { uv_snapshot!(filters, command(&context) .arg("multiple-extras-required-a[extra_b,extra_c]") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1045,7 +1104,7 @@ fn multiple_extras_required() { + package-a==1.0.0 + package-b==1.0.0 + package-c==1.0.0 - "###); + "); assert_installed( &context.venv, @@ -1072,7 +1131,7 @@ fn multiple_extras_required() { /// ```text /// direct-incompatible-versions /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a==1.0.0 /// │ │ └── satisfied by a-1.0.0 @@ -1080,11 +1139,13 @@ fn multiple_extras_required() { /// │ └── satisfied by a-2.0.0 /// └── a /// ├── a-1.0.0 +/// │ └── requires python>=3.8 /// └── a-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn direct_incompatible_versions() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1093,7 +1154,7 @@ fn direct_incompatible_versions() { uv_snapshot!(filters, command(&context) .arg("direct-incompatible-versions-a==1.0.0") .arg("direct-incompatible-versions-a==2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1101,7 +1162,7 @@ fn direct_incompatible_versions() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because you require package-a==1.0.0 and package-a==2.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1120,7 +1181,7 @@ fn direct_incompatible_versions() { /// ```text /// transitive-incompatible-versions /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.0.0 /// │ └── satisfied by a-1.0.0 @@ -1128,12 +1189,13 @@ fn direct_incompatible_versions() { /// └── a-1.0.0 /// ├── requires b==2.0.0 /// └── unsatisfied: no versions for package -/// └── requires b==1.0.0 +/// ├── requires b==1.0.0 /// └── unsatisfied: no versions for package +/// └── requires python>=3.8 /// ``` #[test] fn transitive_incompatible_versions() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1141,7 +1203,7 @@ fn transitive_incompatible_versions() { uv_snapshot!(filters, command(&context) .arg("transitive-incompatible-versions-a==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1150,7 +1212,7 @@ fn transitive_incompatible_versions() { × No solution found when resolving dependencies: ╰─▶ Because package-a==1.0.0 depends on package-b==1.0.0 and package-b==2.0.0, we can conclude that package-a==1.0.0 cannot be used. And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1164,7 +1226,7 @@ fn transitive_incompatible_versions() { /// ```text /// transitive-incompatible-with-root-version /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1172,15 +1234,18 @@ fn transitive_incompatible_versions() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b==2.0.0 -/// │ └── satisfied by b-2.0.0 +/// │ ├── requires b==2.0.0 +/// │ │ └── satisfied by b-2.0.0 +/// │ └── requires python>=3.8 /// └── b /// ├── b-1.0.0 +/// │ └── requires python>=3.8 /// └── b-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_incompatible_with_root_version() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1189,7 +1254,7 @@ fn transitive_incompatible_with_root_version() { uv_snapshot!(filters, command(&context) .arg("transitive-incompatible-with-root-version-a") .arg("transitive-incompatible-with-root-version-b==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1198,7 +1263,7 @@ fn transitive_incompatible_with_root_version() { × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b==2.0.0, we can conclude that all versions of package-a depend on package-b==2.0.0. And because you require package-a and package-b==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1217,7 +1282,7 @@ fn transitive_incompatible_with_root_version() { /// ```text /// transitive-incompatible-with-transitive /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1225,19 +1290,23 @@ fn transitive_incompatible_with_root_version() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c==1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c==2.0.0 -/// │ └── satisfied by c-2.0.0 +/// │ ├── requires c==2.0.0 +/// │ │ └── satisfied by c-2.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_incompatible_with_transitive() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1246,7 +1315,7 @@ fn transitive_incompatible_with_transitive() { uv_snapshot!(filters, command(&context) .arg("transitive-incompatible-with-transitive-a") .arg("transitive-incompatible-with-transitive-b") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1256,7 +1325,7 @@ fn transitive_incompatible_with_transitive() { ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-c==1.0.0, we can conclude that all versions of package-a depend on package-c==1.0.0. And because package-b==1.0.0 depends on package-c==2.0.0 and only package-b==1.0.0 is available, we can conclude that all versions of package-a and all versions of package-b are incompatible. And because you require package-a and package-b, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1275,18 +1344,20 @@ fn transitive_incompatible_with_transitive() { /// ```text /// local-greater-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1.2.3 /// │ ├── satisfied by a-1.2.3+bar /// │ └── satisfied by a-1.2.3+foo /// └── a /// ├── a-1.2.3+bar +/// │ └── requires python>=3.8 /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_greater_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1294,7 +1365,7 @@ fn local_greater_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("local-greater-than-or-equal-a>=1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1304,7 +1375,7 @@ fn local_greater_than_or_equal() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3+foo - "###); + "); // The version '1.2.3+foo' satisfies the constraint '>=1.2.3'. assert_installed( @@ -1320,16 +1391,17 @@ fn local_greater_than_or_equal() { /// ```text /// local-greater-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_greater_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1337,7 +1409,7 @@ fn local_greater_than() { uv_snapshot!(filters, command(&context) .arg("local-greater-than-a>1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1345,7 +1417,7 @@ fn local_greater_than() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.2.3+foo is available and you require package-a>1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed(&context.venv, "local_greater_than_a", &context.temp_dir); } @@ -1355,18 +1427,20 @@ fn local_greater_than() { /// ```text /// local-less-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<=1.2.3 /// │ ├── satisfied by a-1.2.3+bar /// │ └── satisfied by a-1.2.3+foo /// └── a /// ├── a-1.2.3+bar +/// │ └── requires python>=3.8 /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_less_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1374,7 +1448,7 @@ fn local_less_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("local-less-than-or-equal-a<=1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1384,7 +1458,7 @@ fn local_less_than_or_equal() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3+foo - "###); + "); // The version '1.2.3+foo' satisfies the constraint '<=1.2.3'. assert_installed( @@ -1400,16 +1474,17 @@ fn local_less_than_or_equal() { /// ```text /// local-less-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_less_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1417,7 +1492,7 @@ fn local_less_than() { uv_snapshot!(filters, command(&context) .arg("local-less-than-a<1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1425,7 +1500,7 @@ fn local_less_than() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.2.3+foo is available and you require package-a<1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed(&context.venv, "local_less_than_a", &context.temp_dir); } @@ -1435,7 +1510,7 @@ fn local_less_than() { /// ```text /// local-not-latest /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1 /// │ ├── satisfied by a-1.2.3 @@ -1443,12 +1518,15 @@ fn local_less_than() { /// │ └── satisfied by a-1.2.1+foo /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// ├── a-1.2.2+foo +/// │ └── requires python>=3.8 /// └── a-1.2.1+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_not_latest() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1456,7 +1534,7 @@ fn local_not_latest() { uv_snapshot!(filters, command(&context) .arg("local-not-latest-a>=1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1466,7 +1544,7 @@ fn local_not_latest() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.1+foo - "###); + "); assert_installed( &context.venv, @@ -1481,18 +1559,20 @@ fn local_not_latest() { /// ```text /// local-not-used-with-sdist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3 /// │ ├── satisfied by a-1.2.3 /// │ └── satisfied by a-1.2.3+foo /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_not_used_with_sdist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1500,7 +1580,7 @@ fn local_not_used_with_sdist() { uv_snapshot!(filters, command(&context) .arg("local-not-used-with-sdist-a==1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1510,7 +1590,7 @@ fn local_not_used_with_sdist() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3+foo - "###); + "); // The version '1.2.3' with an sdist satisfies the constraint '==1.2.3'. assert_installed( @@ -1526,18 +1606,20 @@ fn local_not_used_with_sdist() { /// ```text /// local-simple /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3 /// │ ├── satisfied by a-1.2.3+bar /// │ └── satisfied by a-1.2.3+foo /// └── a /// ├── a-1.2.3+bar +/// │ └── requires python>=3.8 /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_simple() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1545,7 +1627,7 @@ fn local_simple() { uv_snapshot!(filters, command(&context) .arg("local-simple-a==1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1555,7 +1637,7 @@ fn local_simple() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3+foo - "###); + "); // The version '1.2.3+foo' satisfies the constraint '==1.2.3'. assert_installed( @@ -1571,7 +1653,7 @@ fn local_simple() { /// ```text /// local-transitive-backtrack /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ ├── satisfied by a-1.0.0 @@ -1580,19 +1662,23 @@ fn local_simple() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ ├── a-1.0.0 -/// │ │ └── requires b==2.0.0 -/// │ │ ├── satisfied by b-2.0.0+bar -/// │ │ └── satisfied by b-2.0.0+foo +/// │ │ ├── requires b==2.0.0 +/// │ │ │ ├── satisfied by b-2.0.0+bar +/// │ │ │ └── satisfied by b-2.0.0+foo +/// │ │ └── requires python>=3.8 /// │ └── a-2.0.0 -/// │ └── requires b==2.0.0+bar -/// │ └── satisfied by b-2.0.0+bar +/// │ ├── requires b==2.0.0+bar +/// │ │ └── satisfied by b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_backtrack() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1601,7 +1687,7 @@ fn local_transitive_backtrack() { uv_snapshot!(filters, command(&context) .arg("local-transitive-backtrack-a") .arg("local-transitive-backtrack-b==2.0.0+foo") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1612,7 +1698,7 @@ fn local_transitive_backtrack() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0+foo - "###); + "); // Backtracking to '1.0.0' gives us compatible local versions of b. assert_installed( @@ -1634,7 +1720,7 @@ fn local_transitive_backtrack() { /// ```text /// local-transitive-conflicting /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1642,15 +1728,18 @@ fn local_transitive_backtrack() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b==2.0.0+bar -/// │ └── satisfied by b-2.0.0+bar +/// │ ├── requires b==2.0.0+bar +/// │ │ └── satisfied by b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_conflicting() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1659,7 +1748,7 @@ fn local_transitive_conflicting() { uv_snapshot!(filters, command(&context) .arg("local-transitive-conflicting-a") .arg("local-transitive-conflicting-b==2.0.0+foo") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1668,7 +1757,7 @@ fn local_transitive_conflicting() { × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b==2.0.0+bar, we can conclude that all versions of package-a depend on package-b==2.0.0+bar. And because you require package-a and package-b==2.0.0+foo, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1687,24 +1776,28 @@ fn local_transitive_conflicting() { /// ```text /// local-transitive-confounding /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b==2.0.0 -/// │ ├── satisfied by b-2.0.0 -/// │ ├── satisfied by b-2.0.0+bar -/// │ └── satisfied by b-2.0.0+foo +/// │ ├── requires b==2.0.0 +/// │ │ ├── satisfied by b-2.0.0 +/// │ │ ├── satisfied by b-2.0.0+bar +/// │ │ └── satisfied by b-2.0.0+foo +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0 +/// │ └── requires python>=3.8 /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_confounding() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1712,7 +1805,7 @@ fn local_transitive_confounding() { uv_snapshot!(filters, command(&context) .arg("local-transitive-confounding-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1723,7 +1816,7 @@ fn local_transitive_confounding() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0+foo - "###); + "); // The version '2.0.0+foo' satisfies the constraint '==2.0.0'. assert_installed( @@ -1745,7 +1838,7 @@ fn local_transitive_confounding() { /// ```text /// local-transitive-greater-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1753,16 +1846,19 @@ fn local_transitive_confounding() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b>=2.0.0 -/// │ ├── satisfied by b-2.0.0+bar -/// │ └── satisfied by b-2.0.0+foo +/// │ ├── requires b>=2.0.0 +/// │ │ ├── satisfied by b-2.0.0+bar +/// │ │ └── satisfied by b-2.0.0+foo +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_greater_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1771,7 +1867,7 @@ fn local_transitive_greater_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("local-transitive-greater-than-or-equal-a") .arg("local-transitive-greater-than-or-equal-b==2.0.0+foo") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1782,7 +1878,7 @@ fn local_transitive_greater_than_or_equal() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0+foo - "###); + "); // The version '2.0.0+foo' satisfies both >=2.0.0 and ==2.0.0+foo. assert_installed( @@ -1804,7 +1900,7 @@ fn local_transitive_greater_than_or_equal() { /// ```text /// local-transitive-greater-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1812,15 +1908,18 @@ fn local_transitive_greater_than_or_equal() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b>2.0.0 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b>2.0.0 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_greater_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1829,7 +1928,7 @@ fn local_transitive_greater_than() { uv_snapshot!(filters, command(&context) .arg("local-transitive-greater-than-a") .arg("local-transitive-greater-than-b==2.0.0+foo") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1838,7 +1937,7 @@ fn local_transitive_greater_than() { × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b>2.0.0, we can conclude that all versions of package-a depend on package-b>2.0.0. And because you require package-a and package-b==2.0.0+foo, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1857,7 +1956,7 @@ fn local_transitive_greater_than() { /// ```text /// local-transitive-less-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1865,16 +1964,19 @@ fn local_transitive_greater_than() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b<=2.0.0 -/// │ ├── satisfied by b-2.0.0+bar -/// │ └── satisfied by b-2.0.0+foo +/// │ ├── requires b<=2.0.0 +/// │ │ ├── satisfied by b-2.0.0+bar +/// │ │ └── satisfied by b-2.0.0+foo +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_less_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1883,7 +1985,7 @@ fn local_transitive_less_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("local-transitive-less-than-or-equal-a") .arg("local-transitive-less-than-or-equal-b==2.0.0+foo") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -1894,7 +1996,7 @@ fn local_transitive_less_than_or_equal() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0+foo - "###); + "); // The version '2.0.0+foo' satisfies both <=2.0.0 and ==2.0.0+foo. assert_installed( @@ -1916,7 +2018,7 @@ fn local_transitive_less_than_or_equal() { /// ```text /// local-transitive-less-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1924,15 +2026,18 @@ fn local_transitive_less_than_or_equal() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b<2.0.0 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b<2.0.0 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b-2.0.0+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive_less_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1941,7 +2046,7 @@ fn local_transitive_less_than() { uv_snapshot!(filters, command(&context) .arg("local-transitive-less-than-a") .arg("local-transitive-less-than-b==2.0.0+foo") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -1950,7 +2055,7 @@ fn local_transitive_less_than() { × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b<2.0.0, we can conclude that all versions of package-a depend on package-b<2.0.0. And because you require package-a and package-b==2.0.0+foo, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -1969,7 +2074,7 @@ fn local_transitive_less_than() { /// ```text /// local-transitive /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -1977,16 +2082,19 @@ fn local_transitive_less_than() { /// │ └── satisfied by b-2.0.0+foo /// ├── a /// │ └── a-1.0.0 -/// │ └── requires b==2.0.0 -/// │ ├── satisfied by b-2.0.0+foo -/// │ └── satisfied by b-2.0.0+bar +/// │ ├── requires b==2.0.0 +/// │ │ ├── satisfied by b-2.0.0+foo +/// │ │ └── satisfied by b-2.0.0+bar +/// │ └── requires python>=3.8 /// └── b /// ├── b-2.0.0+foo +/// │ └── requires python>=3.8 /// └── b-2.0.0+bar +/// └── requires python>=3.8 /// ``` #[test] fn local_transitive() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -1995,7 +2103,7 @@ fn local_transitive() { uv_snapshot!(filters, command(&context) .arg("local-transitive-a") .arg("local-transitive-b==2.0.0+foo") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2006,7 +2114,7 @@ fn local_transitive() { Installed 2 packages in [TIME] + package-a==1.0.0 + package-b==2.0.0+foo - "###); + "); // The version '2.0.0+foo' satisfies both ==2.0.0 and ==2.0.0+foo. assert_installed( @@ -2028,18 +2136,20 @@ fn local_transitive() { /// ```text /// local-used-without-sdist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3 /// │ ├── satisfied by a-1.2.3 /// │ └── satisfied by a-1.2.3+foo /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// └── a-1.2.3+foo +/// └── requires python>=3.8 /// ``` #[test] fn local_used_without_sdist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2047,7 +2157,7 @@ fn local_used_without_sdist() { uv_snapshot!(filters, command(&context) .arg("local-used-without-sdist-a==1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2057,7 +2167,7 @@ fn local_used_without_sdist() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3+foo - "###); + "); // The version '1.2.3+foo' satisfies the constraint '==1.2.3'. assert_installed( @@ -2073,17 +2183,19 @@ fn local_used_without_sdist() { /// ```text /// post-equal-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3.post0 /// │ └── satisfied by a-1.2.3.post0 /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post0 +/// └── requires python>=3.8 /// ``` #[test] fn post_equal_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2091,7 +2203,7 @@ fn post_equal_available() { uv_snapshot!(filters, command(&context) .arg("post-equal-available-a==1.2.3.post0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2101,7 +2213,7 @@ fn post_equal_available() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3.post0 - "###); + "); // The version '1.2.3.post0' satisfies the constraint '==1.2.3.post0'. assert_installed( @@ -2117,17 +2229,19 @@ fn post_equal_available() { /// ```text /// post-equal-not-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3.post0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_equal_not_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2135,7 +2249,7 @@ fn post_equal_not_available() { uv_snapshot!(filters, command(&context) .arg("post-equal-not-available-a==1.2.3.post0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2143,7 +2257,7 @@ fn post_equal_not_available() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because there is no version of package-a==1.2.3.post0 and you require package-a==1.2.3.post0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -2157,18 +2271,20 @@ fn post_equal_not_available() { /// ```text /// post-greater-than-or-equal-post /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1.2.3.post0 /// │ ├── satisfied by a-1.2.3.post0 /// │ └── satisfied by a-1.2.3.post1 /// └── a /// ├── a-1.2.3.post0 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_greater_than_or_equal_post() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2176,7 +2292,7 @@ fn post_greater_than_or_equal_post() { uv_snapshot!(filters, command(&context) .arg("post-greater-than-or-equal-post-a>=1.2.3.post0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2186,7 +2302,7 @@ fn post_greater_than_or_equal_post() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3.post1 - "###); + "); // The version '1.2.3.post1' satisfies the constraint '>=1.2.3.post0'. assert_installed( @@ -2202,16 +2318,17 @@ fn post_greater_than_or_equal_post() { /// ```text /// post-greater-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1.2.3 /// │ └── satisfied by a-1.2.3.post1 /// └── a /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_greater_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2219,7 +2336,7 @@ fn post_greater_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("post-greater-than-or-equal-a>=1.2.3") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2229,7 +2346,7 @@ fn post_greater_than_or_equal() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3.post1 - "###); + "); // The version '1.2.3.post1' satisfies the constraint '>=1.2.3'. assert_installed( @@ -2245,18 +2362,21 @@ fn post_greater_than_or_equal() { /// ```text /// post-greater-than-post-not-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3.post2 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-1.2.3 +/// │ └── requires python>=3.8 /// ├── a-1.2.3.post0 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_greater_than_post_not_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2264,7 +2384,7 @@ fn post_greater_than_post_not_available() { uv_snapshot!(filters, command(&context) .arg("post-greater-than-post-not-available-a>1.2.3.post2") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2272,7 +2392,7 @@ fn post_greater_than_post_not_available() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a<=1.2.3.post1 is available and you require package-a>=1.2.3.post3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -2286,17 +2406,19 @@ fn post_greater_than_post_not_available() { /// ```text /// post-greater-than-post /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3.post0 /// │ └── satisfied by a-1.2.3.post1 /// └── a /// ├── a-1.2.3.post0 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_greater_than_post() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2304,7 +2426,7 @@ fn post_greater_than_post() { uv_snapshot!(filters, command(&context) .arg("post-greater-than-post-a>1.2.3.post0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2314,7 +2436,7 @@ fn post_greater_than_post() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.2.3.post1 - "###); + "); // The version '1.2.3.post1' satisfies the constraint '>1.2.3.post0'. assert_installed( @@ -2330,16 +2452,17 @@ fn post_greater_than_post() { /// ```text /// post-greater-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_greater_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2347,7 +2470,7 @@ fn post_greater_than() { uv_snapshot!(filters, command(&context) .arg("post-greater-than-a>1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2355,7 +2478,7 @@ fn post_greater_than() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.2.3.post1 is available and you require package-a>1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed(&context.venv, "post_greater_than_a", &context.temp_dir); } @@ -2365,16 +2488,17 @@ fn post_greater_than() { /// ```text /// post-less-than-or-equal /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<=1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_less_than_or_equal() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2382,7 +2506,7 @@ fn post_less_than_or_equal() { uv_snapshot!(filters, command(&context) .arg("post-less-than-or-equal-a<=1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2390,7 +2514,7 @@ fn post_less_than_or_equal() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.2.3.post1 is available and you require package-a<=1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -2404,16 +2528,17 @@ fn post_less_than_or_equal() { /// ```text /// post-less-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_less_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2421,7 +2546,7 @@ fn post_less_than() { uv_snapshot!(filters, command(&context) .arg("post-less-than-a<1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2429,7 +2554,7 @@ fn post_less_than() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.2.3.post1 is available and you require package-a<1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed(&context.venv, "post_less_than_a", &context.temp_dir); } @@ -2439,17 +2564,19 @@ fn post_less_than() { /// ```text /// post-local-greater-than-post /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3.post1 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-1.2.3.post1 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1+local +/// └── requires python>=3.8 /// ``` #[test] fn post_local_greater_than_post() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2457,7 +2584,7 @@ fn post_local_greater_than_post() { uv_snapshot!(filters, command(&context) .arg("post-local-greater-than-post-a>1.2.3.post1") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2465,7 +2592,7 @@ fn post_local_greater_than_post() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a<=1.2.3.post1+local is available and you require package-a>=1.2.3.post2, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -2479,17 +2606,19 @@ fn post_local_greater_than_post() { /// ```text /// post-local-greater-than /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-1.2.3.post1 +/// │ └── requires python>=3.8 /// └── a-1.2.3.post1+local +/// └── requires python>=3.8 /// ``` #[test] fn post_local_greater_than() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2497,7 +2626,7 @@ fn post_local_greater_than() { uv_snapshot!(filters, command(&context) .arg("post-local-greater-than-a>1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2505,7 +2634,7 @@ fn post_local_greater_than() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only package-a<=1.2.3.post1+local is available and you require package-a>1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -2519,16 +2648,17 @@ fn post_local_greater_than() { /// ```text /// post-simple /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.2.3 /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.2.3.post1 +/// └── requires python>=3.8 /// ``` #[test] fn post_simple() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2536,7 +2666,7 @@ fn post_simple() { uv_snapshot!(filters, command(&context) .arg("post-simple-a==1.2.3") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2544,7 +2674,7 @@ fn post_simple() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because there is no version of package-a==1.2.3 and you require package-a==1.2.3, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed(&context.venv, "post_simple_a", &context.temp_dir); } @@ -2554,7 +2684,7 @@ fn post_simple() { /// ```text /// package-multiple-prereleases-kinds /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1.0.0a1 /// │ ├── satisfied by a-1.0.0a1 @@ -2562,12 +2692,15 @@ fn post_simple() { /// │ └── satisfied by a-1.0.0rc1 /// └── a /// ├── a-1.0.0a1 +/// │ └── requires python>=3.8 /// ├── a-1.0.0b1 +/// │ └── requires python>=3.8 /// └── a-1.0.0rc1 +/// └── requires python>=3.8 /// ``` #[test] fn package_multiple_prereleases_kinds() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2575,7 +2708,7 @@ fn package_multiple_prereleases_kinds() { uv_snapshot!(filters, command(&context) .arg("package-multiple-prereleases-kinds-a>=1.0.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2585,7 +2718,7 @@ fn package_multiple_prereleases_kinds() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0rc1 - "###); + "); // Release candidates should be the highest precedence prerelease kind. assert_installed( @@ -2601,7 +2734,7 @@ fn package_multiple_prereleases_kinds() { /// ```text /// package-multiple-prereleases-numbers /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=1.0.0a1 /// │ ├── satisfied by a-1.0.0a1 @@ -2609,12 +2742,15 @@ fn package_multiple_prereleases_kinds() { /// │ └── satisfied by a-1.0.0a3 /// └── a /// ├── a-1.0.0a1 +/// │ └── requires python>=3.8 /// ├── a-1.0.0a2 +/// │ └── requires python>=3.8 /// └── a-1.0.0a3 +/// └── requires python>=3.8 /// ``` #[test] fn package_multiple_prereleases_numbers() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2622,7 +2758,7 @@ fn package_multiple_prereleases_numbers() { uv_snapshot!(filters, command(&context) .arg("package-multiple-prereleases-numbers-a>=1.0.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2632,7 +2768,7 @@ fn package_multiple_prereleases_numbers() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0a3 - "###); + "); // The latest alpha version should be selected. assert_installed( @@ -2648,18 +2784,21 @@ fn package_multiple_prereleases_numbers() { /// ```text /// package-only-prereleases-boundary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<0.2.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-0.1.0a1 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// └── a-0.3.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn package_only_prereleases_boundary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2667,7 +2806,7 @@ fn package_only_prereleases_boundary() { uv_snapshot!(filters, command(&context) .arg("package-only-prereleases-boundary-a<0.2.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2677,7 +2816,7 @@ fn package_only_prereleases_boundary() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.1.0a1 - "###); + "); // Since there are only prerelease versions of `a` available, a prerelease is allowed. Since the user did not explicitly request a pre-release, pre-releases at the boundary should not be selected. assert_installed( @@ -2693,17 +2832,19 @@ fn package_only_prereleases_boundary() { /// ```text /// package-only-prereleases-in-range /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>0.1.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn package_only_prereleases_in_range() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2711,7 +2852,7 @@ fn package_only_prereleases_in_range() { uv_snapshot!(filters, command(&context) .arg("package-only-prereleases-in-range-a>0.1.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -2721,7 +2862,7 @@ fn package_only_prereleases_in_range() { ╰─▶ Because only package-a<0.1.0 is available and you require package-a>0.1.0, we can conclude that your requirements are unsatisfiable. hint: Pre-releases are available for `package-a` in the requested range (e.g., 1.0.0a1), but pre-releases weren't enabled (try: `--prerelease=allow`) - "###); + "); // Since there are stable versions of `a` available, prerelease versions should not be selected without explicit opt-in. assert_not_installed( @@ -2736,16 +2877,17 @@ fn package_only_prereleases_in_range() { /// ```text /// package-only-prereleases /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn package_only_prereleases() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2753,7 +2895,7 @@ fn package_only_prereleases() { uv_snapshot!(filters, command(&context) .arg("package-only-prereleases-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2763,7 +2905,7 @@ fn package_only_prereleases() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0a1 - "###); + "); // Since there are only prerelease versions of `a` available, it should be installed even though the user did not include a prerelease specifier. assert_installed( @@ -2779,7 +2921,7 @@ fn package_only_prereleases() { /// ```text /// package-prerelease-specified-mixed-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=0.1.0a1 /// │ ├── satisfied by a-0.1.0 @@ -2788,13 +2930,17 @@ fn package_only_prereleases() { /// │ └── satisfied by a-1.0.0a1 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// ├── a-0.3.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn package_prerelease_specified_mixed_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2802,7 +2948,7 @@ fn package_prerelease_specified_mixed_available() { uv_snapshot!(filters, command(&context) .arg("package-prerelease-specified-mixed-available-a>=0.1.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2812,7 +2958,7 @@ fn package_prerelease_specified_mixed_available() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0a1 - "###); + "); // Since the user provided a prerelease specifier, the latest prerelease version should be selected. assert_installed( @@ -2828,7 +2974,7 @@ fn package_prerelease_specified_mixed_available() { /// ```text /// package-prerelease-specified-only-final-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=0.1.0a1 /// │ ├── satisfied by a-0.1.0 @@ -2836,12 +2982,15 @@ fn package_prerelease_specified_mixed_available() { /// │ └── satisfied by a-0.3.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0 +/// │ └── requires python>=3.8 /// └── a-0.3.0 +/// └── requires python>=3.8 /// ``` #[test] fn package_prerelease_specified_only_final_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2852,7 +3001,7 @@ fn package_prerelease_specified_only_final_available() { uv_snapshot!(filters, command(&context) .arg("package-prerelease-specified-only-final-available-a>=0.1.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2862,7 +3011,7 @@ fn package_prerelease_specified_only_final_available() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.3.0 - "###); + "); // The latest stable version should be selected. assert_installed( @@ -2878,7 +3027,7 @@ fn package_prerelease_specified_only_final_available() { /// ```text /// package-prerelease-specified-only-prerelease-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=0.1.0a1 /// │ ├── satisfied by a-0.1.0a1 @@ -2886,12 +3035,15 @@ fn package_prerelease_specified_only_final_available() { /// │ └── satisfied by a-0.3.0a1 /// └── a /// ├── a-0.1.0a1 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// └── a-0.3.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn package_prerelease_specified_only_prerelease_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2902,7 +3054,7 @@ fn package_prerelease_specified_only_prerelease_available() { uv_snapshot!(filters, command(&context) .arg("package-prerelease-specified-only-prerelease-available-a>=0.1.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2912,7 +3064,7 @@ fn package_prerelease_specified_only_prerelease_available() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.3.0a1 - "###); + "); // The latest prerelease version should be selected. assert_installed( @@ -2928,18 +3080,21 @@ fn package_prerelease_specified_only_prerelease_available() { /// ```text /// package-prereleases-boundary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<0.2.0 /// │ └── satisfied by a-0.1.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// └── a-0.3.0 +/// └── requires python>=3.8 /// ``` #[test] fn package_prereleases_boundary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2948,7 +3103,7 @@ fn package_prereleases_boundary() { uv_snapshot!(filters, command(&context) .arg("--prerelease=allow") .arg("package-prereleases-boundary-a<0.2.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -2958,7 +3113,7 @@ fn package_prereleases_boundary() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.1.0 - "###); + "); // Since the user did not use a pre-release specifier, pre-releases at the boundary should not be selected even though pre-releases are allowed. assert_installed( @@ -2974,18 +3129,21 @@ fn package_prereleases_boundary() { /// ```text /// package-prereleases-global-boundary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<0.2.0 /// │ └── satisfied by a-0.1.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// └── a-0.3.0 +/// └── requires python>=3.8 /// ``` #[test] fn package_prereleases_global_boundary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -2994,7 +3152,7 @@ fn package_prereleases_global_boundary() { uv_snapshot!(filters, command(&context) .arg("--prerelease=allow") .arg("package-prereleases-global-boundary-a<0.2.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3004,7 +3162,7 @@ fn package_prereleases_global_boundary() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.1.0 - "###); + "); // Since the user did not use a pre-release specifier, pre-releases at the boundary should not be selected even though pre-releases are allowed. assert_installed( @@ -3020,22 +3178,28 @@ fn package_prereleases_global_boundary() { /// ```text /// package-prereleases-specifier-boundary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a<0.2.0a2 /// │ ├── satisfied by a-0.1.0 /// │ └── satisfied by a-0.2.0a1 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a1 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a2 +/// │ └── requires python>=3.8 /// ├── a-0.2.0a3 +/// │ └── requires python>=3.8 /// └── a-0.3.0 +/// └── requires python>=3.8 /// ``` #[test] fn package_prereleases_specifier_boundary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3043,7 +3207,7 @@ fn package_prereleases_specifier_boundary() { uv_snapshot!(filters, command(&context) .arg("package-prereleases-specifier-boundary-a<0.2.0a2") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3053,7 +3217,7 @@ fn package_prereleases_specifier_boundary() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.2.0a1 - "###); + "); // Since the user used a pre-release specifier, pre-releases at the boundary should be selected. assert_installed( @@ -3069,17 +3233,19 @@ fn package_prereleases_specifier_boundary() { /// ```text /// requires-package-only-prereleases-in-range-global-opt-in /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>0.1.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn requires_package_only_prereleases_in_range_global_opt_in() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3091,7 +3257,7 @@ fn requires_package_only_prereleases_in_range_global_opt_in() { uv_snapshot!(filters, command(&context) .arg("--prerelease=allow") .arg("requires-package-only-prereleases-in-range-global-opt-in-a>0.1.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3101,7 +3267,7 @@ fn requires_package_only_prereleases_in_range_global_opt_in() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0a1 - "###); + "); assert_installed( &context.venv, @@ -3116,17 +3282,19 @@ fn requires_package_only_prereleases_in_range_global_opt_in() { /// ```text /// requires-package-prerelease-and-final-any /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn requires_package_prerelease_and_final_any() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3134,7 +3302,7 @@ fn requires_package_prerelease_and_final_any() { uv_snapshot!(filters, command(&context) .arg("requires-package-prerelease-and-final-any-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3144,7 +3312,7 @@ fn requires_package_prerelease_and_final_any() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.1.0 - "###); + "); // Since the user did not provide a prerelease specifier, the older stable version should be selected. assert_installed( @@ -3160,7 +3328,7 @@ fn requires_package_prerelease_and_final_any() { /// ```text /// transitive-package-only-prereleases-in-range-opt-in /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-0.1.0 @@ -3169,15 +3337,18 @@ fn requires_package_prerelease_and_final_any() { /// │ └── satisfied by b-1.0.0a1 /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b>0.1 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b>0.1 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-0.1.0 +/// │ └── requires python>=3.8 /// └── b-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_prereleases_in_range_opt_in() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3189,7 +3360,7 @@ fn transitive_package_only_prereleases_in_range_opt_in() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-prereleases-in-range-opt-in-a") .arg("transitive-package-only-prereleases-in-range-opt-in-b>0.0.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3200,7 +3371,7 @@ fn transitive_package_only_prereleases_in_range_opt_in() { Installed 2 packages in [TIME] + package-a==0.1.0 + package-b==1.0.0a1 - "###); + "); // Since the user included a dependency on `b` with a prerelease specifier, a prerelease version can be selected. assert_installed( @@ -3222,21 +3393,24 @@ fn transitive_package_only_prereleases_in_range_opt_in() { /// ```text /// transitive-package-only-prereleases-in-range /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b>0.1 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b>0.1 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-0.1.0 +/// │ └── requires python>=3.8 /// └── b-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_prereleases_in_range() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3244,7 +3418,7 @@ fn transitive_package_only_prereleases_in_range() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-prereleases-in-range-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3255,7 +3429,7 @@ fn transitive_package_only_prereleases_in_range() { And because only package-a==0.1.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. hint: Pre-releases are available for `package-b` in the requested range (e.g., 1.0.0a1), but pre-releases weren't enabled (try: `--prerelease=allow`) - "###); + "); // Since there are stable versions of `b` available, the prerelease version should not be selected without explicit opt-in. The available version is excluded by the range requested by the user. assert_not_installed( @@ -3270,20 +3444,22 @@ fn transitive_package_only_prereleases_in_range() { /// ```text /// transitive-package-only-prereleases /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b -/// │ └── unsatisfied: no matching version +/// │ ├── requires b +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// └── b-1.0.0a1 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_prereleases() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3291,7 +3467,7 @@ fn transitive_package_only_prereleases() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-prereleases-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3302,7 +3478,7 @@ fn transitive_package_only_prereleases() { Installed 2 packages in [TIME] + package-a==0.1.0 + package-b==1.0.0a1 - "###); + "); // Since there are only prerelease versions of `b` available, it should be selected even though the user did not opt-in to prereleases. assert_installed( @@ -3324,7 +3500,7 @@ fn transitive_package_only_prereleases() { /// ```text /// transitive-prerelease-and-stable-dependency-many-versions-holes /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -3332,44 +3508,65 @@ fn transitive_package_only_prereleases() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c!=2.0.0a5,!=2.0.0a6,!=2.0.0a7,!=2.0.0b1,<2.0.0b5,>1.0.0 -/// │ ├── satisfied by c-2.0.0a1 -/// │ ├── satisfied by c-2.0.0a2 -/// │ ├── satisfied by c-2.0.0a3 -/// │ ├── satisfied by c-2.0.0a4 -/// │ ├── satisfied by c-2.0.0a8 -/// │ ├── satisfied by c-2.0.0a9 -/// │ ├── satisfied by c-2.0.0b2 -/// │ ├── satisfied by c-2.0.0b3 -/// │ └── satisfied by c-2.0.0b4 +/// │ ├── requires c!=2.0.0a5,!=2.0.0a6,!=2.0.0a7,!=2.0.0b1,<2.0.0b5,>1.0.0 +/// │ │ ├── satisfied by c-2.0.0a1 +/// │ │ ├── satisfied by c-2.0.0a2 +/// │ │ ├── satisfied by c-2.0.0a3 +/// │ │ ├── satisfied by c-2.0.0a4 +/// │ │ ├── satisfied by c-2.0.0a8 +/// │ │ ├── satisfied by c-2.0.0a9 +/// │ │ ├── satisfied by c-2.0.0b2 +/// │ │ ├── satisfied by c-2.0.0b3 +/// │ │ └── satisfied by c-2.0.0b4 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a1 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a2 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a3 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a4 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a5 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a6 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a7 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a8 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a9 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b1 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b2 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b3 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b4 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b5 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b6 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b7 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b8 +/// │ └── requires python>=3.8 /// └── c-2.0.0b9 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_prerelease_and_stable_dependency_many_versions_holes() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3381,7 +3578,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions_holes() { uv_snapshot!(filters, command(&context) .arg("transitive-prerelease-and-stable-dependency-many-versions-holes-a") .arg("transitive-prerelease-and-stable-dependency-many-versions-holes-b") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3405,7 +3602,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions_holes() { package-c>2.0.0a7,<2.0.0b1 package-c>2.0.0b1,<2.0.0b5 ), but pre-releases weren't enabled (try: `--prerelease=allow`) - "###); + "); // Since the user did not explicitly opt-in to a prerelease, it cannot be selected. assert_not_installed( @@ -3425,7 +3622,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions_holes() { /// ```text /// transitive-prerelease-and-stable-dependency-many-versions /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -3433,44 +3630,65 @@ fn transitive_prerelease_and_stable_dependency_many_versions_holes() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c>=2.0.0b1 -/// │ ├── satisfied by c-2.0.0b1 -/// │ ├── satisfied by c-2.0.0b2 -/// │ ├── satisfied by c-2.0.0b3 -/// │ ├── satisfied by c-2.0.0b4 -/// │ ├── satisfied by c-2.0.0b5 -/// │ ├── satisfied by c-2.0.0b6 -/// │ ├── satisfied by c-2.0.0b7 -/// │ ├── satisfied by c-2.0.0b8 -/// │ └── satisfied by c-2.0.0b9 +/// │ ├── requires c>=2.0.0b1 +/// │ │ ├── satisfied by c-2.0.0b1 +/// │ │ ├── satisfied by c-2.0.0b2 +/// │ │ ├── satisfied by c-2.0.0b3 +/// │ │ ├── satisfied by c-2.0.0b4 +/// │ │ ├── satisfied by c-2.0.0b5 +/// │ │ ├── satisfied by c-2.0.0b6 +/// │ │ ├── satisfied by c-2.0.0b7 +/// │ │ ├── satisfied by c-2.0.0b8 +/// │ │ └── satisfied by c-2.0.0b9 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a1 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a2 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a3 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a4 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a5 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a6 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a7 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a8 +/// │ └── requires python>=3.8 /// ├── c-2.0.0a9 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b1 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b2 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b3 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b4 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b5 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b6 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b7 +/// │ └── requires python>=3.8 /// ├── c-2.0.0b8 +/// │ └── requires python>=3.8 /// └── c-2.0.0b9 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_prerelease_and_stable_dependency_many_versions() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3482,7 +3700,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions() { uv_snapshot!(filters, command(&context) .arg("transitive-prerelease-and-stable-dependency-many-versions-a") .arg("transitive-prerelease-and-stable-dependency-many-versions-b") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3495,7 +3713,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions() { And because you require package-a and package-b, we can conclude that your requirements are unsatisfiable. hint: `package-c` was requested with a pre-release marker (e.g., package-c>=2.0.0b1), but pre-releases weren't enabled (try: `--prerelease=allow`) - "###); + "); // Since the user did not explicitly opt-in to a prerelease, it cannot be selected. assert_not_installed( @@ -3515,7 +3733,7 @@ fn transitive_prerelease_and_stable_dependency_many_versions() { /// ```text /// transitive-prerelease-and-stable-dependency-opt-in /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -3526,19 +3744,23 @@ fn transitive_prerelease_and_stable_dependency_many_versions() { /// │ └── satisfied by c-2.0.0b1 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==2.0.0b1 -/// │ └── satisfied by c-2.0.0b1 +/// │ ├── requires c==2.0.0b1 +/// │ │ └── satisfied by c-2.0.0b1 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0b1 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_prerelease_and_stable_dependency_opt_in() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3551,7 +3773,7 @@ fn transitive_prerelease_and_stable_dependency_opt_in() { .arg("transitive-prerelease-and-stable-dependency-opt-in-a") .arg("transitive-prerelease-and-stable-dependency-opt-in-b") .arg("transitive-prerelease-and-stable-dependency-opt-in-c>=0.0.0a1") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3563,7 +3785,7 @@ fn transitive_prerelease_and_stable_dependency_opt_in() { + package-a==1.0.0 + package-b==1.0.0 + package-c==2.0.0b1 - "###); + "); // Since the user explicitly opted-in to a prerelease for `c`, it can be installed. assert_installed( @@ -3591,7 +3813,7 @@ fn transitive_prerelease_and_stable_dependency_opt_in() { /// ```text /// transitive-prerelease-and-stable-dependency /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -3599,19 +3821,23 @@ fn transitive_prerelease_and_stable_dependency_opt_in() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==2.0.0b1 -/// │ └── satisfied by c-2.0.0b1 +/// │ ├── requires c==2.0.0b1 +/// │ │ └── satisfied by c-2.0.0b1 +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0b1 +/// └── requires python>=3.8 /// ``` #[test] fn transitive_prerelease_and_stable_dependency() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3620,7 +3846,7 @@ fn transitive_prerelease_and_stable_dependency() { uv_snapshot!(filters, command(&context) .arg("transitive-prerelease-and-stable-dependency-a") .arg("transitive-prerelease-and-stable-dependency-b") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3631,7 +3857,7 @@ fn transitive_prerelease_and_stable_dependency() { And because only package-a==1.0.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. hint: `package-c` was requested with a pre-release marker (e.g., package-c==2.0.0b1), but pre-releases weren't enabled (try: `--prerelease=allow`) - "###); + "); // Since the user did not explicitly opt-in to a prerelease, it cannot be selected. assert_not_installed( @@ -3677,7 +3903,7 @@ fn python_greater_than_current_backtrack() { uv_snapshot!(filters, command(&context) .arg("python-greater-than-current-backtrack-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3687,7 +3913,7 @@ fn python_greater_than_current_backtrack() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); assert_installed( &context.venv, @@ -3727,7 +3953,7 @@ fn python_greater_than_current_excluded() { uv_snapshot!(filters, command(&context) .arg("python-greater-than-current-excluded-a>=2.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3747,7 +3973,7 @@ fn python_greater_than_current_excluded() { Because the current Python version (3.9.[X]) does not satisfy Python>=3.12 and package-a==4.0.0 depends on Python>=3.12, we can conclude that package-a==4.0.0 cannot be used. And because we know from (2) that package-a>=2.0.0,<4.0.0 cannot be used, we can conclude that package-a>=2.0.0 cannot be used. And because you require package-a>=2.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -3801,7 +4027,7 @@ fn python_greater_than_current_many() { uv_snapshot!(filters, command(&context) .arg("python-greater-than-current-many-a==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3809,7 +4035,7 @@ fn python_greater_than_current_many() { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because there is no version of package-a==1.0.0 and you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -3823,18 +4049,18 @@ fn python_greater_than_current_many() { /// ```text /// python-greater-than-current-patch /// ├── environment -/// │ └── python3.8.12 +/// │ └── python3.9.12 /// ├── root /// │ └── requires a==1.0.0 /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 -/// └── requires python>=3.8.14 (incompatible with environment) +/// └── requires python>=3.9.14 (incompatible with environment) /// ``` #[cfg(feature = "python-patch")] #[test] fn python_greater_than_current_patch() { - let context = TestContext::new("3.8.12"); + let context = TestContext::new("3.9.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3842,16 +4068,16 @@ fn python_greater_than_current_patch() { uv_snapshot!(filters, command(&context) .arg("python-greater-than-current-patch-a==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because the current Python version (3.8.12) does not satisfy Python>=3.8.14 and package-a==1.0.0 depends on Python>=3.8.14, we can conclude that package-a==1.0.0 cannot be used. + ╰─▶ Because the current Python version (3.9.12) does not satisfy Python>=3.9.14 and package-a==1.0.0 depends on Python>=3.9.14, we can conclude that package-a==1.0.0 cannot be used. And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -3883,7 +4109,7 @@ fn python_greater_than_current() { uv_snapshot!(filters, command(&context) .arg("python-greater-than-current-a==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -3892,7 +4118,7 @@ fn python_greater_than_current() { × No solution found when resolving dependencies: ╰─▶ Because the current Python version (3.9.[X]) does not satisfy Python>=3.10 and package-a==1.0.0 depends on Python>=3.10, we can conclude that package-a==1.0.0 cannot be used. And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -3924,7 +4150,7 @@ fn python_less_than_current() { uv_snapshot!(filters, command(&context) .arg("python-less-than-current-a==1.0.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -3934,7 +4160,7 @@ fn python_less_than_current() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); // We ignore the upper bound on Python requirements } @@ -3944,7 +4170,7 @@ fn python_less_than_current() { /// ```text /// python-version-does-not-exist /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a==1.0.0 /// │ └── satisfied by a-1.0.0 @@ -3954,7 +4180,7 @@ fn python_less_than_current() { /// ``` #[test] fn python_version_does_not_exist() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -3962,16 +4188,16 @@ fn python_version_does_not_exist() { uv_snapshot!(filters, command(&context) .arg("python-version-does-not-exist-a==1.0.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because the current Python version (3.8.[X]) does not satisfy Python>=3.30 and package-a==1.0.0 depends on Python>=3.30, we can conclude that package-a==1.0.0 cannot be used. + ╰─▶ Because the current Python version (3.12.[X]) does not satisfy Python>=3.30 and package-a==1.0.0 depends on Python>=3.30, we can conclude that package-a==1.0.0 cannot be used. And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable. - "###); + "); assert_not_installed( &context.venv, @@ -3985,16 +4211,17 @@ fn python_version_does_not_exist() { /// ```text /// no-binary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_binary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4004,7 +4231,7 @@ fn no_binary() { .arg("--no-binary") .arg("no-binary-a") .arg("no-binary-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4014,7 +4241,7 @@ fn no_binary() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); // The source distribution should be used for install } @@ -4024,16 +4251,17 @@ fn no_binary() { /// ```text /// no-build /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_build() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4043,7 +4271,7 @@ fn no_build() { .arg("--only-binary") .arg("no-build-a") .arg("no-build-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4053,7 +4281,7 @@ fn no_build() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); // The wheel should be used for install } @@ -4063,16 +4291,17 @@ fn no_build() { /// ```text /// no-sdist-no-wheels-with-matching-abi /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_sdist_no_wheels_with_matching_abi() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4081,18 +4310,18 @@ fn no_sdist_no_wheels_with_matching_abi() { uv_snapshot!(filters, command(&context) .arg("--python-platform=x86_64-manylinux2014") .arg("no-sdist-no-wheels-with-matching-abi-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python ABI tag (e.g., `cp38`), we can conclude that all versions of package-a cannot be used. + ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python ABI tag (e.g., `cp312`), we can conclude that all versions of package-a cannot be used. And because you require package-a, we can conclude that your requirements are unsatisfiable. - hint: You require CPython 3.8 (`cp38`), but we only found wheels for `package-a` (v1.0.0) with the following Python ABI tag: `graalpy240_310_native` - "###); + hint: You require CPython 3.12 (`cp312`), but we only found wheels for `package-a` (v1.0.0) with the following Python ABI tag: `graalpy240_310_native` + "); assert_not_installed( &context.venv, @@ -4106,16 +4335,17 @@ fn no_sdist_no_wheels_with_matching_abi() { /// ```text /// no-sdist-no-wheels-with-matching-platform /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_sdist_no_wheels_with_matching_platform() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4124,7 +4354,7 @@ fn no_sdist_no_wheels_with_matching_platform() { uv_snapshot!(filters, command(&context) .arg("--python-platform=x86_64-manylinux2014") .arg("no-sdist-no-wheels-with-matching-platform-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4135,7 +4365,7 @@ fn no_sdist_no_wheels_with_matching_platform() { And because you require package-a, we can conclude that your requirements are unsatisfiable. hint: Wheels are available for `package-a` (v1.0.0) on the following platform: `macosx_10_0_ppc64` - "###); + "); assert_not_installed( &context.venv, @@ -4149,16 +4379,17 @@ fn no_sdist_no_wheels_with_matching_platform() { /// ```text /// no-sdist-no-wheels-with-matching-python /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_sdist_no_wheels_with_matching_python() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4167,18 +4398,18 @@ fn no_sdist_no_wheels_with_matching_python() { uv_snapshot!(filters, command(&context) .arg("--python-platform=x86_64-manylinux2014") .arg("no-sdist-no-wheels-with-matching-python-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python implementation tag (e.g., `cp38`), we can conclude that all versions of package-a cannot be used. + ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python implementation tag (e.g., `cp312`), we can conclude that all versions of package-a cannot be used. And because you require package-a, we can conclude that your requirements are unsatisfiable. - hint: You require CPython 3.8 (`cp38`), but we only found wheels for `package-a` (v1.0.0) with the following Python implementation tag: `graalpy310` - "###); + hint: You require CPython 3.12 (`cp312`), but we only found wheels for `package-a` (v1.0.0) with the following Python implementation tag: `graalpy310` + "); assert_not_installed( &context.venv, @@ -4192,16 +4423,17 @@ fn no_sdist_no_wheels_with_matching_python() { /// ```text /// no-wheels-no-build /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_wheels_no_build() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4211,7 +4443,7 @@ fn no_wheels_no_build() { .arg("--only-binary") .arg("no-wheels-no-build-a") .arg("no-wheels-no-build-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4222,7 +4454,7 @@ fn no_wheels_no_build() { And because you require package-a, we can conclude that your requirements are unsatisfiable. hint: Wheels are required for `package-a` because building from source is disabled for `package-a` (i.e., with `--no-build-package package-a`) - "###); + "); assert_not_installed(&context.venv, "no_wheels_no_build_a", &context.temp_dir); } @@ -4232,16 +4464,17 @@ fn no_wheels_no_build() { /// ```text /// no-wheels-with-matching-platform /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_wheels_with_matching_platform() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4249,7 +4482,7 @@ fn no_wheels_with_matching_platform() { uv_snapshot!(filters, command(&context) .arg("no-wheels-with-matching-platform-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4259,7 +4492,7 @@ fn no_wheels_with_matching_platform() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); } /// No wheels are available, only source distributions. @@ -4267,16 +4500,17 @@ fn no_wheels_with_matching_platform() { /// ```text /// no-wheels /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn no_wheels() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4284,7 +4518,7 @@ fn no_wheels() { uv_snapshot!(filters, command(&context) .arg("no-wheels-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4294,7 +4528,7 @@ fn no_wheels() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); } /// No source distributions are available, only wheels but the user has disabled using pre-built binaries. @@ -4302,16 +4536,17 @@ fn no_wheels() { /// ```text /// only-wheels-no-binary /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn only_wheels_no_binary() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4321,7 +4556,7 @@ fn only_wheels_no_binary() { .arg("--no-binary") .arg("only-wheels-no-binary-a") .arg("only-wheels-no-binary-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4332,7 +4567,7 @@ fn only_wheels_no_binary() { And because you require package-a, we can conclude that your requirements are unsatisfiable. hint: A source distribution is required for `package-a` because using pre-built wheels is disabled for `package-a` (i.e., with `--no-binary-package package-a`) - "###); + "); assert_not_installed(&context.venv, "only_wheels_no_binary_a", &context.temp_dir); } @@ -4342,16 +4577,17 @@ fn only_wheels_no_binary() { /// ```text /// only-wheels /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn only_wheels() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4359,7 +4595,7 @@ fn only_wheels() { uv_snapshot!(filters, command(&context) .arg("only-wheels-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4369,7 +4605,7 @@ fn only_wheels() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); } /// A wheel for a specific platform is available alongside the default. @@ -4377,16 +4613,17 @@ fn only_wheels() { /// ```text /// specific-tag-and-default /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-1.0.0 /// └── a /// └── a-1.0.0 +/// └── requires python>=3.8 /// ``` #[test] fn specific_tag_and_default() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4394,7 +4631,7 @@ fn specific_tag_and_default() { uv_snapshot!(filters, command(&context) .arg("specific-tag-and-default-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4404,7 +4641,7 @@ fn specific_tag_and_default() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==1.0.0 - "###); + "); } /// The user requires a version of package `a` which only matches yanked versions. @@ -4412,17 +4649,19 @@ fn specific_tag_and_default() { /// ```text /// package-only-yanked-in-range /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>0.1.0 /// │ └── unsatisfied: no matching version /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn package_only_yanked_in_range() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4430,7 +4669,7 @@ fn package_only_yanked_in_range() { uv_snapshot!(filters, command(&context) .arg("package-only-yanked-in-range-a>0.1.0") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4442,7 +4681,7 @@ fn package_only_yanked_in_range() { package-a==1.0.0 and package-a==1.0.0 was yanked (reason: Yanked for testing), we can conclude that package-a>0.1.0 cannot be used. And because you require package-a>0.1.0, we can conclude that your requirements are unsatisfiable. - "###); + "); // Since there are other versions of `a` available, yanked versions should not be selected without explicit opt-in. assert_not_installed( @@ -4457,16 +4696,17 @@ fn package_only_yanked_in_range() { /// ```text /// package-only-yanked /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── unsatisfied: no matching version /// └── a /// └── a-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn package_only_yanked() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4474,7 +4714,7 @@ fn package_only_yanked() { uv_snapshot!(filters, command(&context) .arg("package-only-yanked-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4483,7 +4723,7 @@ fn package_only_yanked() { × No solution found when resolving dependencies: ╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 was yanked (reason: Yanked for testing), we can conclude that all versions of package-a cannot be used. And because you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); // Yanked versions should not be installed, even if they are the only one available. assert_not_installed(&context.venv, "package_only_yanked_a", &context.temp_dir); @@ -4494,20 +4734,24 @@ fn package_only_yanked() { /// ```text /// package-yanked-specified-mixed-available /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a>=0.1.0 /// │ ├── satisfied by a-0.1.0 /// │ └── satisfied by a-0.3.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// ├── a-0.2.0 (yanked) +/// │ └── requires python>=3.8 /// ├── a-0.3.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn package_yanked_specified_mixed_available() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4515,7 +4759,7 @@ fn package_yanked_specified_mixed_available() { uv_snapshot!(filters, command(&context) .arg("package-yanked-specified-mixed-available-a>=0.1.0") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4525,7 +4769,7 @@ fn package_yanked_specified_mixed_available() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.3.0 - "###); + "); // The latest unyanked version should be selected. assert_installed( @@ -4541,17 +4785,19 @@ fn package_yanked_specified_mixed_available() { /// ```text /// requires-package-yanked-and-unyanked-any /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// └── a /// ├── a-0.1.0 +/// │ └── requires python>=3.8 /// └── a-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn requires_package_yanked_and_unyanked_any() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4559,7 +4805,7 @@ fn requires_package_yanked_and_unyanked_any() { uv_snapshot!(filters, command(&context) .arg("requires-package-yanked-and-unyanked-any-a") - , @r###" + , @r" success: true exit_code: 0 ----- stdout ----- @@ -4569,7 +4815,7 @@ fn requires_package_yanked_and_unyanked_any() { Prepared 1 package in [TIME] Installed 1 package in [TIME] + package-a==0.1.0 - "###); + "); // The unyanked version should be selected. assert_installed( @@ -4585,7 +4831,7 @@ fn requires_package_yanked_and_unyanked_any() { /// ```text /// transitive-package-only-yanked-in-range-opt-in /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-0.1.0 @@ -4593,15 +4839,18 @@ fn requires_package_yanked_and_unyanked_any() { /// │ └── unsatisfied: no matching version /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b>0.1 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b>0.1 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-0.1.0 +/// │ └── requires python>=3.8 /// └── b-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_yanked_in_range_opt_in() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4613,7 +4862,7 @@ fn transitive_package_only_yanked_in_range_opt_in() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-yanked-in-range-opt-in-a") .arg("transitive-package-only-yanked-in-range-opt-in-b==1.0.0") - , @r###" + , @r#" success: true exit_code: 0 ----- stdout ----- @@ -4625,7 +4874,7 @@ fn transitive_package_only_yanked_in_range_opt_in() { + package-a==0.1.0 + package-b==1.0.0 warning: `package-b==1.0.0` is yanked (reason: "Yanked for testing") - "###); + "#); // Since the user included a dependency on `b` with an exact specifier, the yanked version can be selected. assert_installed( @@ -4647,21 +4896,24 @@ fn transitive_package_only_yanked_in_range_opt_in() { /// ```text /// transitive-package-only-yanked-in-range /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b>0.1 -/// │ └── unsatisfied: no matching version +/// │ ├── requires b>0.1 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// ├── b-0.1.0 +/// │ └── requires python>=3.8 /// └── b-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_yanked_in_range() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4669,7 +4921,7 @@ fn transitive_package_only_yanked_in_range() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-yanked-in-range-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4682,7 +4934,7 @@ fn transitive_package_only_yanked_in_range() { and package-b==1.0.0 was yanked (reason: Yanked for testing), we can conclude that package-b>0.1 cannot be used. And because package-a==0.1.0 depends on package-b>0.1, we can conclude that package-a==0.1.0 cannot be used. And because only package-a==0.1.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); // Yanked versions should not be installed, even if they are the only valid version in a range. assert_not_installed( @@ -4697,20 +4949,22 @@ fn transitive_package_only_yanked_in_range() { /// ```text /// transitive-package-only-yanked /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ └── requires a /// │ └── satisfied by a-0.1.0 /// ├── a /// │ └── a-0.1.0 -/// │ └── requires b -/// │ └── unsatisfied: no matching version +/// │ ├── requires b +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// └── b /// └── b-1.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn transitive_package_only_yanked() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4718,7 +4972,7 @@ fn transitive_package_only_yanked() { uv_snapshot!(filters, command(&context) .arg("transitive-package-only-yanked-a") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4728,7 +4982,7 @@ fn transitive_package_only_yanked() { ╰─▶ Because only package-b==1.0.0 is available and package-b==1.0.0 was yanked (reason: Yanked for testing), we can conclude that all versions of package-b cannot be used. And because package-a==0.1.0 depends on package-b, we can conclude that package-a==0.1.0 cannot be used. And because only package-a==0.1.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); // Yanked versions should not be installed, even if they are the only one available. assert_not_installed( @@ -4743,7 +4997,7 @@ fn transitive_package_only_yanked() { /// ```text /// transitive-yanked-and-unyanked-dependency-opt-in /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -4753,19 +5007,23 @@ fn transitive_package_only_yanked() { /// │ └── unsatisfied: no matching version /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==2.0.0 -/// │ └── unsatisfied: no matching version +/// │ ├── requires c==2.0.0 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn transitive_yanked_and_unyanked_dependency_opt_in() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4778,7 +5036,7 @@ fn transitive_yanked_and_unyanked_dependency_opt_in() { .arg("transitive-yanked-and-unyanked-dependency-opt-in-a") .arg("transitive-yanked-and-unyanked-dependency-opt-in-b") .arg("transitive-yanked-and-unyanked-dependency-opt-in-c==2.0.0") - , @r###" + , @r#" success: true exit_code: 0 ----- stdout ----- @@ -4791,7 +5049,7 @@ fn transitive_yanked_and_unyanked_dependency_opt_in() { + package-b==1.0.0 + package-c==2.0.0 warning: `package-c==2.0.0` is yanked (reason: "Yanked for testing") - "###); + "#); // Since the user explicitly selected the yanked version of `c`, it can be installed. assert_installed( @@ -4819,7 +5077,7 @@ fn transitive_yanked_and_unyanked_dependency_opt_in() { /// ```text /// transitive-yanked-and-unyanked-dependency /// ├── environment -/// │ └── python3.8 +/// │ └── python3.12 /// ├── root /// │ ├── requires a /// │ │ └── satisfied by a-1.0.0 @@ -4827,19 +5085,23 @@ fn transitive_yanked_and_unyanked_dependency_opt_in() { /// │ └── satisfied by b-1.0.0 /// ├── a /// │ └── a-1.0.0 -/// │ └── requires c==2.0.0 -/// │ └── unsatisfied: no matching version +/// │ ├── requires c==2.0.0 +/// │ │ └── unsatisfied: no matching version +/// │ └── requires python>=3.8 /// ├── b /// │ └── b-1.0.0 -/// │ └── requires c<=3.0.0,>=1.0.0 -/// │ └── satisfied by c-1.0.0 +/// │ ├── requires c<=3.0.0,>=1.0.0 +/// │ │ └── satisfied by c-1.0.0 +/// │ └── requires python>=3.8 /// └── c /// ├── c-1.0.0 +/// │ └── requires python>=3.8 /// └── c-2.0.0 (yanked) +/// └── requires python>=3.8 /// ``` #[test] fn transitive_yanked_and_unyanked_dependency() { - let context = TestContext::new("3.8"); + let context = TestContext::new("3.12"); // In addition to the standard filters, swap out package names for shorter messages let mut filters = context.filters(); @@ -4848,7 +5110,7 @@ fn transitive_yanked_and_unyanked_dependency() { uv_snapshot!(filters, command(&context) .arg("transitive-yanked-and-unyanked-dependency-a") .arg("transitive-yanked-and-unyanked-dependency-b") - , @r###" + , @r" success: false exit_code: 1 ----- stdout ----- @@ -4857,7 +5119,7 @@ fn transitive_yanked_and_unyanked_dependency() { × No solution found when resolving dependencies: ╰─▶ Because package-c==2.0.0 was yanked (reason: Yanked for testing) and package-a==1.0.0 depends on package-c==2.0.0, we can conclude that package-a==1.0.0 cannot be used. And because only package-a==1.0.0 is available and you require package-a, we can conclude that your requirements are unsatisfiable. - "###); + "); // Since the user did not explicitly select the yanked version, it cannot be used. assert_not_installed( diff --git a/scripts/scenarios/generate.py b/scripts/scenarios/generate.py index d6db67eeb..e5f96b2f9 100755 --- a/scripts/scenarios/generate.py +++ b/scripts/scenarios/generate.py @@ -243,7 +243,9 @@ def main(scenarios: list[Path], snapshot_update: bool = True): env=env, ) if exit_code != 0: - logging.warning(f"Snapshot update failed (Exit code: {exit_code})") + logging.warning( + f"Snapshot update failed with exit code {exit_code} (use -v to show details)" + ) else: logging.info("Skipping snapshot update") diff --git a/scripts/scenarios/requirements.txt b/scripts/scenarios/requirements.txt index 09e4fcf19..c89bdb429 100644 --- a/scripts/scenarios/requirements.txt +++ b/scripts/scenarios/requirements.txt @@ -1,5 +1,5 @@ # This file was autogenerated by uv via the following command: -# uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt --refresh-package packse -n +# uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt -n chevron-blue==0.2.1 # via # -r scripts/scenarios/requirements.in @@ -10,7 +10,7 @@ msgspec==0.18.6 # via packse packaging==24.2 # via hatchling -packse==0.3.45 +packse==0.3.47 # via -r scripts/scenarios/requirements.in pathspec==0.12.1 # via hatchling diff --git a/scripts/scenarios/templates/compile.mustache b/scripts/scenarios/templates/compile.mustache index 973004fcb..aa6db8529 100644 --- a/scripts/scenarios/templates/compile.mustache +++ b/scripts/scenarios/templates/compile.mustache @@ -33,7 +33,7 @@ fn command(context: &TestContext, python_versions: &[&str]) -> Command { .arg(packse_index_url()) .arg("--find-links") .arg(build_vendor_links_url()); - context.add_shared_args(&mut command, true); + context.add_shared_options(&mut command, true); command.env_remove(EnvVars::UV_EXCLUDE_NEWER); command.env(EnvVars::UV_TEST_PYTHON_PATH, python_path); diff --git a/scripts/scenarios/templates/install.mustache b/scripts/scenarios/templates/install.mustache index be425f929..15f48077e 100644 --- a/scripts/scenarios/templates/install.mustache +++ b/scripts/scenarios/templates/install.mustache @@ -50,7 +50,7 @@ fn command(context: &TestContext) -> Command { .arg(packse_index_url()) .arg("--find-links") .arg(build_vendor_links_url()); - context.add_shared_args(&mut command, true); + context.add_shared_options(&mut command, true); command.env_remove(EnvVars::UV_EXCLUDE_NEWER); command } diff --git a/scripts/sync_scenarios.sh b/scripts/sync_scenarios.sh index 62c323b4b..ea68bacb4 100755 --- a/scripts/sync_scenarios.sh +++ b/scripts/sync_scenarios.sh @@ -15,6 +15,10 @@ # For development purposes, the `./scripts/scenarios/generate.py` script can be used directly to generate # test cases from a local set of scenarios. # +# To update the packse version, run the following command first: +# +# $ uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt --upgrade-package packse +# # See `scripts/scenarios/` for supporting files. set -eu