uv/crates/uv/tests/it/lock_scenarios.rs

5481 lines
216 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.53/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi"))]
#![allow(clippy::needless_raw_string_hashes)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::doc_lazy_continuation)]
use anyhow::Result;
use assert_cmd::assert::OutputAssertExt;
use assert_fs::prelude::*;
use insta::assert_snapshot;
use uv_static::EnvVars;
use crate::common::{TestContext, packse_index_url, uv_snapshot};
/// There are two packages, `a` and `b`. We select `a` with `a==2.0.0` first, and then `b`, but `a==2.0.0` conflicts with all new versions of `b`, so we backtrack through versions of `b`.
///
/// We need to detect this conflict and prioritize `b` over `a` instead of backtracking down to the too old version of `b==1.0.0` that doesn't depend on `a` anymore.
///
/// ```text
/// wrong-backtracking-basic
/// ├── 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
/// │ ├── satisfied by b-2.0.0
/// │ ├── satisfied by b-2.0.1
/// │ ├── satisfied by b-2.0.2
/// │ ├── satisfied by b-2.0.3
/// │ ├── satisfied by b-2.0.4
/// │ ├── satisfied by b-2.0.5
/// │ ├── satisfied by b-2.0.6
/// │ ├── satisfied by b-2.0.7
/// │ ├── satisfied by b-2.0.8
/// │ └── satisfied by b-2.0.9
/// ├── a
/// │ ├── a-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ │ └── 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
/// │ ├── b-2.0.1
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.2
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.3
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.4
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.5
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.6
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.7
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-2.0.8
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── b-2.0.9
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── too-old
/// └── too-old-1.0.0
/// ```
#[test]
fn wrong_backtracking_basic() -> 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-basic-", "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-basic-a''',
'''wrong-backtracking-basic-b''',
]
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 = 3
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" },
{ name = "package-b" },
]
[[package]]
name = "package-a"
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_basic_a-1.0.0.tar.gz", hash = "sha256:b4abd2c802ca129d5855225fe456f2a36068c50d0ae545e37a8e08ef0f580b38" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_basic_a-1.0.0-py3-none-any.whl", hash = "sha256:d669cb8614076ad7fc83f46b97abb94d86ada4ad5341d070874e96640ef808ad" },
]
[[package]]
name = "package-b"
version = "2.0.9"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-a" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_basic_b-2.0.9.tar.gz", hash = "sha256:aec746d9adae60458015ad7c11b1b9c589031928c07d9c13f1dff23d473b2480" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_basic_b-2.0.9-py3-none-any.whl", hash = "sha256:30c0b2450c13c06d70ccb8804e41d3be9dacc911e27f30ac58b7880d8fe8e705" },
]
"#
);
});
// 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(())
}
/// 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
/// │ └── a-2.0.0
/// ├── 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
/// ├── b-inner
/// │ ├── b-inner-1.0.0
/// │ │ └── 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
/// │ ├── b-inner-2.0.1
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.2
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.3
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.4
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.5
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.6
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.7
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ ├── b-inner-2.0.8
/// │ │ └── requires a==1.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── b-inner-2.0.9
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── too-old
/// └── too-old-1.0.0
/// ```
#[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.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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
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" },
{ name = "package-b" },
]
[[package]]
name = "package-a"
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_a-1.0.0.tar.gz", hash = "sha256:11281e0531d34bd2f8bc66a25d068b1e434f530fdce72e98b2d7f3a4eecc47a3" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_a-1.0.0-py3-none-any.whl", hash = "sha256:6987cda5abdec6eaf0ac6d7abb83284ac4294c57577644c9173bdc388e179151" },
]
[[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:2463de4ba18fe6b1f03b8458724a399c85c98a354a1861ea02e485757f096e3b" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b-1.0.0-py3-none-any.whl", hash = "sha256:cf4fc24449def13876f05f0c8cae59e4104ab9694b58ad6e92cc3fe25ecea6b3" },
]
[[package]]
name = "package-b-inner"
version = "2.0.9"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-a" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b_inner-2.0.9.tar.gz", hash = "sha256:37312bb0cef3b4a44fb53425c6027412ee70cd68674d16493b6b795077c816b1" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_indirect_b_inner-2.0.9-py3-none-any.whl", hash = "sha256:010e03bdcac3eeb0df2e6dc97351e9ee86f1df605180458646591b2d9ef7e9a3" },
]
"#
);
});
// 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.
///
/// At time of writing, this provokes a fork in the resolver, but it
/// arguably shouldn't since the requirements themselves do not conflict
/// with one another. However, this does impact resolution. Namely, it
/// leaves the `a>=1` fork free to choose `a==2.0.0` since it behaves as if
/// the `a<2` constraint doesn't exist.
///
/// ```text
/// fork-allows-non-conflicting-non-overlapping-dependencies
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=1; sys_platform == "linux"
/// │ │ ├── satisfied by a-1.0.0
/// │ │ └── 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_allows_non_conflicting_non_overlapping_dependencies() -> 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"fork-allows-non-conflicting-non-overlapping-dependencies-",
"package-",
));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-allows-non-conflicting-non-overlapping-dependencies-a>=1; sys_platform == "linux"''',
'''fork-allows-non-conflicting-non-overlapping-dependencies-a<2; sys_platform == "darwin"''',
]
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
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/fork_allows_non_conflicting_non_overlapping_dependencies_a-1.0.0.tar.gz", hash = "sha256:836b578e798d4aaba37ea42ebde338fd422d61d2bc4a93524b9c9cf77a7539d7" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_allows_non_conflicting_non_overlapping_dependencies_a-1.0.0-py3-none-any.whl", hash = "sha256:fce4343aac09c16fee45735fd638efc462aa97496c3e3332b6f8babdbd1e1e4d" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=1" },
]
"#
);
});
// 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 dependency
/// specifications with the same package name are allowed and supported.
///
/// This test exists because the universal resolver forks itself based on
/// duplicate dependency specifications by looking at package name. So at
/// first glance, a case like this could perhaps cause an errant fork.
/// While it's difficult to test for "does not create a fork" (at time of
/// writing, the implementation does not fork), we can at least check that
/// this case is handled correctly without issue. Namely, forking should
/// only occur when there are duplicate dependency specifications with
/// disjoint marker expressions.
///
/// ```text
/// fork-allows-non-conflicting-repeated-dependencies
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=1
/// │ │ ├── satisfied by a-1.0.0
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires a<2
/// │ └── satisfied by a-1.0.0
/// └── a
/// ├── a-1.0.0
/// └── a-2.0.0
/// ```
#[test]
fn fork_allows_non_conflicting_repeated_dependencies() -> 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"fork-allows-non-conflicting-repeated-dependencies-",
"package-",
));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-allows-non-conflicting-repeated-dependencies-a>=1''',
'''fork-allows-non-conflicting-repeated-dependencies-a<2''',
]
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "package-a"
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/fork_allows_non_conflicting_repeated_dependencies_a-1.0.0.tar.gz", hash = "sha256:4666c8498ab4aa641bacb39c2fb379ed87730d4de89bd7797c388a3c748f9f89" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_allows_non_conflicting_repeated_dependencies_a-1.0.0-py3-none-any.whl", hash = "sha256:77f0eb64e8c3bef8dec459d90c0394069eccb40d0c6c978d97bc1c4089d7d626" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", specifier = "<2" },
{ name = "package-a", specifier = ">=1" },
]
"#
);
});
// 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(())
}
/// 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.12
/// ├── 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.12");
// 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"''',
]
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 = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_basic_a-1.0.0.tar.gz", hash = "sha256:a81cba8fd1453d8fdf35ba4b3d8c536d2f9fa4e2ceb6312f497ec608a5262663" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_basic_a-1.0.0-py3-none-any.whl", hash = "sha256:900f299c08b6e0c1ec013259c13ff9279f5672fb395418fd00f937a3830a7edb" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_basic_a-2.0.0.tar.gz", hash = "sha256:3bbd7b86a9b7870ddcfdf343ed8555f414729053b171b3b072c1fef21478feb2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_basic_a-2.0.0-py3-none-any.whl", hash = "sha256:4fa08d0429882d46c4c5262630b174b44aa633fc9d0c3f6a90e17406d6d7eb5a" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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(())
}
/// We have a conflict after forking. This scenario exists to test the error message.
///
/// ```text
/// conflict-in-fork
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=2; sys_platform == "os1"
/// │ │ └── satisfied by a-2.0.0
/// │ └── 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
/// │ └── a-2.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires d==1
/// │ └── satisfied by d-1.0.0
/// ├── c
/// │ └── c-1.0.0
/// │ └── requires d==2
/// │ └── satisfied by d-2.0.0
/// └── d
/// ├── d-1.0.0
/// └── d-2.0.0
/// ```
#[test]
fn conflict_in_fork() -> 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"conflict-in-fork-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''conflict-in-fork-a>=2; sys_platform == "os1"''',
'''conflict-in-fork-a<2; sys_platform == "os2"''',
]
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: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies for split (markers: 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 == '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.
hint: The resolution failed for an environment that is not the current one, consider limiting the environments with `tool.uv.environments`.
"
);
Ok(())
}
/// This test ensures that conflicting dependency specifications lead to an
/// unsatisfiable result.
///
/// In particular, this is a case that should not fork even though there
/// are conflicting requirements because their marker expressions are
/// overlapping. (Well, there aren't any marker expressions here, which
/// means they are both unconditional.)
///
/// ```text
/// fork-conflict-unsatisfiable
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=2
/// │ │ ├── satisfied by a-2.0.0
/// │ │ └── satisfied by a-3.0.0
/// │ └── requires a<2
/// │ └── satisfied by a-1.0.0
/// └── a
/// ├── a-1.0.0
/// ├── a-2.0.0
/// └── a-3.0.0
/// ```
#[test]
fn fork_conflict_unsatisfiable() -> 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"fork-conflict-unsatisfiable-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-conflict-unsatisfiable-a>=2''',
'''fork-conflict-unsatisfiable-a<2''',
]
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: false
exit_code: 1
----- stdout -----
----- 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(())
}
/// This tests that sibling dependencies of a package that provokes a
/// fork are correctly filtered out of forks where they are otherwise
/// impossible.
///
/// In this case, a previous version of the universal resolver would
/// include both `b` and `c` in *both* of the forks produced by the
/// conflicting dependency specifications on `a`. This in turn led to
/// transitive dependency specifications on both `d==1.0.0` and `d==2.0.0`.
/// Since the universal resolver only forks based on local conditions, this
/// led to a failed resolution.
///
/// The correct thing to do here is to ensure that `b` is only part of the
/// `a==4.4.0` fork and `c` is only par of the `a==4.3.0` fork.
///
/// ```text
/// fork-filter-sibling-dependencies
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a==4.4.0; sys_platform == "linux"
/// │ │ └── satisfied by a-4.4.0
/// │ ├── requires a==4.3.0; sys_platform == "darwin"
/// │ │ └── satisfied by a-4.3.0
/// │ ├── requires b==1.0.0; sys_platform == "linux"
/// │ │ └── satisfied by b-1.0.0
/// │ └── requires c==1.0.0; sys_platform == "darwin"
/// │ └── satisfied by c-1.0.0
/// ├── a
/// │ ├── a-4.3.0
/// │ └── a-4.4.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires d==1.0.0
/// │ └── satisfied by d-1.0.0
/// ├── c
/// │ └── c-1.0.0
/// │ └── requires d==2.0.0
/// │ └── satisfied by d-2.0.0
/// └── d
/// ├── d-1.0.0
/// └── d-2.0.0
/// ```
#[test]
fn fork_filter_sibling_dependencies() -> 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"fork-filter-sibling-dependencies-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-filter-sibling-dependencies-a==4.4.0; sys_platform == "linux"''',
'''fork-filter-sibling-dependencies-a==4.3.0; sys_platform == "darwin"''',
'''fork-filter-sibling-dependencies-b==1.0.0; sys_platform == "linux"''',
'''fork-filter-sibling-dependencies-c==1.0.0; sys_platform == "darwin"''',
]
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 7 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'linux'",
"sys_platform == 'darwin'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "4.3.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_a-4.3.0.tar.gz", hash = "sha256:7bd9f28568add1b4f4ae3c75c527376d75cbb34a720b399c36422549fdb5a397" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_a-4.3.0-py3-none-any.whl", hash = "sha256:0cfa959f1188954c7426a84da27f310a7302c8814575ede013b6face9c71dd63" },
]
[[package]]
name = "package-a"
version = "4.4.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_a-4.4.0.tar.gz", hash = "sha256:3ff647ba5d00e7efd6f81922fdc037af1b3d924820304b1dce5aa3e2bb0ebc17" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_a-4.4.0-py3-none-any.whl", hash = "sha256:996fd9369bfc2cd4538d5ef8ead9858574a4c692528874160515570a83986d82" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-d", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_b-1.0.0.tar.gz", hash = "sha256:5cf545d94aae6b0be2476c2bfe9412bea2a01df9dec426235528214faedc3c30" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_b-1.0.0-py3-none-any.whl", hash = "sha256:1e1027c7f771947bfc45d7ba1c45056af51677360f924f206f89deff41c3adba" },
]
[[package]]
name = "package-c"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-d", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_c-1.0.0.tar.gz", hash = "sha256:d1fead7e86d6a81678fa69cb5de6724d0cbfc196bdd6771a6d2029bc0a6dbafe" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_c-1.0.0-py3-none-any.whl", hash = "sha256:add817457a9772f2f81c36517b9a674017332bc634fefe0402810d87230d0609" },
]
[[package]]
name = "package-d"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_d-1.0.0.tar.gz", hash = "sha256:5bafd1cfed4b7bb07af597f0817c3e3b2dd178ab26e9d00e3ec119440dbe7867" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_d-1.0.0-py3-none-any.whl", hash = "sha256:2c07fc89a83f28ee8b8bfb73d5fd3578555c60c3645b6502ff89ce4a4ee47ff3" },
]
[[package]]
name = "package-d"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_d-2.0.0.tar.gz", hash = "sha256:f6c80be71f98c3e0cd3d5a2a7d9be19a9651dd5657a29e5b0f4531d59a611a0b" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_filter_sibling_dependencies_d-2.0.0-py3-none-any.whl", hash = "sha256:b11cb3ef68f972b6b1ebf52d34310ea0e5962c7f618a3eb00db3ffc6c5c6d49f" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "4.3.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "4.4.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-b", marker = "sys_platform == 'linux'" },
{ name = "package-c", marker = "sys_platform == 'darwin'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "==4.3.0" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = "==4.4.0" },
{ name = "package-b", marker = "sys_platform == 'linux'", specifier = "==1.0.0" },
{ name = "package-c", marker = "sys_platform == 'darwin'", specifier = "==1.0.0" },
]
"#
);
});
// 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 checks that we discard fork markers when using `--upgrade`.
///
/// ```text
/// fork-upgrade
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires foo
/// │ ├── satisfied by foo-1.0.0
/// │ └── satisfied by foo-2.0.0
/// ├── bar
/// │ ├── bar-1.0.0
/// │ └── bar-2.0.0
/// └── 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
/// └── foo-2.0.0
/// └── requires bar==2
/// └── satisfied by bar-2.0.0
/// ```
#[test]
fn fork_upgrade() -> 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"fork-upgrade-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-upgrade-foo''',
]
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 = 3
requires-python = ">=3.12"
[[package]]
name = "package-bar"
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/fork_upgrade_bar-2.0.0.tar.gz", hash = "sha256:ad9667b61721151a0ace7cd482b0486eef8f0e41d1317c4051e4305d9e5b7eba" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_upgrade_bar-2.0.0-py3-none-any.whl", hash = "sha256:be280a030a3094647684fcbf8d7d9ada41274adb3414b56e299c8df29ded92d0" },
]
[[package]]
name = "package-foo"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-bar" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_upgrade_foo-2.0.0.tar.gz", hash = "sha256:4f26ade9a4954b1bc419e19f130d47ac9a8a8c7ad7f446085938f29cfb6a7f30" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_upgrade_foo-2.0.0-py3-none-any.whl", hash = "sha256:af4548f32eb03890ad85d538acae65797fd339e2fef3b52538d629cfb46f191e" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-foo" },
]
[package.metadata]
requires-dist = [{ name = "package-foo" }]
"#
);
});
// 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(())
}
/// The root cause the resolver to fork over `a`, but the markers on the variant
/// of `a` don't cover the entire marker space, they are missing Python 3.13.
/// Later, we have a dependency this very hole, which we still need to select,
/// instead of having two forks around but without Python 3.13 and omitting
/// `c` from the solution.
///
/// ```text
/// fork-incomplete-markers
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a==1; python_version < "3.13"
/// │ │ └── satisfied by a-1.0.0
/// │ ├── requires a==2; python_version >= "3.14"
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c; python_version == "3.13"
/// │ └── satisfied by c-1.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_incomplete_markers() -> 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"fork-incomplete-markers-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-incomplete-markers-a==1; python_version < "3.13"''',
'''fork-incomplete-markers-a==2; python_version >= "3.14"''',
'''fork-incomplete-markers-b''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"python_full_version >= '3.14'",
"python_full_version == '3.13.*'",
"python_full_version < '3.13'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"python_full_version < '3.13'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_a-1.0.0.tar.gz", hash = "sha256:47c0f25a9e21c68f14173c556ebc43656d4e3fa75a2802ff5cd8df98deaf965d" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_a-1.0.0-py3-none-any.whl", hash = "sha256:3cdba0dffc4e4fc3b01fbf5b8529b9f85d9811917984cd587d717ae84d853893" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"python_full_version >= '3.14'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_a-2.0.0.tar.gz", hash = "sha256:e32ea9a40f05ad71fc666a4f3441020d9c50023b75b75c5d865a89437885831f" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_a-2.0.0-py3-none-any.whl", hash = "sha256:4b2a4ca84cae18d8c49ad87ec457a60a8fbe1d1160c61d2aeb473cf8c2b8d9e3" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "python_full_version == '3.13.*'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_b-1.0.0.tar.gz", hash = "sha256:99a13ea3286cafd8bdd4054fe0a966950574817d1973e30bcc230502b98f0be7" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_b-1.0.0-py3-none-any.whl", hash = "sha256:f429325c6d7cef0721bca12825f9f38ca781cd633ab305526ce9e2af6d43d68e" },
]
[[package]]
name = "package-c"
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/fork_incomplete_markers_c-1.0.0.tar.gz", hash = "sha256:e1a20988cf66fda67faf7009b002e807d457c38f32a7802772481c00bb734fb8" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_incomplete_markers_c-1.0.0-py3-none-any.whl", hash = "sha256:9d5e2b822bdae8076d9f5a5fa71307eff4d82e7ce9208dc247b1868cf3afe31a" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "python_full_version < '3.13'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "python_full_version >= '3.14'" },
{ name = "package-b" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "python_full_version < '3.13'", specifier = "==1" },
{ name = "package-a", marker = "python_full_version >= '3.14'", specifier = "==2" },
{ name = "package-b" },
]
"#
);
});
// 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 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.12
/// ├── 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.12");
// 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"''',
]
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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_accrue_a-1.0.0.tar.gz", hash = "sha256:275ed50999adcfd2bbdf2ce621b7a4f850b3b314bc9e9f490d8e414cff19134d" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_accrue_a-1.0.0-py3-none-any.whl", hash = "sha256:7d83ea2071fee0d995d31ff7c7ff4db7e4ded2d7e5faa8143fce0296cf9a7a11" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_accrue_b-1.0.0.tar.gz", hash = "sha256:1944e0bfb15477a4dcace6a94fdb885a5e699c7c11c2ec81ee5f999a965d98ab" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_accrue_b-1.0.0-py3-none-any.whl", hash = "sha256:775f67358cd784b5d0a5880bc013beb34efbace88d0329fabfeb5093b7e7bbfa" },
]
[[package]]
name = "package-c"
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/fork_marker_accrue_c-1.0.0.tar.gz", hash = "sha256:0d915ef7a76eed8e00c350dbe83fcff7aec77dba739e5a671cbfba69abca4d94" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_accrue_c-1.0.0-py3-none-any.whl", hash = "sha256:4a6d7a72793d13a666302e6dd2b9ac684c202f53c854c5eef55700067924a23b" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", marker = "implementation_name == 'cpython'" },
{ name = "package-b", marker = "implementation_name == 'pypy'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "implementation_name == 'cpython'", specifier = "==1.0.0" },
{ name = "package-b", marker = "implementation_name == 'pypy'", specifier = "==1.0.0" },
]
"#
);
});
// 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(())
}
/// 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.12
/// ├── 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.12");
// 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"''',
]
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: false
exit_code: 1
----- stdout -----
----- 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(())
}
/// This test builds on `fork-marker-inherit-combined`. Namely, we add
/// `or implementation_name == 'pypy'` to the dependency on `c`. While
/// `sys_platform == 'linux'` cannot be true because of the first fork,
/// the second fork which includes `b==1.0.0` happens precisely when
/// `implementation_name == 'pypy'`. So in this case, `c` should be
/// included.
///
/// ```text
/// fork-marker-inherit-combined-allowed
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ ├── requires b>=2; implementation_name == "cpython"
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ └── requires b<2; implementation_name == "pypy"
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ │ └── requires c; sys_platform == "linux" or implementation_name == "pypy"
/// │ │ └── satisfied by c-1.0.0
/// │ └── b-2.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_marker_inherit_combined_allowed() -> 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"fork-marker-inherit-combined-allowed-", "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-inherit-combined-allowed-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-combined-allowed-a<2; sys_platform == "darwin"''',
]
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 6 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
]
dependencies = [
{ name = "package-b", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'pypy' and sys_platform == 'darwin'" },
{ name = "package-b", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'cpython' and sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_a-1.0.0.tar.gz", hash = "sha256:d6593d7102007515a301ed790fecf1b6366d8fe6c3bbc24a31497f91c44eaac6" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_a-1.0.0-py3-none-any.whl", hash = "sha256:887cde670bb39a789806e7d1a1b562d084ab163b3a3d08e20ec706b0d4453029" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_a-2.0.0.tar.gz", hash = "sha256:d822588720e6f9627a002d7c2cf97a4a8d74e530265b0b288aef2b957327e4e9" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_a-2.0.0-py3-none-any.whl", hash = "sha256:88f87116434130aacff501c430f5413a8d3c2e38f18cd89d0504b37716ecc786" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
]
dependencies = [
{ name = "package-c", marker = "implementation_name == 'pypy' and sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_b-1.0.0.tar.gz", hash = "sha256:a1f33681f42aa5b47c7d05b93f013f8b9555b2ec2df49a42589dc06cab391797" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_b-1.0.0-py3-none-any.whl", hash = "sha256:da22041f6a3ec9d3a9e72fc4a3c7a9bb1b336b25bc48b5e15657866a12d34657" },
]
[[package]]
name = "package-b"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'cpython' and sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_b-2.0.0.tar.gz", hash = "sha256:0509fdaeb0ad18de20daabb084aa27c198db538636d8b1c1fdfe65ed0943f7d2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_b-2.0.0-py3-none-any.whl", hash = "sha256:030efe965f6e36cf4a01e3fd133ac427cee33da4d2b4703c3af560005efca454" },
]
[[package]]
name = "package-c"
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/fork_marker_inherit_combined_allowed_c-1.0.0.tar.gz", hash = "sha256:4a69f0cdfcd06caa73c2e16f11adfc3eeeac3c44210beb3aaf1dad4436351ceb" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_allowed_c-1.0.0-py3-none-any.whl", hash = "sha256:d936683675b39b426aad63f3047792f0c2609b6a459ab17d2d0b86d592be4c6e" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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 builds on `fork-marker-inherit-combined`. Namely, we add
/// `or implementation_name == 'cpython'` to the dependency on `c`.
/// While `sys_platform == 'linux'` cannot be true because of the first
/// fork, the second fork which includes `b==1.0.0` happens precisely
/// when `implementation_name == 'pypy'`, which is *also* disjoint with
/// `implementation_name == 'cpython'`. Therefore, `c` should not be
/// included here.
///
/// ```text
/// fork-marker-inherit-combined-disallowed
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ ├── requires b>=2; implementation_name == "cpython"
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ └── requires b<2; implementation_name == "pypy"
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ │ └── requires c; sys_platform == "linux" or implementation_name == "cpython"
/// │ │ └── satisfied by c-1.0.0
/// │ └── b-2.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_marker_inherit_combined_disallowed() -> 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"fork-marker-inherit-combined-disallowed-", "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-inherit-combined-disallowed-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-combined-disallowed-a<2; sys_platform == "darwin"''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
]
dependencies = [
{ name = "package-b", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'pypy' and sys_platform == 'darwin'" },
{ name = "package-b", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'cpython' and sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_a-1.0.0.tar.gz", hash = "sha256:c5f27540b38e11066006d693119bf351ce8eda80c6ad2b283c7db1b39ec1acbf" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_a-1.0.0-py3-none-any.whl", hash = "sha256:7607e3377c7c4f0cb0e968bfe4e3ed1d3b8b19fceb42a48143e5ed138dca1346" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_a-2.0.0.tar.gz", hash = "sha256:1a98bb0369a890195060689cbad646c9c5aec9f2ead3b2340fc52cfbb252ead5" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_a-2.0.0-py3-none-any.whl", hash = "sha256:f8db9a220f480a2655cc54efe47c603037a91935c95d3da48bc408810b3bc41e" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_b-1.0.0.tar.gz", hash = "sha256:15005f7c07b199cb2d526cc45776bef8327a0d6e7a9cc773a318da76abafc046" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_b-1.0.0-py3-none-any.whl", hash = "sha256:1ea9b95b6aa8ae09ff6711bc175c854d4caf4c3ad9ab69b1da3d6cec4a6cb7ed" },
]
[[package]]
name = "package-b"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'cpython' and sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_b-2.0.0.tar.gz", hash = "sha256:5ed91f43bd7013a8d4d1593a5aadc5a9e0d8629d5ee16f1357f89d24f20be2b9" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_disallowed_b-2.0.0-py3-none-any.whl", hash = "sha256:d4f998f9d1a9f8714347565237d2f1502d9699942c3cdd86cdb4ea7c5c7e5796" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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(())
}
/// In this test, we check that marker expressions which provoke a fork
/// are carried through to subsequent forks. Here, the `a>=2` and `a<2`
/// dependency specifications create a fork, and then the `a<2` fork leads
/// to `a==1.0.0` with dependency specifications on `b>=2` and `b<2` that
/// provoke yet another fork. Finally, in the `b<2` fork, a dependency on
/// `c` is introduced whose marker expression is disjoint with the marker
/// expression that provoked the *first* fork. Therefore, `c` should be
/// entirely excluded from the resolution.
///
/// ```text
/// fork-marker-inherit-combined
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ ├── requires b>=2; implementation_name == "cpython"
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ └── requires b<2; implementation_name == "pypy"
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ │ └── requires c; sys_platform == "linux"
/// │ │ └── satisfied by c-1.0.0
/// │ └── b-2.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_marker_inherit_combined() -> 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"fork-marker-inherit-combined-", "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-inherit-combined-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-combined-a<2; sys_platform == "darwin"''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
"implementation_name == 'cpython' and sys_platform == 'darwin'",
"implementation_name != 'cpython' and implementation_name != 'pypy' and sys_platform == 'darwin'",
]
dependencies = [
{ name = "package-b", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'pypy' and sys_platform == 'darwin'" },
{ name = "package-b", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "implementation_name == 'cpython' and sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_a-1.0.0.tar.gz", hash = "sha256:7abc9661d5e25b05f7dd170fcda8f4abe0f6005768efd5f48b20be876e532954" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_a-1.0.0-py3-none-any.whl", hash = "sha256:d904b3e7317e89d18a9497d93cbf322b101ec1a08aeb3ef911666382e91b12d7" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_a-2.0.0.tar.gz", hash = "sha256:413d4b8f065d7c36eb99760218d2a755242b2682d3976a7adfcc1dd2e2414e44" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_a-2.0.0-py3-none-any.whl", hash = "sha256:21d5b138fbb524ce43f65b2d0a9791e73e64ceb3d88f4be42f2a07bd41520412" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'pypy' and sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_b-1.0.0.tar.gz", hash = "sha256:1a52000f85375ddf93f7094d36d4c613af75b4cfc0638edb5be8ad4f984a74b2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_b-1.0.0-py3-none-any.whl", hash = "sha256:62bc162290737672b8d017ad0c067298b7ad0ef9ada95ae37c35d0f9a738d8a4" },
]
[[package]]
name = "package-b"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"implementation_name == 'cpython' and sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_b-2.0.0.tar.gz", hash = "sha256:bdeb3b79dc439acb4f5a76c8afd7fb5f5a1e80d89030ba1e0fd3514455505271" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_combined_b-2.0.0-py3-none-any.whl", hash = "sha256:cf0d309bcf6092017ecf29fec37f1d0cc80fe59fee3f0488c52e944a913a3a8b" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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 is like `fork-marker-inherit`, but where both `a>=2` and `a<2`
/// have a conditional dependency on `b`. For `a>=2`, the conditional
/// dependency on `b` has overlap with the `a>=2` marker expression, and
/// thus, `b` should be included *only* in the dependencies for `a==2.0.0`.
/// As with `fork-marker-inherit`, the `a<2` path should exclude `b==1.0.0`
/// since their marker expressions are disjoint.
///
/// ```text
/// fork-marker-inherit-isolated
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ └── requires b; sys_platform == "linux"
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// │ └── requires b; sys_platform == "linux"
/// │ └── satisfied by b-1.0.0
/// └── b
/// └── b-1.0.0
/// ```
#[test]
fn fork_marker_inherit_isolated() -> 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"fork-marker-inherit-isolated-", "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-inherit-isolated-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-isolated-a<2; sys_platform == "darwin"''',
]
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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_isolated_a-1.0.0.tar.gz", hash = "sha256:026f954ea486398d169b3bffbcc3619f261de760e30665db52dd4347c4c2051d" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_isolated_a-1.0.0-py3-none-any.whl", hash = "sha256:df72f591a1280e23989ae5b027b2c08b39b1a059458287cd5e3ac1c5f331119d" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
dependencies = [
{ name = "package-b", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_isolated_a-2.0.0.tar.gz", hash = "sha256:048dfffa5cc67b19eb5b4db562119293e1dd49e8c93395d242677216efbb2408" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_isolated_a-2.0.0-py3-none-any.whl", hash = "sha256:57a7c3e75553c34b1e269efb0c462f83eba34160f2c089b5ddab663eb2a95485" },
]
[[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/fork_marker_inherit_isolated_b-1.0.0.tar.gz", hash = "sha256:7e7b0a264412f2f9563e0b0b9a003f0b22fe47d202f804f07e48c0fea29802e4" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_isolated_b-1.0.0-py3-none-any.whl", hash = "sha256:c8ff985d36ad17a8f0dd4b36805d02369cb4f9bdc64d794cfd42cbb1ffd98740" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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 is like `fork-marker-inherit`, but tests that the marker
/// expressions that provoke a fork are carried transitively through the
/// dependency graph. In this case, `a<2 -> b -> c -> d`, but where the
/// last dependency on `d` requires a marker expression that is disjoint
/// with the initial `a<2` dependency. Therefore, it ought to be completely
/// excluded from the resolution.
///
/// ```text
/// fork-marker-inherit-transitive
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ └── requires b
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c
/// │ └── satisfied by c-1.0.0
/// ├── c
/// │ └── c-1.0.0
/// │ └── requires d; sys_platform == "linux"
/// │ └── satisfied by d-1.0.0
/// └── d
/// └── d-1.0.0
/// ```
#[test]
fn fork_marker_inherit_transitive() -> 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"fork-marker-inherit-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-marker-inherit-transitive-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-transitive-a<2; sys_platform == "darwin"''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
dependencies = [
{ name = "package-b", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_a-1.0.0.tar.gz", hash = "sha256:a6f10f68c6f39595be9e35bcb5bc47c8dff406417da2f949180c9acca5885d32" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_a-1.0.0-py3-none-any.whl", hash = "sha256:fc324cbddab19f021387526d0bfc0b63ba8d2994516a5f9cafabb97e93100c70" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_a-2.0.0.tar.gz", hash = "sha256:50c12e6503e560beabfc9c6ffd594998d34a34ec27fc395115c239f52d61e582" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_a-2.0.0-py3-none-any.whl", hash = "sha256:26a501017aced48531ec9ed5148f95ab7322c5ceef9bdbf25bba6d950621e474" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_b-1.0.0.tar.gz", hash = "sha256:0a26e85593cef47acec83439527e58890ed1afb419b73bf6ccc344df4e1c2072" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_b-1.0.0-py3-none-any.whl", hash = "sha256:bc91cd833ffbc3f3dce3d74a5776a440907e8894ea8b2e106699374531f8dfc4" },
]
[[package]]
name = "package-c"
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/fork_marker_inherit_transitive_c-1.0.0.tar.gz", hash = "sha256:4ad54ca5a23cdb1810d467603551ff254a3652b55f54f17ab991ab7205ad427e" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_transitive_c-1.0.0-py3-none-any.whl", hash = "sha256:4cd03a954fb6353f68a76930b79d9ec9aae9bf80ebe23b539434170b4d7819d9" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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 tests that markers which provoked a fork in the universal resolver
/// are used to ignore dependencies which cannot possibly be installed by a
/// resolution produced by that fork.
///
/// In this example, the `a<2` dependency is only active on Darwin
/// platforms. But the `a==1.0.0` distribution has a dependency on `b`
/// that is only active on Linux, where as `a==2.0.0` does not. Therefore,
/// when the fork provoked by the `a<2` dependency considers `b`, it should
/// ignore it because it isn't possible for `sys_platform == 'linux'` and
/// `sys_platform == 'darwin'` to be simultaneously true.
///
/// ```text
/// fork-marker-inherit
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ │ └── requires b; sys_platform == "linux"
/// │ │ └── satisfied by b-1.0.0
/// │ └── a-2.0.0
/// └── b
/// └── b-1.0.0
/// ```
#[test]
fn fork_marker_inherit() -> 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"fork-marker-inherit-", "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-inherit-a>=2; sys_platform == "linux"''',
'''fork-marker-inherit-a<2; sys_platform == "darwin"''',
]
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 = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_a-1.0.0.tar.gz", hash = "sha256:6f045f31d58183fe437f35b34462e5ec9bf0bcee541f423999426aad7ccfe1b3" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_a-1.0.0-py3-none-any.whl", hash = "sha256:63bfd654bcd092e74a8ccae0f496e3b1062a5e9e2d98741f1548f337582c849b" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_a-2.0.0.tar.gz", hash = "sha256:3222e12bb0136902b05479736e8731146ab3a01ebf0f666a6fe8c812e1181e33" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_inherit_a-2.0.0-py3-none-any.whl", hash = "sha256:72e2161338e159f2d6bed4cb519bc2ebf94e9daf2cbe5e0ac26d5fbe537f38af" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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 is like `fork-marker-inherit`, but it tests that dependency
/// filtering only occurs in the context of a fork.
///
/// For example, as in `fork-marker-inherit`, the `c` dependency of
/// `a<2` should be entirely excluded here since it is possible for
/// `sys_platform` to be simultaneously equivalent to Darwin and Linux.
/// However, the unconditional dependency on `b`, which in turn depends on
/// `c` for Linux only, should still incorporate `c` as the dependency is
/// not part of any fork.
///
/// ```text
/// fork-marker-limited-inherit
/// ├── environment
/// │ └── python3.12
/// ├── 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
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ │ └── requires c; sys_platform == "linux"
/// │ │ └── satisfied by c-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires c; sys_platform == "linux"
/// │ └── satisfied by c-1.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn fork_marker_limited_inherit() -> 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"fork-marker-limited-inherit-", "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-limited-inherit-a>=2; sys_platform == "linux"''',
'''fork-marker-limited-inherit-a<2; sys_platform == "darwin"''',
'''fork-marker-limited-inherit-b''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_a-1.0.0.tar.gz", hash = "sha256:7bb040222692677419ec7074324c46ae68148a4c4feb95f73fab51f88605f4c3" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_a-1.0.0-py3-none-any.whl", hash = "sha256:2d1c0ba50a12a630bab2870cffc57f27075cd1b6146208ec6ecbd128dc1c697e" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_a-2.0.0.tar.gz", hash = "sha256:23cb8783034c2c8fb7d9ce4f404241946dddde2c9e845d2ab19ee161d83d4dcb" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_a-2.0.0-py3-none-any.whl", hash = "sha256:a15b853867a573c4c3ba8798c7cddac85c19c6f029a1926aa80f37519bb6ce7c" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_b-1.0.0.tar.gz", hash = "sha256:401047757cda70f63f0fd187361d225f34ebae0ed9dfc6c732c54005c58206f4" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_b-1.0.0-py3-none-any.whl", hash = "sha256:6533104ddd85f6e10b501e76dd9b324eef8852edd412bfc29aad83a82a2310c3" },
]
[[package]]
name = "package-c"
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/fork_marker_limited_inherit_c-1.0.0.tar.gz", hash = "sha256:3e8b40d054a5cf6d2f68be7750bd83cd305063f99025717df5def825f6236896" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_limited_inherit_c-1.0.0-py3-none-any.whl", hash = "sha256:17d86b6d2a25639cb06591901bb06353622b5c728e71562fd4c20c7a404fa5f6" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-b" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" },
{ name = "package-b" },
]
"#
);
});
// 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 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.12
/// ├── 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.12");
// 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"''',
]
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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "0.1.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_a-0.1.0.tar.gz", hash = "sha256:f8a3a4de6e08270cbf03e8d1e9d860dd56e57cc57529b8f622a3e6029b68d4e0" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_a-0.1.0-py3-none-any.whl", hash = "sha256:6c1efed1a7f00b594202e9a811a0c2fc80cb54e62073c8d92d39c82fc745ba48" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_b-1.0.0.tar.gz", hash = "sha256:13419956d96ad6b90ba779235ba6900fe084fbae8dcb288ca6749af98e537b58" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_b-1.0.0-py3-none-any.whl", hash = "sha256:932c364daf4c721d3f592d8371b4d6408cf919c3560f114cba60a82fc566b397" },
]
[[package]]
name = "package-b"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_b-2.0.0.tar.gz", hash = "sha256:2b1c59091de521af15778ccb7aa6a3718dd89730b215adb2a9094652e7f34133" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_selection_b-2.0.0-py3-none-any.whl", hash = "sha256:1d22dd5dc6026d5794bff9e6236968c8ffdfc7a6173926abdfd43b0591d947eb" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
{ name = "package-b", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-b", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a" },
{ name = "package-b", marker = "sys_platform == 'darwin'", specifier = "<2" },
{ name = "package-b", marker = "sys_platform == 'linux'", specifier = ">=2" },
]
"#
);
});
// 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(())
}
///
///
/// ```text
/// fork-marker-track
/// ├── environment
/// │ └── python3.12
/// ├── 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.12");
// 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"''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'darwin'",
"sys_platform == 'linux'",
"sys_platform != 'darwin' and sys_platform != 'linux'",
]
[[package]]
name = "package-a"
version = "1.3.1"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "implementation_name == 'iron'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_a-1.3.1.tar.gz", hash = "sha256:6386d3023910b48db03db9fb28d75fcb8fa5a72a2ddc39de3fb6e8f15e9e1f8b" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_a-1.3.1-py3-none-any.whl", hash = "sha256:369b83e46c9331551548ed3e3a8643aa2b821f72478a4a30c88e88937d5c5e47" },
]
[[package]]
name = "package-b"
version = "2.7"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'darwin'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_b-2.7.tar.gz", hash = "sha256:8bd81fc189a302ec091eb05dac4f70510daf13fd82e10d8e0443c2d1d232748b" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_b-2.7-py3-none-any.whl", hash = "sha256:dd05dff9c80b7a425882b0809238784d44f021fd8b43f23c5d8ee24e1232532f" },
]
[[package]]
name = "package-b"
version = "2.8"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_b-2.8.tar.gz", hash = "sha256:4908ff48ea9ff17deaa3e56fb78938fa14c2fef9cd7f20ece4e8424d6b0785b3" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_b-2.8-py3-none-any.whl", hash = "sha256:c9e3f25dd64091d3169a2ac13a22b2687eaebc482381a0d05dfbab74464ad395" },
]
[[package]]
name = "package-c"
version = "1.10"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_c-1.10.tar.gz", hash = "sha256:24ac6f9d025c0e4750c7a215150b51397df744f674fb372a23d8ffe6b243a040" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_marker_track_c-1.10-py3-none-any.whl", hash = "sha256:4e7104c302c1b05a2b1eae4abf4e27ba81866ec5af416e54562985e9495a22ad" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
{ name = "package-b", version = "2.7", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'darwin'" },
{ name = "package-b", version = "2.8", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a" },
{ name = "package-b", marker = "sys_platform == 'darwin'", specifier = "<2.8" },
{ name = "package-b", marker = "sys_platform == 'linux'", specifier = ">=2.8" },
]
"#
);
});
// 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 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.12
/// ├── 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.12");
// 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''',
]
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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_non_fork_marker_transitive_a-1.0.0.tar.gz", hash = "sha256:013eeda4d82bc86fad1a9f0b12e7dca4dda21f1588fdba1ac3345b2fa139c8c2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_non_fork_marker_transitive_a-1.0.0-py3-none-any.whl", hash = "sha256:6150d8b54b7119a143b976472eac7c380cb130dd384ac02cffd7e6ce0cf82942" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", marker = "sys_platform == 'darwin'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_non_fork_marker_transitive_b-1.0.0.tar.gz", hash = "sha256:8257a5deb16f69d60e917f8817093640675bee4ab354a088b81b3e5969832e0c" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_non_fork_marker_transitive_b-1.0.0-py3-none-any.whl", hash = "sha256:e38a84fa43b292c50cf762656d4b2f4e57dea7fddf7be073146fb0870e7c0190" },
]
[[package]]
name = "package-c"
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/fork_non_fork_marker_transitive_c-2.0.0.tar.gz", hash = "sha256:44f2bc2e48b3b88bc4c4b64b7ef7df191c55a6fe0ea402d02dfc8132cec37c1f" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_non_fork_marker_transitive_c-2.0.0-py3-none-any.whl", hash = "sha256:9afd9106b0434c27efd84358f5a5a125950bac3a808535b4b2fa1b78ecbb766f" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
{ name = "package-b" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", specifier = "==1.0.0" },
{ name = "package-b", specifier = "==1.0.0" },
]
"#
);
});
// 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 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.12
/// ├── 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.12");
// 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"''',
]
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: false
exit_code: 1
----- stdout -----
----- stderr -----
× 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-b==1.0.0 and package-a{sys_platform == 'linux'}==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(())
}
/// 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.12
/// ├── 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.12");
// 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''',
]
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: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because package-a==1.0.0 depends on package-c{sys_platform == 'linux'}<2.0.0 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(())
}
/// This scenario tests a very basic case of overlapping markers. Namely,
/// it emulates a common pattern in the ecosystem where marker expressions
/// are used to progressively increase the version constraints of a package
/// as the Python version increases.
///
/// In this case, there is actually a split occurring between
/// `python_version < '3.13'` and the other marker expressions, so this
/// isn't just a scenario with overlapping but non-disjoint markers.
///
/// In particular, this serves as a regression test. uv used to create a
/// lock file with a dependency on `a` with the following markers:
///
/// python_version < '3.13' or python_version >= '3.14'
///
/// But this implies that `a` won't be installed for Python 3.13, which is
/// clearly wrong.
///
/// The issue was that uv was intersecting *all* marker expressions. So
/// that `a>=1.1.0` and `a>=1.2.0` fork was getting `python_version >=
/// '3.13' and python_version >= '3.14'`, which, of course, simplifies
/// to `python_version >= '3.14'`. But this is wrong! It should be
/// `python_version >= '3.13' or python_version >= '3.14'`, which of course
/// simplifies to `python_version >= '3.13'`. And thus, the resulting forks
/// are not just disjoint but complete in this case.
///
/// Since there are no other constraints on `a`, this causes uv to select
/// `1.2.0` unconditionally. (The marker expressions get normalized out
/// entirely.)
///
/// ```text
/// fork-overlapping-markers-basic
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=1.0.0; python_version < "3.13"
/// │ │ ├── satisfied by a-1.0.0
/// │ │ ├── satisfied by a-1.1.0
/// │ │ └── satisfied by a-1.2.0
/// │ ├── requires a>=1.1.0; python_version >= "3.13"
/// │ │ ├── satisfied by a-1.1.0
/// │ │ └── satisfied by a-1.2.0
/// │ └── requires a>=1.2.0; python_version >= "3.14"
/// │ └── satisfied by a-1.2.0
/// └── a
/// ├── a-1.0.0
/// ├── a-1.1.0
/// └── a-1.2.0
/// ```
#[test]
fn fork_overlapping_markers_basic() -> 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"fork-overlapping-markers-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-overlapping-markers-basic-a>=1.0.0; python_version < "3.13"''',
'''fork-overlapping-markers-basic-a>=1.1.0; python_version >= "3.13"''',
'''fork-overlapping-markers-basic-a>=1.2.0; python_version >= "3.14"''',
]
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"python_full_version >= '3.14'",
"python_full_version == '3.13.*'",
"python_full_version < '3.13'",
]
[[package]]
name = "package-a"
version = "1.2.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_overlapping_markers_basic_a-1.2.0.tar.gz", hash = "sha256:bc36ec5060fa24617aa2b40a77b62e9a80737aeec255fa3e005933cdfd81ad98" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_overlapping_markers_basic_a-1.2.0-py3-none-any.whl", hash = "sha256:3afae4a2c2a114de372c165e5b874dbb52bc41aa7ebee2b519820e89c8ccbeec" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "python_full_version < '3.13'", specifier = ">=1.0.0" },
{ name = "package-a", marker = "python_full_version >= '3.13'", specifier = ">=1.1.0" },
{ name = "package-a", marker = "python_full_version >= '3.14'", specifier = ">=1.2.0" },
]
"#
);
});
// 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 contains a bistable resolution scenario when not using ahead-of-time
/// splitting of resolution forks: We meet one of two fork points depending on the
/// preferences, creating a resolution whose preferences lead us the other fork
/// point.
///
/// In the first case, we are in cleaver 2 and fork on `sys_platform`, in the
/// second case, we are in foo 1 or bar 1 amd fork over `os_name`.
///
/// First case: We select cleaver 2, fork on `sys_platform`, we reject cleaver 2
/// (missing fork `os_name`), we select cleaver 1 and don't fork on `os_name` in
/// `fork-if-not-forked`, done.
/// Second case: We have preference cleaver 1, fork on `os_name` in
/// `fork-if-not-forked`, we reject cleaver 1, we select cleaver 2, we fork on
/// `sys_platform`, we accept cleaver 2 since we forked on `os_name`, done.
///
/// ```text
/// preferences-dependent-forking-bistable
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires cleaver
/// │ ├── satisfied by cleaver-2.0.0
/// │ └── satisfied by cleaver-1.0.0
/// ├── cleaver
/// │ ├── cleaver-2.0.0
/// │ │ ├── requires fork-sys-platform==1; sys_platform == "linux"
/// │ │ │ └── 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 reject-cleaver2==1; os_name == "posix"
/// │ │ │ └── satisfied by reject-cleaver2-1.0.0
/// │ │ └── requires reject-cleaver2-proxy
/// │ │ └── satisfied by reject-cleaver2-proxy-1.0.0
/// │ └── cleaver-1.0.0
/// │ ├── requires fork-if-not-forked!=2; sys_platform == "linux"
/// │ │ ├── satisfied by fork-if-not-forked-1.0.0
/// │ │ └── 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 reject-cleaver1==1; sys_platform == "linux"
/// │ │ └── satisfied by reject-cleaver1-1.0.0
/// │ └── requires reject-cleaver1-proxy
/// │ └── satisfied by reject-cleaver1-proxy-1.0.0
/// ├── fork-if-not-forked
/// │ ├── fork-if-not-forked-1.0.0
/// │ │ ├── requires fork-os-name==1; os_name == "posix"
/// │ │ │ └── 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 reject-cleaver1-proxy
/// │ │ └── satisfied by reject-cleaver1-proxy-1.0.0
/// │ ├── fork-if-not-forked-2.0.0
/// │ └── fork-if-not-forked-3.0.0
/// ├── 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
/// ├── fork-os-name
/// │ ├── fork-os-name-1.0.0
/// │ └── fork-os-name-2.0.0
/// ├── fork-sys-platform
/// │ ├── fork-sys-platform-1.0.0
/// │ └── fork-sys-platform-2.0.0
/// ├── reject-cleaver1
/// │ ├── reject-cleaver1-1.0.0
/// │ └── reject-cleaver1-2.0.0
/// ├── reject-cleaver1-proxy
/// │ └── reject-cleaver1-proxy-1.0.0
/// │ └── requires reject-cleaver1==2; sys_platform != "linux"
/// │ └── satisfied by reject-cleaver1-2.0.0
/// ├── reject-cleaver2
/// │ ├── reject-cleaver2-1.0.0
/// │ └── reject-cleaver2-2.0.0
/// └── reject-cleaver2-proxy
/// └── reject-cleaver2-proxy-1.0.0
/// └── 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.12");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"preferences-dependent-forking-bistable-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''preferences-dependent-forking-bistable-cleaver''',
]
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 8 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'linux'",
"sys_platform != 'linux'",
]
[[package]]
name = "package-cleaver"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-fork-if-not-forked", version = "3.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-fork-if-not-forked-proxy", marker = "sys_platform != 'linux'" },
{ name = "package-reject-cleaver1", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-reject-cleaver1-proxy" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_cleaver-1.0.0.tar.gz", hash = "sha256:d2279d73d7ffff655e269c3bcea9674895dd55631d542ed12fab64a4bbd9fc29" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_cleaver-1.0.0-py3-none-any.whl", hash = "sha256:6ab14dc6b3a9658f2a222b752773beaf43ac5379fba0a88bb3012282936328b0" },
]
[[package]]
name = "package-fork-if-not-forked"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked-2.0.0.tar.gz", hash = "sha256:a79abb4beae739e1413afe652bcda59e3807253e46907729dab211954be06a2c" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked-2.0.0-py3-none-any.whl", hash = "sha256:1c580daeffeba5529c44ae1afb90b858ea7c696157c1c72ba59de0f32f61dd26" },
]
[[package]]
name = "package-fork-if-not-forked"
version = "3.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked-3.0.0.tar.gz", hash = "sha256:4d45258ebd32cd819906e69f2e2b890044d6e99b24b8e82ebc88aba6fe607b1a" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked-3.0.0-py3-none-any.whl", hash = "sha256:b246c161c65bcf1387dbbf5458bb4841076818c2838babd1d5d274b436eda26e" },
]
[[package]]
name = "package-fork-if-not-forked-proxy"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-fork-if-not-forked", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked_proxy-1.0.0.tar.gz", hash = "sha256:80e40c848eed5472237156444ccaf72ddb0176cd095f2b69469fce203981a14e" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_fork_if_not_forked_proxy-1.0.0-py3-none-any.whl", hash = "sha256:38cf97a4a1a1bd748744ec3859023c9e1173171525cdec8f8a48e8e5adf4422c" },
]
[[package]]
name = "package-reject-cleaver1"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1-1.0.0.tar.gz", hash = "sha256:42426a00cb3e8c7994faf906ebcf102e0cbf7e68eabd8ada77562489ae185a3d" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1-1.0.0-py3-none-any.whl", hash = "sha256:7468472d90e0004b177841ffbc5997fca3fa3f593607a8c90ffb013aa7681768" },
]
[[package]]
name = "package-reject-cleaver1"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1-2.0.0.tar.gz", hash = "sha256:1f7c625af40a3dcd86ca2765f496a3423cd0ee5162bf136bf7b73d956ae6715f" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1-2.0.0-py3-none-any.whl", hash = "sha256:695334dd35d3cb9045e111a4fda566d982558fef7a74026138941d869b97c014" },
]
[[package]]
name = "package-reject-cleaver1-proxy"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-reject-cleaver1", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1_proxy-1.0.0.tar.gz", hash = "sha256:cbdc4afe283a0b8c556015b20fa5818c9be23f769cfea0b1f3c8ce138af064f9" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bistable_reject_cleaver1_proxy-1.0.0-py3-none-any.whl", hash = "sha256:74b2c5db1d5841444d89d8238b7a89b082327cf7d51fa674349544ad0f67073b" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-cleaver" },
]
[package.metadata]
requires-dist = [{ name = "package-cleaver" }]
"#
);
});
// 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(())
}
/// Like `preferences-dependent-forking`, but when we don't fork the resolution fails.
///
/// Consider a fresh run without preferences:
/// * We start with cleaver 2
/// * We fork
/// * We reject cleaver 2
/// * We find cleaver solution in fork 1 with foo 2 with bar 1
/// * We find cleaver solution in fork 2 with foo 1 with bar 2
/// * We write cleaver 1, foo 1, foo 2, bar 1 and bar 2 to the lockfile
///
/// In a subsequent run, we read the preference cleaver 1 from the lockfile (the preferences for foo and bar don't matter):
/// * We start with cleaver 1
/// * We're in universal mode, cleaver requires foo 1, bar 1
/// * foo 1 requires bar 2, conflict
///
/// Design sketch:
/// ```text
/// root -> clear, foo, bar
/// # Cause a fork, then forget that version.
/// cleaver 2 -> unrelated-dep==1; fork==1
/// cleaver 2 -> unrelated-dep==2; fork==2
/// cleaver 2 -> reject-cleaver-2
/// # Allow different versions when forking, but force foo 1, bar 1 in universal mode without forking.
/// cleaver 1 -> foo==1; fork==1
/// cleaver 1 -> bar==1; fork==2
/// # When we selected foo 1, bar 1 in universal mode for cleaver, this causes a conflict, otherwise we select bar 2.
/// foo 1 -> bar==2
/// ```
///
/// ```text
/// preferences-dependent-forking-conflicting
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires bar
/// │ │ ├── satisfied by bar-1.0.0
/// │ │ └── satisfied by bar-2.0.0
/// │ ├── requires cleaver
/// │ │ ├── satisfied by cleaver-2.0.0
/// │ │ └── satisfied by cleaver-1.0.0
/// │ └── requires foo
/// │ ├── satisfied by foo-1.0.0
/// │ └── satisfied by foo-2.0.0
/// ├── bar
/// │ ├── bar-1.0.0
/// │ └── bar-2.0.0
/// ├── cleaver
/// │ ├── cleaver-2.0.0
/// │ │ ├── requires reject-cleaver-2
/// │ │ │ └── satisfied by reject-cleaver-2-1.0.0
/// │ │ ├── requires unrelated-dep==1; sys_platform == "linux"
/// │ │ │ └── satisfied by unrelated-dep-1.0.0
/// │ │ └── requires unrelated-dep==2; sys_platform != "linux"
/// │ │ └── satisfied by unrelated-dep-2.0.0
/// │ └── 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
/// ├── foo
/// │ ├── foo-1.0.0
/// │ │ └── requires bar==2
/// │ │ └── satisfied by bar-2.0.0
/// │ └── foo-2.0.0
/// ├── reject-cleaver-2
/// │ └── reject-cleaver-2-1.0.0
/// │ └── requires unrelated-dep==3
/// │ └── satisfied by unrelated-dep-3.0.0
/// └── unrelated-dep
/// ├── unrelated-dep-1.0.0
/// ├── unrelated-dep-2.0.0
/// └── unrelated-dep-3.0.0
/// ```
#[test]
fn preferences_dependent_forking_conflicting() -> 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"preferences-dependent-forking-conflicting-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''preferences-dependent-forking-conflicting-cleaver''',
'''preferences-dependent-forking-conflicting-foo''',
'''preferences-dependent-forking-conflicting-bar''',
]
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 6 packages in [TIME]
"
);
Ok(())
}
/// This test case is like "preferences-dependent-forking-bistable", but with three
/// states instead of two. The first two locks are in a different state, then we
/// enter the tristable state.
///
/// It's not polished, but it's useful to have something with a higher period
/// than 2 in our test suite.
///
/// ```text
/// preferences-dependent-forking-tristable
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires bar
/// │ │ ├── satisfied by bar-1.0.0
/// │ │ └── satisfied by bar-2.0.0
/// │ ├── requires cleaver
/// │ │ ├── satisfied by cleaver-2.0.0
/// │ │ └── satisfied by cleaver-1.0.0
/// │ └── requires foo
/// │ ├── satisfied by foo-1.0.0
/// │ └── satisfied by foo-2.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ └── requires unrelated-dep3==1; os_name == "posix"
/// │ └── satisfied by unrelated-dep3-1.0.0
/// ├── b
/// │ └── b-1.0.0
/// │ └── requires unrelated-dep3==2; os_name != "posix"
/// │ └── satisfied by unrelated-dep3-2.0.0
/// ├── bar
/// │ ├── bar-1.0.0
/// │ │ ├── requires c!=3; sys_platform == "linux"
/// │ │ │ ├── satisfied by c-1.0.0
/// │ │ │ └── satisfied by c-2.0.0
/// │ │ ├── requires d; sys_platform != "linux"
/// │ │ │ └── satisfied by d-1.0.0
/// │ │ └── requires reject-cleaver-1
/// │ │ └── satisfied by reject-cleaver-1-1.0.0
/// │ └── bar-2.0.0
/// ├── c
/// │ ├── c-1.0.0
/// │ │ ├── requires reject-cleaver-1
/// │ │ │ └── satisfied by reject-cleaver-1-1.0.0
/// │ │ ├── requires unrelated-dep2==1; os_name == "posix"
/// │ │ │ └── satisfied by unrelated-dep2-1.0.0
/// │ │ └── requires unrelated-dep2==2; os_name != "posix"
/// │ │ └── satisfied by unrelated-dep2-2.0.0
/// │ ├── c-2.0.0
/// │ └── c-3.0.0
/// ├── cleaver
/// │ ├── cleaver-2.0.0
/// │ │ ├── requires a
/// │ │ │ └── satisfied by a-1.0.0
/// │ │ ├── requires b
/// │ │ │ └── satisfied by b-1.0.0
/// │ │ ├── requires unrelated-dep==1; sys_platform == "linux"
/// │ │ │ └── satisfied by unrelated-dep-1.0.0
/// │ │ └── requires unrelated-dep==2; sys_platform != "linux"
/// │ │ └── satisfied by unrelated-dep-2.0.0
/// │ └── 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
/// ├── d
/// │ └── d-1.0.0
/// │ └── requires c!=2
/// │ ├── satisfied by c-1.0.0
/// │ └── satisfied by c-3.0.0
/// ├── foo
/// │ ├── foo-1.0.0
/// │ │ ├── requires c!=3; sys_platform == "linux"
/// │ │ │ ├── satisfied by c-1.0.0
/// │ │ │ └── satisfied by c-2.0.0
/// │ │ ├── requires c!=2; sys_platform != "linux"
/// │ │ │ ├── satisfied by c-1.0.0
/// │ │ │ └── satisfied by c-3.0.0
/// │ │ └── requires reject-cleaver-1
/// │ │ └── satisfied by reject-cleaver-1-1.0.0
/// │ └── foo-2.0.0
/// ├── reject-cleaver-1
/// │ └── reject-cleaver-1-1.0.0
/// │ ├── 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 unrelated-dep3==3
/// │ └── satisfied by unrelated-dep3-3.0.0
/// ├── unrelated-dep
/// │ ├── unrelated-dep-1.0.0
/// │ ├── unrelated-dep-2.0.0
/// │ └── unrelated-dep-3.0.0
/// ├── unrelated-dep2
/// │ ├── unrelated-dep2-1.0.0
/// │ ├── unrelated-dep2-2.0.0
/// │ └── unrelated-dep2-3.0.0
/// └── unrelated-dep3
/// ├── unrelated-dep3-1.0.0
/// ├── unrelated-dep3-2.0.0
/// └── unrelated-dep3-3.0.0
/// ```
#[test]
fn preferences_dependent_forking_tristable() -> 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"preferences-dependent-forking-tristable-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''preferences-dependent-forking-tristable-cleaver''',
'''preferences-dependent-forking-tristable-foo''',
'''preferences-dependent-forking-tristable-bar''',
]
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 11 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'linux'",
"sys_platform != 'linux'",
]
[[package]]
name = "package-bar"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
dependencies = [
{ name = "package-d", marker = "sys_platform != 'linux'" },
{ name = "package-reject-cleaver-1", marker = "sys_platform != 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_bar-1.0.0.tar.gz", hash = "sha256:cab958c70ac0b91cf9db6d44846ee4aff97cdedaf1eaf96400657177eb8cf7d2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_bar-1.0.0-py3-none-any.whl", hash = "sha256:b81a56870b304c579d5ce5c1e4d0ae1ee60f109d50c739ead96ff4775ea1fb6b" },
]
[[package]]
name = "package-bar"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_bar-2.0.0.tar.gz", hash = "sha256:73f911717b729830afd19bdd8f8fee3562a8b03e8fc8f3a734becf9b15bcb9a4" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_bar-2.0.0-py3-none-any.whl", hash = "sha256:25f44f6a64ef2a5b0e315a7ddf6470931c7c9c3acca67b477a6130abddea1523" },
]
[[package]]
name = "package-c"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_c-2.0.0.tar.gz", hash = "sha256:ac8b3503e17933efe9be91ce969d2fd6f95d3175d5aa8f4033a1abd2baa5b4de" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_c-2.0.0-py3-none-any.whl", hash = "sha256:d04193e40e9415b4239a8709518dc780dc6ed4475124c4a9f0c98574dcbf7569" },
]
[[package]]
name = "package-c"
version = "3.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_c-3.0.0.tar.gz", hash = "sha256:5932c8648a79247c23756a841f5bc6ee94018cf5ec0228ae0049f9de6035262e" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_c-3.0.0-py3-none-any.whl", hash = "sha256:4a0d4549221dc761782115280a678c5ffbf1f93b8c78a5a935a197298b6dc625" },
]
[[package]]
name = "package-cleaver"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-bar", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
{ name = "package-foo", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_cleaver-1.0.0.tar.gz", hash = "sha256:6c1a467374165e60c80b639fc4ca4830dd66796fc1a363f78b2c5b0756838909" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_cleaver-1.0.0-py3-none-any.whl", hash = "sha256:1291f62c2630beb9e7a07461e7a79cf662934e4ca2fa80da0f6e7e02bb84a7d6" },
]
[[package]]
name = "package-d"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", version = "3.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_d-1.0.0.tar.gz", hash = "sha256:0662b34dc84d1529fd1f75f69c0802a5ac768611a3a11ba331af81e0e67f96a2" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_d-1.0.0-py3-none-any.whl", hash = "sha256:7917517d7d735efd5b2559223d95c5e776963b25c5cb174e2d64199898aa6adf" },
]
[[package]]
name = "package-foo"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-c", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-c", version = "3.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
{ name = "package-reject-cleaver-1" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_foo-1.0.0.tar.gz", hash = "sha256:3ab8216595ed4d66e27f853cbbfc61142cc06c1a1205c9477581c6b1463a6245" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_foo-1.0.0-py3-none-any.whl", hash = "sha256:3a42e5594ebefa939a4a366419cd335e9e52942798b6f5ab6e37b9b55e6474b8" },
]
[[package]]
name = "package-reject-cleaver-1"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-unrelated-dep2", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-unrelated-dep2", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_reject_cleaver_1-1.0.0.tar.gz", hash = "sha256:5fc04a8d0cf1eaa98da779661bf9328b04ba771bbb9261e7784b025a40c8a133" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_reject_cleaver_1-1.0.0-py3-none-any.whl", hash = "sha256:979e44471666eba857933319c56c678ac393c72081b13f67f1f41b47f558ccf9" },
]
[[package]]
name = "package-unrelated-dep2"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_unrelated_dep2-1.0.0.tar.gz", hash = "sha256:83fe5a7e81958bd422fb5cfde2c60537b97228762eada43a658e621e64a0780d" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_unrelated_dep2-1.0.0-py3-none-any.whl", hash = "sha256:461e8e88feafdaad02a4a79b9f1ad874333ee92131ca83030190c48b96dbcfc4" },
]
[[package]]
name = "package-unrelated-dep2"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_unrelated_dep2-2.0.0.tar.gz", hash = "sha256:0b491eba7b182cb80955e8592d144f20b57bcfeaf7852c568a03fdd6b0dfd752" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_tristable_unrelated_dep2-2.0.0-py3-none-any.whl", hash = "sha256:c3aedfba6ce432d4d79bc2c304f8bc493a562e0fdc963eed9253f4eb8e8bdb8e" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-bar", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
{ name = "package-bar", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-cleaver" },
{ name = "package-foo" },
]
[package.metadata]
requires-dist = [
{ name = "package-bar" },
{ name = "package-cleaver" },
{ name = "package-foo" },
]
"#
);
});
// 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 contains a scenario where the solution depends on whether we fork, and whether we fork depends on the
/// preferences.
///
/// Consider a fresh run without preferences:
/// * We start with cleaver 2
/// * We fork
/// * We reject cleaver 2
/// * We find cleaver solution in fork 1 with foo 2 with bar 1
/// * We find cleaver solution in fork 2 with foo 1 with bar 2
/// * We write cleaver 1, foo 1, foo 2, bar 1 and bar 2 to the lockfile
///
/// In a subsequent run, we read the preference cleaver 1 from the lockfile (the preferences for foo and bar don't matter):
/// * We start with cleaver 1
/// * We're in universal mode, we resolve foo 1 and bar 1
/// * We write cleaver 1 and bar 1 to the lockfile
///
/// We call a resolution that's different on the second run to the first unstable.
///
/// Design sketch:
/// ```text
/// root -> clear, foo, bar
/// # Cause a fork, then forget that version.
/// cleaver 2 -> unrelated-dep==1; fork==1
/// cleaver 2 -> unrelated-dep==2; fork==2
/// cleaver 2 -> reject-cleaver-2
/// # Allow different versions when forking, but force foo 1, bar 1 in universal mode without forking.
/// cleaver 1 -> foo==1; fork==1
/// cleaver 1 -> bar==1; fork==2
/// ```
///
/// ```text
/// preferences-dependent-forking
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires bar
/// │ │ ├── satisfied by bar-1.0.0
/// │ │ └── satisfied by bar-2.0.0
/// │ ├── requires cleaver
/// │ │ ├── satisfied by cleaver-2.0.0
/// │ │ └── satisfied by cleaver-1.0.0
/// │ └── requires foo
/// │ ├── satisfied by foo-1.0.0
/// │ └── satisfied by foo-2.0.0
/// ├── bar
/// │ ├── bar-1.0.0
/// │ └── bar-2.0.0
/// ├── cleaver
/// │ ├── cleaver-2.0.0
/// │ │ ├── requires reject-cleaver-2
/// │ │ │ └── satisfied by reject-cleaver-2-1.0.0
/// │ │ ├── requires unrelated-dep==1; sys_platform == "linux"
/// │ │ │ └── satisfied by unrelated-dep-1.0.0
/// │ │ └── requires unrelated-dep==2; sys_platform != "linux"
/// │ │ └── satisfied by unrelated-dep-2.0.0
/// │ └── 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
/// ├── foo
/// │ ├── foo-1.0.0
/// │ └── foo-2.0.0
/// ├── reject-cleaver-2
/// │ └── reject-cleaver-2-1.0.0
/// │ └── requires unrelated-dep==3
/// │ └── satisfied by unrelated-dep-3.0.0
/// └── unrelated-dep
/// ├── unrelated-dep-1.0.0
/// ├── unrelated-dep-2.0.0
/// └── unrelated-dep-3.0.0
/// ```
#[test]
fn preferences_dependent_forking() -> 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"preferences-dependent-forking-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''preferences-dependent-forking-cleaver''',
'''preferences-dependent-forking-foo''',
'''preferences-dependent-forking-bar''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"sys_platform == 'linux'",
"sys_platform != 'linux'",
]
[[package]]
name = "package-bar"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform != 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bar-1.0.0.tar.gz", hash = "sha256:78ac06984ed655965d557096cd218087641602f523eb74dc241e3237c7d6129b" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bar-1.0.0-py3-none-any.whl", hash = "sha256:bf0ab2b019e425ef38d7c5632551fefd42aaa8ab96357ab2d3ce0124dfdfe892" },
]
[[package]]
name = "package-bar"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'linux'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bar-2.0.0.tar.gz", hash = "sha256:70831af376e906171eb5905b0a163f92418e1398400b6ad749b04c7ba27102e1" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_bar-2.0.0-py3-none-any.whl", hash = "sha256:fc188f8e81088843447d1863c1098bdeef1d051040b8caaf94b0421fa331d827" },
]
[[package]]
name = "package-cleaver"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-bar", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
{ name = "package-foo", marker = "sys_platform == 'linux'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_cleaver-1.0.0.tar.gz", hash = "sha256:380812f7558b9df90347bf44e47a240e4a5ff5372628c00b3c467e95858b0e47" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_cleaver-1.0.0-py3-none-any.whl", hash = "sha256:1873c290ddafcd254f74bc4d80000b094159212141172ea24f7565dcd3bbcfe2" },
]
[[package]]
name = "package-foo"
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/preferences_dependent_forking_foo-1.0.0.tar.gz", hash = "sha256:477ad43616170d9bfec354f737d7025c5e92fce2faa0fdbf25d4c3c077a5df54" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/preferences_dependent_forking_foo-1.0.0-py3-none-any.whl", hash = "sha256:8a40eef897548e3434cab40ccdfe88648dced3bbe4f2ca40404e5dbb57d8025b" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-bar", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform != 'linux'" },
{ name = "package-bar", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'linux'" },
{ name = "package-cleaver" },
{ name = "package-foo" },
]
[package.metadata]
requires-dist = [
{ name = "package-bar" },
{ name = "package-cleaver" },
{ name = "package-foo" },
]
"#
);
});
// 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 scenario tries to check that the "remaining universe" handling in
/// the universal resolver is correct. Namely, whenever we create forks
/// from disjoint markers that don't union to the universe, we need to
/// create *another* fork corresponding to the difference between the
/// universe and the union of the forks.
///
/// But when we do this, that remaining universe fork needs to be created
/// like any other fork: it should start copying whatever set of forks
/// existed by the time we got to this point, intersecting the markers with
/// the markers describing the remaining universe and then filtering out
/// any dependencies that are disjoint with the resulting markers.
///
/// This test exercises that logic by ensuring that a package `z` in the
/// remaining universe is excluded based on the combination of markers
/// from a parent fork. That is, if the remaining universe fork does not
/// pick up the markers from the parent forks, then `z` would be included
/// because the remaining universe for _just_ the `b` dependencies of `a`
/// is `os_name != 'linux' and os_name != 'darwin'`, which is satisfied by
/// `z`'s marker of `sys_platform == 'windows'`. However, `a 1.0.0` is only
/// selected in the context of `a < 2 ; sys_platform == 'illumos'`, so `z`
/// should never appear in the resolution.
///
/// ```text
/// fork-remaining-universe-partitioning
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a>=2; sys_platform == "windows"
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires a<2; sys_platform == "illumos"
/// │ └── satisfied by a-1.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ │ ├── requires b>=2; os_name == "linux"
/// │ │ │ └── satisfied by b-2.0.0
/// │ │ ├── requires b<2; os_name == "darwin"
/// │ │ │ └── satisfied by b-1.0.0
/// │ │ └── requires z; sys_platform == "windows"
/// │ │ └── satisfied by z-1.0.0
/// │ └── a-2.0.0
/// ├── b
/// │ ├── b-1.0.0
/// │ └── b-2.0.0
/// └── z
/// └── z-1.0.0
/// ```
#[test]
fn fork_remaining_universe_partitioning() -> 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"fork-remaining-universe-partitioning-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-remaining-universe-partitioning-a>=2; sys_platform == "windows"''',
'''fork-remaining-universe-partitioning-a<2; sys_platform == "illumos"''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
resolution-markers = [
"os_name == 'darwin' and sys_platform == 'illumos'",
"os_name == 'linux' and sys_platform == 'illumos'",
"os_name != 'darwin' and os_name != 'linux' and sys_platform == 'illumos'",
"sys_platform == 'windows'",
"sys_platform != 'illumos' and sys_platform != 'windows'",
]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"os_name == 'darwin' and sys_platform == 'illumos'",
"os_name == 'linux' and sys_platform == 'illumos'",
"os_name != 'darwin' and os_name != 'linux' and sys_platform == 'illumos'",
]
dependencies = [
{ name = "package-b", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "os_name == 'darwin' and sys_platform == 'illumos'" },
{ name = "package-b", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "os_name == 'linux' and sys_platform == 'illumos'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_a-1.0.0.tar.gz", hash = "sha256:8265b2f0d92cd4d63f303ca1a81c0920b9bcb9026434388b5c41847772ea2e41" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_a-1.0.0-py3-none-any.whl", hash = "sha256:2964220ab58b53d9e84ecb9f384d7284e914280779e0157ea5f1c1f4375a67b0" },
]
[[package]]
name = "package-a"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"sys_platform == 'windows'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_a-2.0.0.tar.gz", hash = "sha256:a06312972c1436362b2af1366918160dd775f046a2a6991d7ec6f3ae17e2da4e" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_a-2.0.0-py3-none-any.whl", hash = "sha256:4e4f4e2dd97e69715d430c227bdaa8635a46b4eac5d26b9d48edf6ea21c2ea9c" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"os_name == 'darwin' and sys_platform == 'illumos'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_b-1.0.0.tar.gz", hash = "sha256:a41c05053e9b6c47c7d1e66a7b0ae74542b40008f906c0bca8e65ddbb124c8f1" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_b-1.0.0-py3-none-any.whl", hash = "sha256:60c8698c2721d7abba70175c61d206f47a77729268735740294778b6fd1913e4" },
]
[[package]]
name = "package-b"
version = "2.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
resolution-markers = [
"os_name == 'linux' and sys_platform == 'illumos'",
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_b-2.0.0.tar.gz", hash = "sha256:043c931dd9a88b360ec57b3bc6753b5df22f0e844b7589f1e42afd84c9de9d76" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_remaining_universe_partitioning_b-2.0.0-py3-none-any.whl", hash = "sha256:2bea93dc4ccddac32a3f3ab47df20c9f39a6fb7c34a2916d4df6397442202ba9" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", version = "1.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'illumos'" },
{ name = "package-a", version = "2.0.0", source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }, marker = "sys_platform == 'windows'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'illumos'", specifier = "<2" },
{ name = "package-a", marker = "sys_platform == 'windows'", specifier = ">=2" },
]
"#
);
});
// 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 tests that a `Requires-Python` specifier will result in the
/// exclusion of dependency specifications that cannot possibly satisfy it.
///
/// In particular, this is tested via the `python_full_version` marker with
/// a pre-release version.
///
/// ```text
/// fork-requires-python-full-prerelease
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires a==1.0.0; python_full_version == "3.9b1"
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn fork_requires_python_full_prerelease() -> 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"fork-requires-python-full-prerelease-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-requires-python-full-prerelease-a==1.0.0; python_full_version == "3.9b1"''',
]
requires-python = ">=3.10"
"###,
)?;
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 1 package in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.10"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
[package.metadata]
requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9'", specifier = "==1.0.0" }]
"#
);
});
// 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 tests that a `Requires-Python` specifier will result in the
/// exclusion of dependency specifications that cannot possibly satisfy it.
///
/// In particular, this is tested via the `python_full_version` marker
/// instead of the more common `python_version` marker.
///
/// ```text
/// fork-requires-python-full
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires a==1.0.0; python_full_version == "3.9"
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn fork_requires_python_full() -> 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"fork-requires-python-full-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-requires-python-full-a==1.0.0; python_full_version == "3.9"''',
]
requires-python = ">=3.10"
"###,
)?;
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 1 package in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.10"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
[package.metadata]
requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9'", specifier = "==1.0.0" }]
"#
);
});
// 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 tests that a `Requires-Python` specifier that includes a Python
/// patch version will not result in excluded a dependency specification
/// with a `python_version == '3.10'` marker.
///
/// This is a regression test for the universal resolver where it would
/// convert a `Requires-Python: >=3.10.1` specifier into a
/// `python_version >= '3.10.1'` marker expression, which would be
/// considered disjoint with `python_version == '3.10'`. Thus, the
/// dependency `a` below was erroneously excluded. It should be included.
///
/// ```text
/// fork-requires-python-patch-overlap
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires a==1.0.0; python_version == "3.10"
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python>=3.10
/// ```
#[test]
fn fork_requires_python_patch_overlap() -> 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"fork-requires-python-patch-overlap-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-requires-python-patch-overlap-a==1.0.0; python_version == "3.10"''',
]
requires-python = ">=3.10.1"
"###,
)?;
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.10.1"
[[package]]
name = "package-a"
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/fork_requires_python_patch_overlap_a-1.0.0.tar.gz", hash = "sha256:98210d2d45238045c16262c38a2211b3239e1ea164dd6061292f6012e5c85d1e" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/fork_requires_python_patch_overlap_a-1.0.0-py3-none-any.whl", hash = "sha256:a6a97b0e0d0b176aa3942b7f58c8898a32e7050ada4349f6105922d3e2db3924" },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", marker = "python_full_version < '3.11'" },
]
[package.metadata]
requires-dist = [{ name = "package-a", marker = "python_full_version == '3.10.*'", specifier = "==1.0.0" }]
"#
);
});
// 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 tests that a `Requires-Python` specifier will result in the
/// exclusion of dependency specifications that cannot possibly satisfy it.
///
/// ```text
/// fork-requires-python
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires a==1.0.0; python_version == "3.9"
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// ```
#[test]
fn fork_requires_python() -> 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"fork-requires-python-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''fork-requires-python-a==1.0.0; python_version == "3.9"''',
]
requires-python = ">=3.10"
"###,
)?;
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 1 package in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.10"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
[package.metadata]
requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9.*'", specifier = "==1.0.0" }]
"#
);
});
// 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 that we only include wheels that match the required Python version
///
/// ```text
/// requires-python-wheels
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── a
/// └── a-1.0.0
/// └── requires python>=3.10
/// ```
#[test]
fn requires_python_wheels() -> 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"requires-python-wheels-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''requires-python-wheels-a==1.0.0''',
]
requires-python = ">=3.10"
"###,
)?;
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.10"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
]
[package.metadata]
requires-dist = [{ name = "package-a", specifier = "==1.0.0" }]
[[package]]
name = "package-a"
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/requires_python_wheels_a-1.0.0.tar.gz", hash = "sha256:a47ad4fb0ebd76fcde3bf4aabf5d9393039f76822d990858e23ad17cd23dc67a" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/requires_python_wheels_a-1.0.0-cp310-cp310-any.whl", hash = "sha256:38109d4f29bd910e11cf3ea462fe06e740a346e76d1afa95fda2228845725de5" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/requires_python_wheels_a-1.0.0-cp311-cp311-any.whl", hash = "sha256:38109d4f29bd910e11cf3ea462fe06e740a346e76d1afa95fda2228845725de5" },
]
"#
);
});
// 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(())
}
/// `c` is not reachable due to the markers, it should be excluded from the lockfile
///
/// ```text
/// unreachable-package
/// ├── environment
/// │ └── 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
/// └── b
/// └── b-1.0.0
/// ```
#[test]
fn unreachable_package() -> 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"unreachable-package-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''unreachable-package-a==1.0.0; sys_platform == "win32"''',
]
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 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", marker = "sys_platform == 'win32'" },
]
[package.metadata]
requires-dist = [{ name = "package-a", marker = "sys_platform == 'win32'", specifier = "==1.0.0" }]
[[package]]
name = "package-a"
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/unreachable_package_a-1.0.0.tar.gz", hash = "sha256:4ceb6be97b8f4526768c02f4a270cf270e225361eb42d1e87426b164be82f383" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_package_a-1.0.0-py3-none-any.whl", hash = "sha256:a61dae53684bd2dbc1bd96b375b55e0c2f445b47d4c601b061d3fe1138fd805d" },
]
"#
);
});
// 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 that we only include wheels that match the platform markers
///
/// ```text
/// unreachable-wheels
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a==1.0.0; sys_platform == "win32"
/// │ │ └── satisfied by a-1.0.0
/// │ ├── requires b==1.0.0; sys_platform == "linux"
/// │ │ └── satisfied by b-1.0.0
/// │ └── requires c==1.0.0; sys_platform == "darwin"
/// │ └── satisfied by c-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// ├── b
/// │ └── b-1.0.0
/// └── c
/// └── c-1.0.0
/// ```
#[test]
fn unreachable_wheels() -> 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"unreachable-wheels-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''unreachable-wheels-a==1.0.0; sys_platform == "win32"''',
'''unreachable-wheels-b==1.0.0; sys_platform == "linux"''',
'''unreachable-wheels-c==1.0.0; sys_platform == "darwin"''',
]
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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a", marker = "sys_platform == 'win32'" },
{ name = "package-b", marker = "sys_platform == 'linux'" },
{ name = "package-c", marker = "sys_platform == 'darwin'" },
]
[package.metadata]
requires-dist = [
{ name = "package-a", marker = "sys_platform == 'win32'", specifier = "==1.0.0" },
{ name = "package-b", marker = "sys_platform == 'linux'", specifier = "==1.0.0" },
{ name = "package-c", marker = "sys_platform == 'darwin'", specifier = "==1.0.0" },
]
[[package]]
name = "package-a"
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/unreachable_wheels_a-1.0.0.tar.gz", hash = "sha256:7af67216432f3484632f08d42817a4425b2f7e6285d066b857b1b63479683173" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_wheels_a-1.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:fb0f200722746083492595dd95b5774f8807e632fa290b5615e66e921267cfd2" },
]
[[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/unreachable_wheels_b-1.0.0.tar.gz", hash = "sha256:31943f973b8114889e4acd42add16396be474638db534604e6ca0a5d88e27ee5" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_wheels_b-1.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44108443dc9bf6bfb387875df0ee4ea793832d91417097586a0b90cc261da199" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_wheels_b-1.0.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:44108443dc9bf6bfb387875df0ee4ea793832d91417097586a0b90cc261da199" },
]
[[package]]
name = "package-c"
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/unreachable_wheels_c-1.0.0.tar.gz", hash = "sha256:019230145b8dc90c687cb360077ffcd470243795480fd145d25b2a4af2b71858" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_wheels_c-1.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:17f36f8a58561cf654235bbfecb9d4390bacc62d666ebcf4c93d94b750eb425e" },
]
"#
);
});
// 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 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 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
/// └── tzdata
/// └── tzdata-1.0.0
/// ```
#[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.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 4 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
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:73bfd3a8cd320336ded5c7cb2219544b8b66819c784cb88634fc2d716b42654b" }
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:29661efd1d691398d6fc0c1cca3618d795ce64ef50f4b152ff9cff471582afe1" },
]
[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:988780eb0dc092cd5af36bef12d5c42404ee4dd73e6c29c842cc802a558d355e" }
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:8f07333ec83cc11023198e50ec91314afbe96e3b905183ec060e60388d18eab4" },
]
[[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:05613cdd40338ffb46f0c94efa618d5b64b4879040c520b2934b982772220f47" }
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:8d59a2ae73c64014e27574eae496a70d5619aca1ddcb04f5a589de97850b13a8" },
]
[[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
/// │ └── a-2.0.0
/// │ └── requires b==1; python_version >= "3.10"
/// │ └── satisfied by b-1.0.0
/// └── b
/// ├── b-1.0.0
/// └── b-2.0.0
/// ```
#[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 = 3
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:df3b975e935948c0e3ce80413fabacc7473b3b77fa6143c2d50134ca9821b982" }
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:7d8ceba929775dd3294275637a76c1556b816705f86d9d913b92df708bbe09bc" },
]
[[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:1871d4ccdcae672dbeda7e8c9bd16c28e3256e343470d1ae9f8bd2946ba7ab9f" }
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:d92888ac830ae8768749436fec5133b9262667c2c743285f941b18bb13724222" },
]
"#
);
});
// 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.12
/// ├── root
/// │ └── requires a
/// │ └── satisfied by a-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// │ ├── requires b; platform_machine == "x86_64"
/// │ │ └── 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
/// ├── b
/// │ └── b-1.0.0
/// ├── c
/// │ └── c-1.0.0
/// └── d
/// └── d-1.0.0
/// ```
#[test]
fn specific_architecture() -> 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"specific-architecture-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''specific-architecture-a''',
]
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 5 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-a" },
]
[package.metadata]
requires-dist = [{ name = "package-a" }]
[[package]]
name = "package-a"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
dependencies = [
{ name = "package-b", marker = "platform_machine == 'x86_64'" },
{ name = "package-c", marker = "platform_machine == 'aarch64'" },
{ name = "package-d", marker = "platform_machine == 'i686'" },
]
sdist = { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_a-1.0.0.tar.gz", hash = "sha256:d2ab13af91c3f80269717ccc9d71dae2b0cf59b0b53b7ce5e1687c3c12530518" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_a-1.0.0-py3-none-any.whl", hash = "sha256:55436c2630725abac18f06b5f2255ed32c447b8b6e8ef6abfe533259028abb82" },
]
[[package]]
name = "package-b"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_b-1.0.0-cp313-cp313-freebsd_13_aarch64.whl", hash = "sha256:e494f9d058ab90fc641c4390bbd81164210daf0d1811672d187636653496f77d" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_b-1.0.0-cp313-cp313-freebsd_13_x86_64.whl", hash = "sha256:e494f9d058ab90fc641c4390bbd81164210daf0d1811672d187636653496f77d" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_b-1.0.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:e494f9d058ab90fc641c4390bbd81164210daf0d1811672d187636653496f77d" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_b-1.0.0-cp313-cp313-manylinux2010_x86_64.whl", hash = "sha256:e494f9d058ab90fc641c4390bbd81164210daf0d1811672d187636653496f77d" },
]
[[package]]
name = "package-c"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_c-1.0.0-cp313-cp313-freebsd_13_aarch64.whl", hash = "sha256:64ebbefd7b78db539d4884fc7f2d9df24bd253511cb67350ac6b610291cd8405" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_c-1.0.0-cp313-cp313-freebsd_13_x86_64.whl", hash = "sha256:64ebbefd7b78db539d4884fc7f2d9df24bd253511cb67350ac6b610291cd8405" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_c-1.0.0-cp313-cp313-macosx_10_9_arm64.whl", hash = "sha256:64ebbefd7b78db539d4884fc7f2d9df24bd253511cb67350ac6b610291cd8405" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_c-1.0.0-cp313-cp313-manylinux2010_aarch64.whl", hash = "sha256:64ebbefd7b78db539d4884fc7f2d9df24bd253511cb67350ac6b610291cd8405" },
]
[[package]]
name = "package-d"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_d-1.0.0-cp313-cp313-freebsd_13_aarch64.whl", hash = "sha256:f49cf7bda1ea7366cd0cae8b9f0d8975f7b29ae3569b2aa70fe2d5eb5176cc64" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_d-1.0.0-cp313-cp313-freebsd_13_x86_64.whl", hash = "sha256:f49cf7bda1ea7366cd0cae8b9f0d8975f7b29ae3569b2aa70fe2d5eb5176cc64" },
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_d-1.0.0-cp313-cp313-manylinux2010_i686.whl", hash = "sha256:f49cf7bda1ea7366cd0cae8b9f0d8975f7b29ae3569b2aa70fe2d5eb5176cc64" },
]
"#
);
});
// 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(())
}