uv/crates/uv/tests/lock_scenarios.rs

882 lines
38 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! DO NOT EDIT
//!
//! Generated with `./scripts/sync_scenarios.sh`
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.18/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi"))]
#![allow(clippy::needless_raw_string_hashes)]
use anyhow::Result;
use assert_fs::prelude::*;
use insta::assert_snapshot;
use common::{uv_snapshot, TestContext};
mod common;
/// An extremely basic test of universal resolution. In this case, the resolution
/// should contain two distinct versions of `a` depending on `sys_platform`.
///
/// ```text
/// fork-basic
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a>=2; sys_platform == "linux"
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires a<2; sys_platform == "darwin"
/// │ └── satisfied by a-1.0.0
/// └── a
/// ├── a-1.0.0
/// └── a-2.0.0
/// ```
#[test]
fn fork_basic() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-basic-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-basic-a>=2; sys_platform == "linux"''',
'''fork-basic-a<2; sys_platform == "darwin"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
Resolved 3 packages in [TIME]
"###
);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock"))?;
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.8"
[[distribution]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-1.0.0.tar.gz#sha256=3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a", hash = "sha256:3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-1.0.0-py3-none-any.whl#sha256=b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e", hash = "sha256:b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e" }]
[[distribution]]
name = "package-a"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-2.0.0.tar.gz#sha256=ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e", hash = "sha256:ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-2.0.0-py3-none-any.whl#sha256=9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01", hash = "sha256:9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01" }]
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+."
sdist = { path = "." }
[[distribution.dependencies]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'darwin'"
[[distribution.dependencies]]
name = "package-a"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'linux'"
"###
);
});
Ok(())
}
/// This is actually a non-forking test case that tests the tracking of marker
/// expressions in general. In this case, the dependency on `c` should have its
/// marker expressions automatically combined. In this case, it's `linux OR darwin`,
/// even though `linux OR darwin` doesn't actually appear verbatim as a marker
/// expression for any dependency on `c`.
///
/// ```text
/// fork-marker-accrue
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a==1.0.0; implementation_name == "cpython"
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b==1.0.0; implementation_name == "pypy"
/// │ └── 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
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c==1.0.0; sys_platform == "darwin"
/// │ └── satisfied by c-1.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_marker_accrue() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-marker-accrue-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-marker-accrue-a==1.0.0; implementation_name == "cpython"''',
'''fork-marker-accrue-b==1.0.0; implementation_name == "pypy"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
Resolved 4 packages in [TIME]
"###
);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock"))?;
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.8"
[[distribution]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_a-1.0.0.tar.gz#sha256=9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37", hash = "sha256:9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_a-1.0.0-py3-none-any.whl#sha256=5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a", hash = "sha256:5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a" }]
[[distribution.dependencies]]
name = "package-c"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'linux'"
[[distribution]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_b-1.0.0.tar.gz#sha256=d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859", hash = "sha256:d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_b-1.0.0-py3-none-any.whl#sha256=e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f", hash = "sha256:e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f" }]
[[distribution.dependencies]]
name = "package-c"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'darwin'"
[[distribution]]
name = "package-c"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_c-1.0.0.tar.gz#sha256=81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad", hash = "sha256:81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_c-1.0.0-py3-none-any.whl#sha256=f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6", hash = "sha256:f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6" }]
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+."
sdist = { path = "." }
[[distribution.dependencies]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "implementation_name == 'cpython'"
[[distribution.dependencies]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "implementation_name == 'pypy'"
"###
);
});
Ok(())
}
/// A basic test that ensures, at least in this one basic case, that forking in
/// universal resolution happens only when the corresponding marker expressions are
/// completely disjoint. Here, we provide two completely incompatible dependency
/// specifications with equivalent markers. Thus, they are trivially not disjoint,
/// and resolution should fail. NOTE: This acts a regression test for the initial
/// version of universal resolution that would fork whenever a package was repeated
/// in the list of dependency specifications. So previously, this would produce a
/// resolution with both `1.0.0` and `2.0.0` of `a`. But of course, the correct
/// behavior is to fail resolving.
///
/// ```text
/// fork-marker-disjoint
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a>=2; sys_platform == "linux"
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires a<2; sys_platform == "linux"
/// │ └── satisfied by a-1.0.0
/// └── a
/// ├── a-1.0.0
/// └── a-2.0.0
/// ```
#[test]
fn fork_marker_disjoint() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-marker-disjoint-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-marker-disjoint-a>=2; sys_platform == "linux"''',
'''fork-marker-disjoint-a<2; sys_platform == "linux"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
× No solution found when resolving dependencies:
╰─▶ Because project==0.1.0 depends on package-a{sys_platform == 'linux'}>=2 and package-a{sys_platform == 'linux'}<2, we can conclude that project==0.1.0 cannot be used.
And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable.
"###
);
Ok(())
}
/// This tests a case where the resolver forks because of non-overlapping marker
/// expressions on `b`. In the original universal resolver implementation, this
/// resulted in multiple versions of `a` being unconditionally included in the lock
/// file. So this acts as a regression test to ensure that only one version of `a`
/// is selected.
///
/// ```text
/// fork-marker-selection
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-0.1.0
/// │ │ └── satisfied by a-0.2.0
/// │ ├── requires b>=2; sys_platform == "linux"
/// │ │ └── satisfied by b-2.0.0
/// │ └── requires b<2; sys_platform == "darwin"
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ ├── a-0.1.0
/// │ └── a-0.2.0
/// │ └── requires b>=2.0.0
/// │ └── satisfied by b-2.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[test]
fn fork_marker_selection() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-marker-selection-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-marker-selection-a''',
'''fork-marker-selection-b>=2; sys_platform == "linux"''',
'''fork-marker-selection-b<2; sys_platform == "darwin"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
Resolved 5 packages in [TIME]
"###
);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock"))?;
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.8"
[[distribution]]
name = "package-a"
version = "0.1.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.1.0.tar.gz#sha256=03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282", hash = "sha256:03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.1.0-py3-none-any.whl#sha256=0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473", hash = "sha256:0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473" }]
[[distribution]]
name = "package-a"
version = "0.2.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.2.0.tar.gz#sha256=ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f", hash = "sha256:ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.2.0-py3-none-any.whl#sha256=78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c", hash = "sha256:78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c" }]
[[distribution.dependencies]]
name = "package-b"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-1.0.0.tar.gz#sha256=97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1", hash = "sha256:97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-1.0.0-py3-none-any.whl#sha256=aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca", hash = "sha256:aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca" }]
[[distribution]]
name = "package-b"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-2.0.0.tar.gz#sha256=1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a", hash = "sha256:1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-2.0.0-py3-none-any.whl#sha256=ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf", hash = "sha256:ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf" }]
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+."
sdist = { path = "." }
[[distribution.dependencies]]
name = "package-a"
version = "0.1.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution.dependencies]]
name = "package-a"
version = "0.2.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution.dependencies]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'darwin'"
[[distribution.dependencies]]
name = "package-b"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'linux'"
"###
);
});
Ok(())
}
///
/// ```text
/// fork-marker-track
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-1.3.1
/// │ │ ├── satisfied by a-2.0.0
/// │ │ ├── satisfied by a-3.1.0
/// │ │ └── satisfied by a-4.3.0
/// │ ├── requires b>=2.8; sys_platform == "linux"
/// │ │ └── satisfied by b-2.8
/// │ └── requires b<2.8; sys_platform == "darwin"
/// │ └── satisfied by b-2.7
/// ├── a
/// │ ├── a-1.3.1
/// │ │ └── requires c; implementation_name == "iron"
/// │ │ └── satisfied by c-1.10
/// │ ├── a-2.0.0
/// │ │ ├── requires b>=2.8
/// │ │ │ └── satisfied by b-2.8
/// │ │ └── requires c; implementation_name == "cpython"
/// │ │ └── satisfied by c-1.10
/// │ ├── a-3.1.0
/// │ │ ├── requires b>=2.8
/// │ │ │ └── satisfied by b-2.8
/// │ │ └── requires c; implementation_name == "pypy"
/// │ │ └── satisfied by c-1.10
/// │ └── a-4.3.0
/// │ └── requires b>=2.8
/// │ └── satisfied by b-2.8
/// ├── b
/// │ ├── b-2.7
/// │ └── b-2.8
/// └── c
/// └── c-1.10
/// ```
#[test]
fn fork_marker_track() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-marker-track-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-marker-track-a''',
'''fork-marker-track-b>=2.8; sys_platform == "linux"''',
'''fork-marker-track-b<2.8; sys_platform == "darwin"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
Resolved 6 packages in [TIME]
"###
);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock"))?;
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.8"
[[distribution]]
name = "package-a"
version = "1.3.1"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-1.3.1.tar.gz#sha256=b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37", hash = "sha256:b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-1.3.1-py3-none-any.whl#sha256=8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f", hash = "sha256:8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f" }]
[[distribution.dependencies]]
name = "package-c"
version = "1.10"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "implementation_name == 'iron'"
[[distribution]]
name = "package-a"
version = "4.3.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-4.3.0.tar.gz#sha256=46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75", hash = "sha256:46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-4.3.0-py3-none-any.whl#sha256=73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5", hash = "sha256:73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5" }]
[[distribution.dependencies]]
name = "package-b"
version = "2.8"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution]]
name = "package-b"
version = "2.7"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.7.tar.gz#sha256=25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd", hash = "sha256:25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.7-py3-none-any.whl#sha256=be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808", hash = "sha256:be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808" }]
[[distribution]]
name = "package-b"
version = "2.8"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.8.tar.gz#sha256=7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628", hash = "sha256:7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.8-py3-none-any.whl#sha256=d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1", hash = "sha256:d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1" }]
[[distribution]]
name = "package-c"
version = "1.10"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_c-1.10.tar.gz#sha256=6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930", hash = "sha256:6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_c-1.10-py3-none-any.whl#sha256=19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff", hash = "sha256:19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff" }]
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+."
sdist = { path = "." }
[[distribution.dependencies]]
name = "package-a"
version = "1.3.1"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution.dependencies]]
name = "package-a"
version = "4.3.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution.dependencies]]
name = "package-b"
version = "2.7"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'darwin'"
[[distribution.dependencies]]
name = "package-b"
version = "2.8"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'linux'"
"###
);
});
Ok(())
}
/// This is the same setup as `non-local-fork-marker-transitive`, but the disjoint
/// dependency specifications on `c` use the same constraints and thus depend on the
/// same version of `c`. In this case, there is no conflict.
///
/// ```text
/// fork-non-fork-marker-transitive
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b==1.0.0
/// │ └── 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
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c>=2.0.0; sys_platform == "darwin"
/// │ └── satisfied by c-2.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0
/// ```
#[test]
fn fork_non_fork_marker_transitive() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-non-fork-marker-transitive-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-non-fork-marker-transitive-a==1.0.0''',
'''fork-non-fork-marker-transitive-b==1.0.0''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
Resolved 4 packages in [TIME]
"###
);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock"))?;
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.8"
[[distribution]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_a-1.0.0.tar.gz#sha256=017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749", hash = "sha256:017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_a-1.0.0-py3-none-any.whl#sha256=d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c", hash = "sha256:d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c" }]
[[distribution.dependencies]]
name = "package-c"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'linux'"
[[distribution]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_b-1.0.0.tar.gz#sha256=f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a", hash = "sha256:f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_b-1.0.0-py3-none-any.whl#sha256=d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4", hash = "sha256:d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4" }]
[[distribution.dependencies]]
name = "package-c"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
marker = "sys_platform == 'darwin'"
[[distribution]]
name = "package-c"
version = "2.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_c-2.0.0.tar.gz#sha256=c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34", hash = "sha256:c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34" }
wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_c-2.0.0-py3-none-any.whl#sha256=661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74", hash = "sha256:661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74" }]
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+."
sdist = { path = "." }
[[distribution.dependencies]]
name = "package-a"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
[[distribution.dependencies]]
name = "package-b"
version = "1.0.0"
source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/"
"###
);
});
Ok(())
}
/// This is like `non-local-fork-marker-transitive`, but the marker expressions are
/// placed on sibling dependency specifications. However, the actual dependency on
/// `c` is indirect, and thus, there's no fork detected by the universal resolver.
/// This in turn results in an unresolvable conflict on `c`.
///
/// ```text
/// fork-non-local-fork-marker-direct
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a==1.0.0; sys_platform == "linux"
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b==1.0.0; sys_platform == "darwin"
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires c<2.0.0
/// │ └── satisfied by c-1.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c>=2.0.0
/// │ └── satisfied by c-2.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0
/// ```
#[test]
fn fork_non_local_fork_marker_direct() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-non-local-fork-marker-direct-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-non-local-fork-marker-direct-a==1.0.0; sys_platform == "linux"''',
'''fork-non-local-fork-marker-direct-b==1.0.0; sys_platform == "darwin"''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
× No solution found when resolving dependencies:
╰─▶ Because package-b{sys_platform == 'darwin'}==1.0.0 depends on package-c>=2.0.0 and package-a{sys_platform == 'linux'}==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 project==0.1.0 depends on package-a{sys_platform == 'linux'}==1.0.0 and package-b{sys_platform == 'darwin'}==1.0.0, we can conclude that project==0.1.0 cannot be used.
And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable.
"###
);
Ok(())
}
/// This setup introduces dependencies on two distinct versions of `c`, where each
/// such dependency has a marker expression attached that would normally make them
/// disjoint. In a non-universal resolver, this is no problem. But in a forking
/// resolver that tries to create one universal resolution, this can lead to two
/// distinct versions of `c` in the resolution. This is in and of itself not a
/// problem, since that is an expected scenario for universal resolution. The
/// problem in this case is that because the dependency specifications for `c` occur
/// in two different points (i.e., they are not sibling dependency specifications)
/// in the dependency graph, the forking resolver does not "detect" it, and thus
/// never forks and thus this results in "no resolution."
///
/// ```text
/// fork-non-local-fork-marker-transitive
/// ├── environment
/// │ └── python3.8
/// ├── root
/// │ ├── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b==1.0.0
/// │ └── 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
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c>=2.0.0; sys_platform == "darwin"
/// │ └── satisfied by c-2.0.0
/// └── c
/// ├── c-1.0.0
/// └── c-2.0.0
/// ```
#[test]
fn fork_non_local_fork_marker_transitive() -> Result<()> {
let context = TestContext::new("3.8");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"fork-non-local-fork-marker-transitive-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-non-local-fork-marker-transitive-a==1.0.0''',
'''fork-non-local-fork-marker-transitive-b==1.0.0''',
]
"###,
)?;
let mut cmd = context.lock_without_exclude_newer();
cmd.arg("--index-url")
.arg("https://astral-sh.github.io/packse/0.3.18/simple-html/");
uv_snapshot!(filters, cmd, @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning.
warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`.
× No solution found when resolving dependencies:
╰─▶ Because package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}>=2.0.0 and only package-c{sys_platform == 'darwin'}<=2.0.0 is available, we can conclude that package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}==2.0.0.
And because only the following versions of package-c{sys_platform == 'linux'} are available:
package-c{sys_platform == 'linux'}==1.0.0
package-c{sys_platform == 'linux'}>=2.0.0
and package-a==1.0.0 depends on package-c{sys_platform == 'linux'}<2.0.0, we can conclude that package-a==1.0.0 and package-b==1.0.0 are incompatible.
And because project==0.1.0 depends on package-a==1.0.0 and package-b==1.0.0, we can conclude that project==0.1.0 cannot be used.
And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable.
"###
);
Ok(())
}