mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-11 16:34:33 +00:00
Update packse to pull in additional local version tests (#2462)
Precursor to #2430.
This commit is contained in:
parent
2fb8df3769
commit
17732246df
7 changed files with 587 additions and 34 deletions
|
|
@ -257,6 +257,19 @@ impl Cache {
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(root.join(".git"))?;
|
.open(root.join(".git"))?;
|
||||||
|
|
||||||
|
// Add an empty .gitignore to the build bucket, to ensure that the cache's own .gitignore
|
||||||
|
// doesn't interfere with source distribution builds. Build backends (like hatchling) will
|
||||||
|
// traverse upwards to look for .gitignore files.
|
||||||
|
fs::create_dir_all(root.join(CacheBucket::BuiltWheels.to_str()))?;
|
||||||
|
match fs::OpenOptions::new().write(true).create_new(true).open(
|
||||||
|
root.join(CacheBucket::BuiltWheels.to_str())
|
||||||
|
.join(".gitignore"),
|
||||||
|
) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => (),
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
|
||||||
fs::canonicalize(root)
|
fs::canonicalize(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -816,7 +816,8 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
let span =
|
let span =
|
||||||
info_span!("download_source_dist", filename = filename, source_dist = %source_dist);
|
info_span!("download_source_dist", filename = filename, source_dist = %source_dist);
|
||||||
let temp_dir =
|
let temp_dir =
|
||||||
tempfile::tempdir_in(self.build_context.cache().root()).map_err(Error::CacheWrite)?;
|
tempfile::tempdir_in(self.build_context.cache().bucket(CacheBucket::BuiltWheels))
|
||||||
|
.map_err(Error::CacheWrite)?;
|
||||||
let reader = response
|
let reader = response
|
||||||
.bytes_stream()
|
.bytes_stream()
|
||||||
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))
|
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))
|
||||||
|
|
@ -896,7 +897,8 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
} else {
|
} else {
|
||||||
debug!("Unpacking for build: {source_dist}");
|
debug!("Unpacking for build: {source_dist}");
|
||||||
|
|
||||||
let temp_dir = tempfile::tempdir_in(self.build_context.cache().root())
|
let temp_dir =
|
||||||
|
tempfile::tempdir_in(self.build_context.cache().bucket(CacheBucket::BuiltWheels))
|
||||||
.map_err(Error::CacheWrite)?;
|
.map_err(Error::CacheWrite)?;
|
||||||
|
|
||||||
// Unzip the archive into the temporary directory.
|
// Unzip the archive into the temporary directory.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! DO NOT EDIT
|
//! DO NOT EDIT
|
||||||
//!
|
//!
|
||||||
//! Generated with ./scripts/scenarios/sync.sh
|
//! Generated with ./scripts/scenarios/sync.sh
|
||||||
//! Scenarios from <https://github.com/zanieb/packse/tree/0.3.7/scenarios>
|
//! Scenarios from <https://github.com/zanieb/packse/tree/0.3.9/scenarios>
|
||||||
//!
|
//!
|
||||||
#![cfg(all(feature = "python", feature = "pypi"))]
|
#![cfg(all(feature = "python", feature = "pypi"))]
|
||||||
|
|
||||||
|
|
@ -27,9 +27,9 @@ fn command(context: &TestContext, python_versions: &[&str]) -> Command {
|
||||||
.arg("compile")
|
.arg("compile")
|
||||||
.arg("requirements.in")
|
.arg("requirements.in")
|
||||||
.arg("--index-url")
|
.arg("--index-url")
|
||||||
.arg("https://astral-sh.github.io/packse/0.3.7/simple-html/")
|
.arg("https://astral-sh.github.io/packse/0.3.9/simple-html/")
|
||||||
.arg("--find-links")
|
.arg("--find-links")
|
||||||
.arg("https://raw.githubusercontent.com/zanieb/packse/0.3.7/vendor/links.html")
|
.arg("https://raw.githubusercontent.com/zanieb/packse/0.3.9/vendor/links.html")
|
||||||
.arg("--cache-dir")
|
.arg("--cache-dir")
|
||||||
.arg(context.cache_dir.path())
|
.arg(context.cache_dir.path())
|
||||||
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
||||||
|
|
@ -66,7 +66,7 @@ fn incompatible_python_compatible_override() -> Result<()> {
|
||||||
let context = TestContext::new("3.9");
|
let context = TestContext::new("3.9");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((r"incompatible-python-compatible-override-", "package-"));
|
filters.push((r"incompatible-python-compatible-override-", "package-"));
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ fn compatible_python_incompatible_override() -> Result<()> {
|
||||||
let context = TestContext::new("3.11");
|
let context = TestContext::new("3.11");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((r"compatible-python-incompatible-override-", "package-"));
|
filters.push((r"compatible-python-incompatible-override-", "package-"));
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ fn incompatible_python_compatible_override_unavailable_no_wheels() -> Result<()>
|
||||||
let context = TestContext::new("3.9");
|
let context = TestContext::new("3.9");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((
|
filters.push((
|
||||||
r"incompatible-python-compatible-override-unavailable-no-wheels-",
|
r"incompatible-python-compatible-override-unavailable-no-wheels-",
|
||||||
|
|
@ -218,7 +218,7 @@ fn incompatible_python_compatible_override_available_no_wheels() -> Result<()> {
|
||||||
let context = TestContext::new("3.9");
|
let context = TestContext::new("3.9");
|
||||||
let python_versions = &["3.11"];
|
let python_versions = &["3.11"];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((
|
filters.push((
|
||||||
r"incompatible-python-compatible-override-available-no-wheels-",
|
r"incompatible-python-compatible-override-available-no-wheels-",
|
||||||
|
|
@ -273,7 +273,7 @@ fn incompatible_python_compatible_override_no_compatible_wheels() -> Result<()>
|
||||||
let context = TestContext::new("3.9");
|
let context = TestContext::new("3.9");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((
|
filters.push((
|
||||||
r"incompatible-python-compatible-override-no-compatible-wheels-",
|
r"incompatible-python-compatible-override-no-compatible-wheels-",
|
||||||
|
|
@ -331,7 +331,7 @@ fn incompatible_python_compatible_override_other_wheel() -> Result<()> {
|
||||||
let context = TestContext::new("3.9");
|
let context = TestContext::new("3.9");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((
|
filters.push((
|
||||||
r"incompatible-python-compatible-override-other-wheel-",
|
r"incompatible-python-compatible-override-other-wheel-",
|
||||||
|
|
@ -391,7 +391,7 @@ fn python_patch_override_no_patch() -> Result<()> {
|
||||||
let context = TestContext::new("3.8.18");
|
let context = TestContext::new("3.8.18");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((r"python-patch-override-no-patch-", "package-"));
|
filters.push((r"python-patch-override-no-patch-", "package-"));
|
||||||
|
|
||||||
|
|
@ -438,7 +438,7 @@ fn python_patch_override_patch_compatible() -> Result<()> {
|
||||||
let context = TestContext::new("3.8.18");
|
let context = TestContext::new("3.8.18");
|
||||||
let python_versions = &[];
|
let python_versions = &[];
|
||||||
|
|
||||||
// In addition to the standard filters, swap out package names for more realistic messages
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
let mut filters = INSTA_FILTERS.to_vec();
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
filters.push((r"python-patch-override-patch-compatible-", "package-"));
|
filters.push((r"python-patch-override-patch-compatible-", "package-"));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! DO NOT EDIT
|
//! DO NOT EDIT
|
||||||
//!
|
//!
|
||||||
//! Generated with ./scripts/scenarios/sync.sh
|
//! Generated with ./scripts/scenarios/sync.sh
|
||||||
//! Scenarios from <https://github.com/zanieb/packse/tree/0.3.7/scenarios>
|
//! Scenarios from <https://github.com/zanieb/packse/tree/0.3.9/scenarios>
|
||||||
//!
|
//!
|
||||||
#![cfg(all(feature = "python", feature = "pypi"))]
|
#![cfg(all(feature = "python", feature = "pypi"))]
|
||||||
|
|
||||||
|
|
@ -46,9 +46,9 @@ fn command(context: &TestContext) -> Command {
|
||||||
.arg("pip")
|
.arg("pip")
|
||||||
.arg("install")
|
.arg("install")
|
||||||
.arg("--index-url")
|
.arg("--index-url")
|
||||||
.arg("https://astral-sh.github.io/packse/0.3.7/simple-html/")
|
.arg("https://astral-sh.github.io/packse/0.3.9/simple-html/")
|
||||||
.arg("--find-links")
|
.arg("--find-links")
|
||||||
.arg("https://raw.githubusercontent.com/zanieb/packse/0.3.7/vendor/links.html")
|
.arg("https://raw.githubusercontent.com/zanieb/packse/0.3.9/vendor/links.html")
|
||||||
.arg("--cache-dir")
|
.arg("--cache-dir")
|
||||||
.arg(context.cache_dir.path())
|
.arg(context.cache_dir.path())
|
||||||
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
.env("VIRTUAL_ENV", context.venv.as_os_str())
|
||||||
|
|
@ -1289,7 +1289,7 @@ fn local_simple() {
|
||||||
╰─▶ Because there is no version of package-a==1.2.3 and you require package-a==1.2.3, we can conclude that the requirements are unsatisfiable.
|
╰─▶ Because there is no version of package-a==1.2.3 and you require package-a==1.2.3, we can conclude that the requirements are unsatisfiable.
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// The verison '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
// The version '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
||||||
assert_not_installed(&context.venv, "local_simple_a", &context.temp_dir);
|
assert_not_installed(&context.venv, "local_simple_a", &context.temp_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1330,10 +1330,11 @@ fn local_not_used_with_sdist() {
|
||||||
+ package-a==1.2.3
|
+ package-a==1.2.3
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// The verison '1.2.3' with an sdist satisfies the constraint '==1.2.3'.
|
// The version '1.2.3' with an sdist satisfies the constraint '==1.2.3'.
|
||||||
assert_not_installed(
|
assert_installed(
|
||||||
&context.venv,
|
&context.venv,
|
||||||
"local_not_used_with_sdist_a",
|
"local_not_used_with_sdist_a",
|
||||||
|
"1.2.3",
|
||||||
&context.temp_dir,
|
&context.temp_dir,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1374,7 +1375,7 @@ fn local_used_without_sdist() {
|
||||||
╰─▶ Because package-a==1.2.3 is unusable because no wheels are available with a matching Python ABI and you require package-a==1.2.3, we can conclude that the requirements are unsatisfiable.
|
╰─▶ Because package-a==1.2.3 is unusable because no wheels are available with a matching Python ABI and you require package-a==1.2.3, we can conclude that the requirements are unsatisfiable.
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// The verison '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
// The version '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
||||||
assert_not_installed(
|
assert_not_installed(
|
||||||
&context.venv,
|
&context.venv,
|
||||||
"local_used_without_sdist_a",
|
"local_used_without_sdist_a",
|
||||||
|
|
@ -1470,13 +1471,235 @@ fn local_transitive() {
|
||||||
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// The verison '2.0.0+foo' satisfies both ==2.0.0 and ==2.0.0+foo.
|
// The version '2.0.0+foo' satisfies both ==2.0.0 and ==2.0.0+foo.
|
||||||
assert_not_installed(&context.venv, "local_transitive_a", &context.temp_dir);
|
assert_not_installed(&context.venv, "local_transitive_a", &context.temp_dir);
|
||||||
assert_not_installed(&context.venv, "local_transitive_b", &context.temp_dir);
|
assert_not_installed(&context.venv, "local_transitive_b", &context.temp_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A transitive constraint on a local version should not match an exclusive ordered
|
||||||
|
/// operator.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-greater-than
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ └── satisfied by a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ └── a-1.0.0
|
||||||
|
/// │ └── requires b>2.0.0
|
||||||
|
/// │ └── unsatisfied: no matching version
|
||||||
|
/// └── b
|
||||||
|
/// └── b-2.0.0+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_greater_than() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-greater-than-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-greater-than-a")
|
||||||
|
.arg("local-transitive-greater-than-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
Downloaded 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
+ package-a==1.0.0
|
||||||
|
+ package-b==2.0.0+foo
|
||||||
|
"###);
|
||||||
|
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_greater_than_a",
|
||||||
|
"1.0.0",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_greater_than_b",
|
||||||
|
"2.0.0+foo",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A transitive constraint on a local version should match an inclusive ordered
|
||||||
|
/// operator.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-greater-than-or-equal
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ └── satisfied by a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ └── a-1.0.0
|
||||||
|
/// │ └── requires b>=2.0.0
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// └── b
|
||||||
|
/// └── b-2.0.0+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_greater_than_or_equal() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-greater-than-or-equal-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-greater-than-or-equal-a")
|
||||||
|
.arg("local-transitive-greater-than-or-equal-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
Downloaded 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
+ package-a==1.0.0
|
||||||
|
+ package-b==2.0.0+foo
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// The version '2.0.0+foo' satisfies both >=2.0.0 and ==2.0.0+foo.
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_greater_than_or_equal_a",
|
||||||
|
"1.0.0",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_greater_than_or_equal_b",
|
||||||
|
"2.0.0+foo",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A transitive constraint on a local version should not match an exclusive ordered
|
||||||
|
/// operator.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-less-than
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ └── satisfied by a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ └── a-1.0.0
|
||||||
|
/// │ └── requires b<2.0.0
|
||||||
|
/// │ └── unsatisfied: no matching version
|
||||||
|
/// └── b
|
||||||
|
/// └── b-2.0.0+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_less_than() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-less-than-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-less-than-a")
|
||||||
|
.arg("local-transitive-less-than-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b<2.0.0, we can conclude that all versions of package-a depend on package-b<2.0.0.
|
||||||
|
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_less_than_a",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_less_than_b",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A transitive constraint on a local version should match an inclusive ordered
|
||||||
|
/// operator.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-less-than-or-equal
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ └── satisfied by a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ └── a-1.0.0
|
||||||
|
/// │ └── requires b<=2.0.0
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// └── b
|
||||||
|
/// └── b-2.0.0+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_less_than_or_equal() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-less-than-or-equal-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-less-than-or-equal-a")
|
||||||
|
.arg("local-transitive-less-than-or-equal-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b<=2.0.0, we can conclude that all versions of package-a depend on package-b<=2.0.0.
|
||||||
|
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// The version '2.0.0+foo' satisfies both <=2.0.0 and ==2.0.0+foo.
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_less_than_or_equal_a",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_less_than_or_equal_b",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// A transitive dependency has both a non-local and local version published, but
|
/// A transitive dependency has both a non-local and local version published, but
|
||||||
/// the non-local version is unuable.
|
/// the non-local version is unusable.
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
/// local-transitive-confounding
|
/// local-transitive-confounding
|
||||||
|
|
@ -1515,7 +1738,7 @@ fn local_transitive_confounding() {
|
||||||
And because only package-a==1.0.0 is available and you require package-a, we can conclude that the requirements are unsatisfiable.
|
And because only package-a==1.0.0 is available and you require package-a, we can conclude that the requirements are unsatisfiable.
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// The verison '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
// The version '1.2.3+foo' satisfies the constraint '==1.2.3'.
|
||||||
assert_not_installed(
|
assert_not_installed(
|
||||||
&context.venv,
|
&context.venv,
|
||||||
"local_transitive_confounding_a",
|
"local_transitive_confounding_a",
|
||||||
|
|
@ -1523,6 +1746,286 @@ fn local_transitive_confounding() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A dependency depends on a conflicting local version of a direct dependency.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-conflicting
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ └── satisfied by a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ └── a-1.0.0
|
||||||
|
/// │ └── requires b==2.0.0+bar
|
||||||
|
/// │ └── satisfied by b-2.0.0+bar
|
||||||
|
/// └── b
|
||||||
|
/// ├── b-2.0.0+foo
|
||||||
|
/// └── b-2.0.0+bar
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_conflicting() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-conflicting-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-conflicting-a")
|
||||||
|
.arg("local-transitive-conflicting-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 depends on package-b==2.0.0+bar, we can conclude that all versions of package-a depend on package-b==2.0.0+bar.
|
||||||
|
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_conflicting_a",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_conflicting_b",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A dependency depends on a conflicting local version of a direct dependency, but
|
||||||
|
/// we can backtrack to a compatible version.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-transitive-backtrack
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ ├── requires a
|
||||||
|
/// │ │ ├── satisfied by a-1.0.0
|
||||||
|
/// │ │ └── satisfied by a-2.0.0
|
||||||
|
/// │ └── requires b==2.0.0+foo
|
||||||
|
/// │ └── satisfied by b-2.0.0+foo
|
||||||
|
/// ├── a
|
||||||
|
/// │ ├── a-1.0.0
|
||||||
|
/// │ │ └── requires b==2.0.0
|
||||||
|
/// │ │ ├── satisfied by b-2.0.0+foo
|
||||||
|
/// │ │ └── satisfied by b-2.0.0+bar
|
||||||
|
/// │ └── a-2.0.0
|
||||||
|
/// │ └── requires b==2.0.0+bar
|
||||||
|
/// │ └── satisfied by b-2.0.0+bar
|
||||||
|
/// └── b
|
||||||
|
/// ├── b-2.0.0+foo
|
||||||
|
/// └── b-2.0.0+bar
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_transitive_backtrack() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-transitive-backtrack-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-transitive-backtrack-a")
|
||||||
|
.arg("local-transitive-backtrack-b==2.0.0+foo")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only the following versions of package-a are available:
|
||||||
|
package-a==1.0.0
|
||||||
|
package-a==2.0.0
|
||||||
|
and package-a==1.0.0 depends on package-b==2.0.0, we can conclude that package-a<2.0.0 depends on package-b==2.0.0.
|
||||||
|
And because package-a==2.0.0 depends on package-b==2.0.0+bar, we can conclude that all versions of package-a depend on one of:
|
||||||
|
package-b==2.0.0
|
||||||
|
package-b==2.0.0+bar
|
||||||
|
|
||||||
|
And because you require package-a and you require package-b==2.0.0+foo, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Backtracking to '1.0.0' gives us compatible local versions of b.
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_backtrack_a",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_transitive_backtrack_b",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A local version should be excluded in exclusive ordered comparisons.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-greater-than
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ └── requires a>1.2.3
|
||||||
|
/// │ └── unsatisfied: no matching version
|
||||||
|
/// └── a
|
||||||
|
/// └── a-1.2.3+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_greater_than() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-greater-than-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-greater-than-a>1.2.3")
|
||||||
|
, @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
Downloaded 1 package in [TIME]
|
||||||
|
Installed 1 package in [TIME]
|
||||||
|
+ package-a==1.2.3+foo
|
||||||
|
"###);
|
||||||
|
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_greater_than_a",
|
||||||
|
"1.2.3+foo",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A local version should be included in inclusive ordered comparisons.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-greater-than-or-equal
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ └── requires a>=1.2.3
|
||||||
|
/// │ └── satisfied by a-1.2.3+foo
|
||||||
|
/// └── a
|
||||||
|
/// └── a-1.2.3+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_greater_than_or_equal() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-greater-than-or-equal-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-greater-than-or-equal-a>=1.2.3")
|
||||||
|
, @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
Downloaded 1 package in [TIME]
|
||||||
|
Installed 1 package in [TIME]
|
||||||
|
+ package-a==1.2.3+foo
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// The version '1.2.3+foo' satisfies the constraint '>=1.2.3'.
|
||||||
|
assert_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_greater_than_or_equal_a",
|
||||||
|
"1.2.3+foo",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A local version should be excluded in exclusive ordered comparisons.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-less-than
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ └── requires a<1.2.3
|
||||||
|
/// │ └── unsatisfied: no matching version
|
||||||
|
/// └── a
|
||||||
|
/// └── a-1.2.3+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_less_than() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-less-than-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-less-than-a<1.2.3")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only package-a>=1.2.3 is available and you require package-a<1.2.3, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
assert_not_installed(&context.venv, "local_less_than_a", &context.temp_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A local version should be included in inclusive ordered comparisons.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// local-less-than-or-equal
|
||||||
|
/// ├── environment
|
||||||
|
/// │ └── python3.8
|
||||||
|
/// ├── root
|
||||||
|
/// │ └── requires a<=1.2.3
|
||||||
|
/// │ └── satisfied by a-1.2.3+foo
|
||||||
|
/// └── a
|
||||||
|
/// └── a-1.2.3+foo
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn local_less_than_or_equal() {
|
||||||
|
let context = TestContext::new("3.8");
|
||||||
|
|
||||||
|
// In addition to the standard filters, swap out package names for shorter messages
|
||||||
|
let mut filters = INSTA_FILTERS.to_vec();
|
||||||
|
filters.push((r"local-less-than-or-equal-", "package-"));
|
||||||
|
|
||||||
|
uv_snapshot!(filters, command(&context)
|
||||||
|
.arg("local-less-than-or-equal-a<=1.2.3")
|
||||||
|
, @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because only package-a>1.2.3 is available and you require package-a<=1.2.3, we can conclude that the requirements are unsatisfiable.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// The version '1.2.3+foo' satisfies the constraint '<=1.2.3'.
|
||||||
|
assert_not_installed(
|
||||||
|
&context.venv,
|
||||||
|
"local_less_than_or_equal_a",
|
||||||
|
&context.temp_dir,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// The user requires any version of package `a` which only has prerelease versions
|
/// The user requires any version of package `a` which only has prerelease versions
|
||||||
/// available.
|
/// available.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -137,14 +137,49 @@ def main(scenarios: list[Path], snapshot_update: bool = True):
|
||||||
# We do not yet support local version identifiers
|
# We do not yet support local version identifiers
|
||||||
for scenario in data["scenarios"]:
|
for scenario in data["scenarios"]:
|
||||||
expected = scenario["expected"]
|
expected = scenario["expected"]
|
||||||
if (
|
if scenario["name"] in (
|
||||||
scenario["name"].startswith("local-")
|
"local-less-than-or-equal",
|
||||||
and scenario["name"] != "local-not-latest"
|
"local-simple",
|
||||||
|
"local-transitive-confounding",
|
||||||
|
"local-transitive-backtrack",
|
||||||
|
"local-used-with-sdist",
|
||||||
|
"local-used-without-sdist",
|
||||||
|
"local-transitive",
|
||||||
|
"local-transitive-less-than-or-equal",
|
||||||
):
|
):
|
||||||
expected["satisfiable"] = False
|
expected["satisfiable"] = False
|
||||||
expected[
|
expected[
|
||||||
"explanation"
|
"explanation"
|
||||||
] = "We do not have correct behavior for local version identifiers yet"
|
] = "We do not have correct behavior for local version identifiers yet"
|
||||||
|
elif scenario["name"] == "local-greater-than":
|
||||||
|
expected["satisfiable"] = True
|
||||||
|
expected["packages"] = [
|
||||||
|
{
|
||||||
|
"name": "local-greater-than-a",
|
||||||
|
"version": "1.2.3+foo",
|
||||||
|
"module_name": "local_greater_than_a",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expected["explanation"] = (
|
||||||
|
"We do not have correct behavior for local version identifiers yet"
|
||||||
|
)
|
||||||
|
elif scenario["name"] == "local-transitive-greater-than":
|
||||||
|
expected["satisfiable"] = True
|
||||||
|
expected["packages"] = [
|
||||||
|
{
|
||||||
|
"name": "local-transitive-greater-than-a",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"module_name": "local_transitive_greater_than_a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "local-transitive-greater-than-b",
|
||||||
|
"version": "2.0.0+foo",
|
||||||
|
"module_name": "local_transitive_greater_than_b",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
expected["explanation"] = (
|
||||||
|
"We do not have correct behavior for local version identifiers yet"
|
||||||
|
)
|
||||||
|
|
||||||
# Split scenarios into `install` and `compile` cases
|
# Split scenarios into `install` and `compile` cases
|
||||||
install_scenarios = []
|
install_scenarios = []
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
chevron-blue
|
chevron-blue
|
||||||
packse>=0.3.6
|
packse>=0.3.9
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# This file was autogenerated by uv via the following command:
|
# This file was autogenerated by uv via the following command:
|
||||||
# uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt --refresh-package packse --upgrade
|
# uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt --refresh-package packse
|
||||||
certifi==2024.2.2
|
certifi==2024.2.2
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==3.3.2
|
charset-normalizer==3.3.2
|
||||||
|
|
@ -14,7 +14,7 @@ hatchling==1.21.1
|
||||||
# via packse
|
# via packse
|
||||||
idna==3.6
|
idna==3.6
|
||||||
# via requests
|
# via requests
|
||||||
importlib-metadata==7.0.1
|
importlib-metadata==7.0.2
|
||||||
# via twine
|
# via twine
|
||||||
jaraco-classes==3.3.1
|
jaraco-classes==3.3.1
|
||||||
# via keyring
|
# via keyring
|
||||||
|
|
@ -30,9 +30,9 @@ msgspec==0.18.6
|
||||||
# via packse
|
# via packse
|
||||||
nh3==0.2.15
|
nh3==0.2.15
|
||||||
# via readme-renderer
|
# via readme-renderer
|
||||||
packaging==23.2
|
packaging==24.0
|
||||||
# via hatchling
|
# via hatchling
|
||||||
packse==0.3.7
|
packse==0.3.9
|
||||||
pathspec==0.12.1
|
pathspec==0.12.1
|
||||||
# via hatchling
|
# via hatchling
|
||||||
pkginfo==1.10.0
|
pkginfo==1.10.0
|
||||||
|
|
@ -55,7 +55,7 @@ rfc3986==2.0.0
|
||||||
# via twine
|
# via twine
|
||||||
rich==13.7.1
|
rich==13.7.1
|
||||||
# via twine
|
# via twine
|
||||||
setuptools==69.1.1
|
setuptools==69.2.0
|
||||||
# via packse
|
# via packse
|
||||||
trove-classifiers==2024.3.3
|
trove-classifiers==2024.3.3
|
||||||
# via hatchling
|
# via hatchling
|
||||||
|
|
@ -65,5 +65,5 @@ urllib3==2.2.1
|
||||||
# via
|
# via
|
||||||
# requests
|
# requests
|
||||||
# twine
|
# twine
|
||||||
zipp==3.17.0
|
zipp==3.18.0
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue