mirror of https://github.com/astral-sh/uv
Improve handling of package conflicts
This commit is contained in:
parent
827708e67e
commit
88eb0e94c4
|
|
@ -3,7 +3,7 @@ use tracing::trace;
|
||||||
use uv_distribution_types::{RequiresPython, RequiresPythonRange};
|
use uv_distribution_types::{RequiresPython, RequiresPythonRange};
|
||||||
use uv_pep440::VersionSpecifiers;
|
use uv_pep440::VersionSpecifiers;
|
||||||
use uv_pep508::{MarkerEnvironment, MarkerTree};
|
use uv_pep508::{MarkerEnvironment, MarkerTree};
|
||||||
use uv_pypi_types::{ConflictItem, ConflictItemRef, ResolverMarkerEnvironment};
|
use uv_pypi_types::{ConflictItem, ConflictItemRef, ConflictKindRef, ResolverMarkerEnvironment};
|
||||||
|
|
||||||
use crate::pubgrub::{PubGrubDependency, PubGrubPackage};
|
use crate::pubgrub::{PubGrubDependency, PubGrubPackage};
|
||||||
use crate::resolver::ForkState;
|
use crate::resolver::ForkState;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ use uv_pep508::{
|
||||||
MarkerEnvironment, MarkerExpression, MarkerOperator, MarkerTree, MarkerValueString,
|
MarkerEnvironment, MarkerExpression, MarkerOperator, MarkerTree, MarkerValueString,
|
||||||
};
|
};
|
||||||
use uv_platform_tags::Tags;
|
use uv_platform_tags::Tags;
|
||||||
use uv_pypi_types::{ConflictItem, ConflictItemRef, Conflicts, VerbatimParsedUrl};
|
use uv_pypi_types::{ConflictItem, ConflictItemRef, ConflictKindRef, Conflicts, VerbatimParsedUrl};
|
||||||
use uv_types::{BuildContext, HashStrategy, InstalledPackagesProvider};
|
use uv_types::{BuildContext, HashStrategy, InstalledPackagesProvider};
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
|
|
||||||
|
|
@ -3637,7 +3637,7 @@ impl Forks {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a fork that excludes ALL extras.
|
// Create a fork that excludes ALL conflicts.
|
||||||
if let Some(fork_none) = fork.clone().filter(set.iter().cloned().map(Err)) {
|
if let Some(fork_none) = fork.clone().filter(set.iter().cloned().map(Err)) {
|
||||||
new.push(fork_none);
|
new.push(fork_none);
|
||||||
}
|
}
|
||||||
|
|
@ -3770,6 +3770,17 @@ impl Fork {
|
||||||
};
|
};
|
||||||
if self.env.included_by_group(conflicting_item) {
|
if self.env.included_by_group(conflicting_item) {
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
match conflicting_item.kind() {
|
||||||
|
// We should not filter entire projects unless they're a top-level dependency
|
||||||
|
ConflictKindRef::Project => {
|
||||||
|
if dep.parent.is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConflictKindRef::Group(_) => {}
|
||||||
|
ConflictKindRef::Extra(_) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(conflicting_item) = dep.conflicting_item() {
|
if let Some(conflicting_item) = dep.conflicting_item() {
|
||||||
self.conflicts.remove(&conflicting_item);
|
self.conflicts.remove(&conflicting_item);
|
||||||
|
|
|
||||||
|
|
@ -2768,14 +2768,14 @@ fn lock_conflicting_project_basic1() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 3 packages in [TIME]
|
Resolved 3 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = context.read("uv.lock");
|
let lock = context.read("uv.lock");
|
||||||
|
|
||||||
|
|
@ -2866,7 +2866,7 @@ fn lock_conflicting_project_basic1() -> Result<()> {
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: Group `foo` and the project are incompatible with the declared conflicts: {`project:foo`, the project}
|
error: Group `foo` and package `project` are incompatible with the declared conflicts: {`project:foo`, project}
|
||||||
");
|
");
|
||||||
// Another install, but this time with `--only-group=foo`,
|
// Another install, but this time with `--only-group=foo`,
|
||||||
// which excludes the project and is thus okay.
|
// which excludes the project and is thus okay.
|
||||||
|
|
@ -2941,14 +2941,14 @@ fn lock_conflicting_workspace_members() -> Result<()> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Lock should succeed because we declared the conflict
|
// Lock should succeed because we declared the conflict
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 4 packages in [TIME]
|
Resolved 4 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = context.read("uv.lock");
|
let lock = context.read("uv.lock");
|
||||||
|
|
||||||
|
|
@ -3118,6 +3118,82 @@ fn lock_conflicting_workspace_members_depends_direct() -> Result<()> {
|
||||||
|
|
||||||
// This should fail to resolve, because these conflict
|
// This should fail to resolve, because these conflict
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because subexample depends on sortedcontainers==2.4.0 and example depends on sortedcontainers==2.3.0, we can conclude that example and subexample are incompatible.
|
||||||
|
And because example depends on subexample and your workspace requires example, we can conclude that your workspace's requirements are unsatisfiable.
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`lock_conflicting_workspace_members_depends_direct`], but the root project depends on the
|
||||||
|
/// conflicting workspace member via a direct optional dependency.
|
||||||
|
#[test]
|
||||||
|
fn lock_conflicting_workspace_members_depends_direct_extra() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "example"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = ["sortedcontainers==2.3.0"]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
foo = ["subexample"]
|
||||||
|
|
||||||
|
[tool.uv.workspace]
|
||||||
|
members = ["subexample"]
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
conflicts = [
|
||||||
|
[
|
||||||
|
{ package = "example" },
|
||||||
|
{ package = "example", extra = "foo"},
|
||||||
|
{ package = "subexample" },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
subexample = { workspace = true }
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["example"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Create the subproject
|
||||||
|
let subproject_dir = context.temp_dir.child("subexample");
|
||||||
|
subproject_dir.create_dir_all()?;
|
||||||
|
|
||||||
|
let sub_pyproject_toml = subproject_dir.child("pyproject.toml");
|
||||||
|
sub_pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "subexample"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = ["sortedcontainers==2.4.0"]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// This should succeed, because the conflict is optional
|
||||||
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -3127,6 +3203,7 @@ fn lock_conflicting_workspace_members_depends_direct() -> Result<()> {
|
||||||
");
|
");
|
||||||
|
|
||||||
let lock = context.read("uv.lock");
|
let lock = context.read("uv.lock");
|
||||||
|
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
filters => context.filters(),
|
filters => context.filters(),
|
||||||
}, {
|
}, {
|
||||||
|
|
@ -3136,6 +3213,7 @@ fn lock_conflicting_workspace_members_depends_direct() -> Result<()> {
|
||||||
revision = 2
|
revision = 2
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
conflicts = [[
|
conflicts = [[
|
||||||
|
{ package = "example", extra = "foo" },
|
||||||
{ package = "example" },
|
{ package = "example" },
|
||||||
{ package = "subexample" },
|
{ package = "subexample" },
|
||||||
]]
|
]]
|
||||||
|
|
@ -3154,14 +3232,15 @@ fn lock_conflicting_workspace_members_depends_direct() -> Result<()> {
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "sortedcontainers", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'project-7-example'" },
|
{ name = "sortedcontainers", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-7-example-foo' or extra == 'project-7-example'" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "sortedcontainers", specifier = "==2.3.0" },
|
{ name = "sortedcontainers", specifier = "==2.3.0" },
|
||||||
{ name = "subexample", editable = "subexample" },
|
{ name = "subexample", marker = "extra == 'foo'", editable = "subexample" },
|
||||||
]
|
]
|
||||||
|
provides-extras = ["foo"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sortedcontainers"
|
name = "sortedcontainers"
|
||||||
|
|
@ -3186,27 +3265,116 @@ fn lock_conflicting_workspace_members_depends_direct() -> Result<()> {
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { editable = "subexample" }
|
source = { editable = "subexample" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "sortedcontainers", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'project-10-subexample'" },
|
{ name = "sortedcontainers", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'project-10-subexample' or (extra == 'extra-7-example-foo' and extra == 'project-7-example')" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "sortedcontainers", specifier = "==2.4.0" }]
|
requires-dist = [{ name = "sortedcontainers", specifier = "==2.4.0" }]
|
||||||
"#)});
|
"#
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Syncing should fail too
|
// Install from the lockfile
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 4 packages in [TIME]
|
|
||||||
Prepared 2 packages in [TIME]
|
Prepared 2 packages in [TIME]
|
||||||
Installed 2 packages in [TIME]
|
Installed 2 packages in [TIME]
|
||||||
+ example==0.1.0 (from file://[TEMP_DIR]/)
|
+ example==0.1.0 (from file://[TEMP_DIR]/)
|
||||||
+ sortedcontainers==2.3.0
|
+ sortedcontainers==2.3.0
|
||||||
");
|
");
|
||||||
|
|
||||||
|
// Attempt to install with the extra selected
|
||||||
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--extra").arg("foo"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Extra `foo` and package `example` are incompatible with the declared conflicts: {`example[foo]`, example, subexample}
|
||||||
|
");
|
||||||
|
|
||||||
|
// Install just the child package
|
||||||
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--package").arg("subexample"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Prepared 2 packages in [TIME]
|
||||||
|
Uninstalled 2 packages in [TIME]
|
||||||
|
Installed 2 packages in [TIME]
|
||||||
|
- example==0.1.0 (from file://[TEMP_DIR]/)
|
||||||
|
- sortedcontainers==2.3.0
|
||||||
|
+ sortedcontainers==2.4.0
|
||||||
|
+ subexample==0.1.0 (from file://[TEMP_DIR]/subexample)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Install with just development dependencies
|
||||||
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--only-dev"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Uninstalled 2 packages in [TIME]
|
||||||
|
- sortedcontainers==2.4.0
|
||||||
|
- subexample==0.1.0 (from file://[TEMP_DIR]/subexample)
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mar
|
||||||
|
#[test]
|
||||||
|
fn lock_conflicting_extras_depends() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "example"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
foo = ["sortedcontainers==2.3.0", "example[bar]"]
|
||||||
|
bar = ["sortedcontainers==2.4.0"]
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
conflicts = [
|
||||||
|
[
|
||||||
|
{ extra = "foo" },
|
||||||
|
{ extra = "bar" },
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["example"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// This should fail to resolve, because the extras are always required together
|
||||||
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
× No solution found when resolving dependencies:
|
||||||
|
╰─▶ Because example[foo] depends on sortedcontainers==2.3.0 and sortedcontainers==2.4.0, we can conclude that example[foo]'s requirements are unsatisfiable.
|
||||||
|
And because your project requires example[foo], we can conclude that your project's requirements are unsatisfiable.
|
||||||
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3373,7 +3541,7 @@ fn lock_conflicting_project_basic2() -> Result<()> {
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: Group `foo` and the project are incompatible with the declared conflicts: {`example:foo`, the project}
|
error: Group `foo` and package `example` are incompatible with the declared conflicts: {`example:foo`, example}
|
||||||
");
|
");
|
||||||
// Another install, but this time with `--only-group=foo`,
|
// Another install, but this time with `--only-group=foo`,
|
||||||
// which excludes the project and is thus okay.
|
// which excludes the project and is thus okay.
|
||||||
|
|
|
||||||
|
|
@ -1049,23 +1049,23 @@ fn extra_unconditional() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 6 packages in [TIME]
|
Resolved 6 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
// This should error since we're enabling two conflicting extras.
|
// This should error since we're enabling two conflicting extras.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 2
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: Found conflicting extras `proxy1[extra1]` and `proxy1[extra2]` enabled simultaneously
|
error: Found conflicting extras `proxy1[extra1]` and `proxy1[extra2]` enabled simultaneously
|
||||||
"###);
|
");
|
||||||
|
|
||||||
root_pyproject_toml.write_str(
|
root_pyproject_toml.write_str(
|
||||||
r#"
|
r#"
|
||||||
|
|
@ -1084,14 +1084,14 @@ fn extra_unconditional() -> Result<()> {
|
||||||
proxy1 = { workspace = true }
|
proxy1 = { workspace = true }
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 6 packages in [TIME]
|
Resolved 6 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
// This is fine because we are only enabling one
|
// This is fine because we are only enabling one
|
||||||
// extra, and thus, there is no conflict.
|
// extra, and thus, there is no conflict.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||||
|
|
@ -1126,17 +1126,17 @@ fn extra_unconditional() -> Result<()> {
|
||||||
proxy1 = { workspace = true }
|
proxy1 = { workspace = true }
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 6 packages in [TIME]
|
Resolved 6 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
// This is fine because we are only enabling one
|
// This is fine because we are only enabling one
|
||||||
// extra, and thus, there is no conflict.
|
// extra, and thus, there is no conflict.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -1147,7 +1147,7 @@ fn extra_unconditional() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- anyio==4.1.0
|
- anyio==4.1.0
|
||||||
+ anyio==4.2.0
|
+ anyio==4.2.0
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1202,14 +1202,14 @@ fn extra_unconditional_non_conflicting() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 5 packages in [TIME]
|
Resolved 5 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
// This *should* install `anyio==4.1.0`, but when this
|
// This *should* install `anyio==4.1.0`, but when this
|
||||||
// test was initially written, it didn't. This was because
|
// test was initially written, it didn't. This was because
|
||||||
|
|
@ -1425,26 +1425,26 @@ fn extra_unconditional_non_local_conflict() -> Result<()> {
|
||||||
// that can never be installed! Namely, because two different
|
// that can never be installed! Namely, because two different
|
||||||
// conflicting extras are enabled unconditionally in all
|
// conflicting extras are enabled unconditionally in all
|
||||||
// configurations.
|
// configurations.
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 6 packages in [TIME]
|
Resolved 6 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
// This should fail. If it doesn't and we generated a lock
|
// This should fail. If it doesn't and we generated a lock
|
||||||
// file above, then this will likely result in the installation
|
// file above, then this will likely result in the installation
|
||||||
// of two different versions of the same package.
|
// of two different versions of the same package.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 2
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
error: Found conflicting extras `c[x1]` and `c[x2]` enabled simultaneously
|
error: Found conflicting extras `c[x1]` and `c[x2]` enabled simultaneously
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1711,14 +1711,14 @@ fn group_basic() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 3 packages in [TIME]
|
Resolved 3 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = context.read("uv.lock");
|
let lock = context.read("uv.lock");
|
||||||
|
|
||||||
|
|
@ -1866,14 +1866,14 @@ fn group_default() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 3 packages in [TIME]
|
Resolved 3 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = context.read("uv.lock");
|
let lock = context.read("uv.lock");
|
||||||
|
|
||||||
|
|
@ -2398,14 +2398,14 @@ fn multiple_sources_index_disjoint_groups() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 4 packages in [TIME]
|
Resolved 4 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
|
|
||||||
|
|
@ -2881,7 +2881,7 @@ fn non_optional_dependency_extra() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -2891,7 +2891,7 @@ fn non_optional_dependency_extra() -> Result<()> {
|
||||||
Prepared 1 package in [TIME]
|
Prepared 1 package in [TIME]
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2928,7 +2928,7 @@ fn non_optional_dependency_group() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -2938,7 +2938,7 @@ fn non_optional_dependency_group() -> Result<()> {
|
||||||
Prepared 1 package in [TIME]
|
Prepared 1 package in [TIME]
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2978,7 +2978,7 @@ fn non_optional_dependency_mixed() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -2988,7 +2988,7 @@ fn non_optional_dependency_mixed() -> Result<()> {
|
||||||
Prepared 1 package in [TIME]
|
Prepared 1 package in [TIME]
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -3178,7 +3178,7 @@ fn shared_optional_dependency_group1() -> Result<()> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--group=baz").arg("--group=foo"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--group=baz").arg("--group=foo"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -3190,7 +3190,7 @@ fn shared_optional_dependency_group1() -> Result<()> {
|
||||||
+ anyio==4.3.0
|
+ anyio==4.3.0
|
||||||
+ idna==3.5
|
+ idna==3.5
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
|
|
@ -3605,7 +3605,7 @@ fn shared_optional_dependency_group2() -> Result<()> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--group=bar"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--group=bar"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -3617,7 +3617,7 @@ fn shared_optional_dependency_group2() -> Result<()> {
|
||||||
+ anyio==4.3.0
|
+ anyio==4.3.0
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
|
|
@ -3895,7 +3895,7 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -3907,7 +3907,7 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
+ anyio==4.3.0
|
+ anyio==4.3.0
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
|
|
@ -3996,7 +3996,7 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
|
|
||||||
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
||||||
// So this should remove `idna==3.6` installed above.
|
// So this should remove `idna==3.6` installed above.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--extra=foo"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--extra=foo"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4008,9 +4008,9 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- idna==3.6
|
- idna==3.6
|
||||||
+ idna==3.5
|
+ idna==3.5
|
||||||
"###);
|
");
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--extra=bar"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--extra=bar"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4021,9 +4021,9 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- idna==3.5
|
- idna==3.5
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
"###);
|
");
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4031,7 +4031,7 @@ fn shared_dependency_extra() -> Result<()> {
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 5 packages in [TIME]
|
Resolved 5 packages in [TIME]
|
||||||
Audited 3 packages in [TIME]
|
Audited 3 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -4070,7 +4070,7 @@ fn shared_dependency_group() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4082,7 +4082,7 @@ fn shared_dependency_group() -> Result<()> {
|
||||||
+ anyio==4.3.0
|
+ anyio==4.3.0
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
|
|
@ -4246,7 +4246,7 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4258,7 +4258,7 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
+ anyio==4.3.0
|
+ anyio==4.3.0
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
+ sniffio==1.3.1
|
+ sniffio==1.3.1
|
||||||
"###);
|
");
|
||||||
|
|
||||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
insta::with_settings!({
|
insta::with_settings!({
|
||||||
|
|
@ -4351,7 +4351,7 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
|
|
||||||
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
// This shouldn't install two versions of `idna`, only one, `idna==3.5`.
|
||||||
// So this should remove `idna==3.6` installed above.
|
// So this should remove `idna==3.6` installed above.
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--extra=foo"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--extra=foo"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4363,9 +4363,9 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- idna==3.6
|
- idna==3.6
|
||||||
+ idna==3.5
|
+ idna==3.5
|
||||||
"###);
|
");
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync().arg("--group=bar"), @r###"
|
uv_snapshot!(context.filters(), context.sync().arg("--group=bar"), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4376,9 +4376,9 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- idna==3.5
|
- idna==3.5
|
||||||
+ idna==3.6
|
+ idna==3.6
|
||||||
"###);
|
");
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
@ -4386,7 +4386,7 @@ fn shared_dependency_mixed() -> Result<()> {
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 5 packages in [TIME]
|
Resolved 5 packages in [TIME]
|
||||||
Audited 3 packages in [TIME]
|
Audited 3 packages in [TIME]
|
||||||
"###);
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue