mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Consolidate UnusableDependencies
into a generic Unavailable
incompatibility (#1088)
Requires https://github.com/zanieb/pubgrub/pull/20 In short, `UnusableDependencies` can be generalized into `Unavailable` which encompasses incompatibilities where a package range which is unusable for some inherent reason as well as when its dependencies are unusable. We can eventually use this to track more incompatibilities in the solver. I made the reason string required because I can't see a case where we should leave it out. Additionally, this improves the display of conflicts in the root requirements.
This commit is contained in:
parent
091f8e09ff
commit
ed1ac640b9
7 changed files with 54 additions and 49 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2246,7 +2246,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "pubgrub"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/zanieb/pubgrub?rev=0e02ea9fc8d021fb6a6b9e77b09ade4332068f42#0e02ea9fc8d021fb6a6b9e77b09ade4332068f42"
|
||||
source = "git+https://github.com/zanieb/pubgrub?rev=7a573e3902ff338abdcf3b87682e4c6d04845f2f#7a573e3902ff338abdcf3b87682e4c6d04845f2f"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"log",
|
||||
|
|
|
@ -53,7 +53,7 @@ owo-colors = { version = "3.5.0" }
|
|||
petgraph = { version = "0.6.4" }
|
||||
platform-info = { version = "2.0.2" }
|
||||
plist = { version = "1.6.0" }
|
||||
pubgrub = { git = "https://github.com/zanieb/pubgrub", rev = "0e02ea9fc8d021fb6a6b9e77b09ade4332068f42" }
|
||||
pubgrub = { git = "https://github.com/zanieb/pubgrub", rev = "7a573e3902ff338abdcf3b87682e4c6d04845f2f" }
|
||||
pyo3 = { version = "0.20.2" }
|
||||
pyo3-log = { version = "0.9.0"}
|
||||
pyproject-toml = { version = "0.8.1" }
|
||||
|
|
|
@ -49,10 +49,10 @@ pub enum ResolveError {
|
|||
#[error("~= operator requires at least two release segments: {0}")]
|
||||
InvalidTildeEquals(pep440_rs::VersionSpecifier),
|
||||
|
||||
#[error("Conflicting URLs for package `{0}`:\n- {1}\n- {2}")]
|
||||
#[error("There are conflicting URLs for package `{0}`:\n- {1}\n- {2}")]
|
||||
ConflictingUrls(PackageName, String, String),
|
||||
|
||||
#[error("Conflicting versions for `{0}`: {1}")]
|
||||
#[error("There are conflicting versions for `{0}`: {1}")]
|
||||
ConflictingVersions(String, String),
|
||||
|
||||
#[error("Package `{0}` attempted to resolve via URL: {1}. URL dependencies must be expressed as direct requirements or constraints. Consider adding `{0} @ {1}` to your dependencies or constraints file.")]
|
||||
|
|
|
@ -96,32 +96,18 @@ impl ReportFormatter<PubGrubPackage, Range<Version>> for PubGrubReportFormatter<
|
|||
}
|
||||
}
|
||||
}
|
||||
External::UnavailableDependencies(package, set) => {
|
||||
let set = self.simplify_set(set, package);
|
||||
format!(
|
||||
"dependencies of {}are unavailable",
|
||||
Padded::new("", &PackageRange::compatibility(package, &set), " ")
|
||||
)
|
||||
}
|
||||
External::UnusableDependencies(package, set, reason) => {
|
||||
if let Some(reason) = reason {
|
||||
if matches!(package, PubGrubPackage::Root(_)) {
|
||||
format!("{package} dependencies are unusable: {reason}")
|
||||
} else {
|
||||
let set = self.simplify_set(set, package);
|
||||
format!(
|
||||
"dependencies of {}are unusable: {reason}",
|
||||
Padded::new("", &PackageRange::compatibility(package, &set), " ")
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let set = self.simplify_set(set, package);
|
||||
format!(
|
||||
"dependencies of {}are unusable",
|
||||
Padded::new("", &PackageRange::compatibility(package, &set), " ")
|
||||
)
|
||||
External::Unavailable(package, set, reason) => match package {
|
||||
PubGrubPackage::Root(Some(name)) => {
|
||||
format!("{name} cannot be used because {reason}")
|
||||
}
|
||||
}
|
||||
PubGrubPackage::Root(None) => {
|
||||
format!("your requirements cannot be used because {reason}")
|
||||
}
|
||||
_ => format!(
|
||||
"{}is unusable because {reason}",
|
||||
Padded::new("", &PackageRange::compatibility(package, set), " ")
|
||||
),
|
||||
},
|
||||
External::FromDependencyOf(package, package_set, dependency, dependency_set) => {
|
||||
let package_set = self.simplify_set(package_set, package);
|
||||
let dependency_set = self.simplify_set(dependency_set, dependency);
|
||||
|
@ -403,8 +389,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
}
|
||||
}
|
||||
External::NotRoot(..) => {}
|
||||
External::UnavailableDependencies(..) => {}
|
||||
External::UnusableDependencies(..) => {}
|
||||
External::Unavailable(..) => {}
|
||||
External::FromDependencyOf(..) => {}
|
||||
},
|
||||
DerivationTree::Derived(derived) => {
|
||||
|
|
|
@ -335,22 +335,30 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
.get_dependencies(package, &version, &mut priorities, request_sink)
|
||||
.await?
|
||||
{
|
||||
Dependencies::Unusable(reason) => {
|
||||
state.add_incompatibility(Incompatibility::unusable_dependencies(
|
||||
Dependencies::Unavailable(reason) => {
|
||||
let message = {
|
||||
if matches!(package, PubGrubPackage::Root(_)) {
|
||||
// Including front-matter for the root package is redundant
|
||||
reason.clone()
|
||||
} else {
|
||||
format!("its dependencies are unusable because {reason}")
|
||||
}
|
||||
};
|
||||
state.add_incompatibility(Incompatibility::unavailable(
|
||||
package.clone(),
|
||||
version.clone(),
|
||||
reason.clone(),
|
||||
message,
|
||||
));
|
||||
continue;
|
||||
}
|
||||
Dependencies::Known(constraints) if constraints.contains_key(package) => {
|
||||
Dependencies::Available(constraints) if constraints.contains_key(package) => {
|
||||
return Err(PubGrubError::SelfDependency {
|
||||
package: package.clone(),
|
||||
version: version.clone(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
Dependencies::Known(constraints) => constraints,
|
||||
Dependencies::Available(constraints) => constraints,
|
||||
};
|
||||
|
||||
// Add that package and version if the dependencies are not problematic.
|
||||
|
@ -588,7 +596,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
| ResolveError::ConflictingUrls(..)),
|
||||
) = constraints
|
||||
{
|
||||
return Ok(Dependencies::Unusable(Some(err.to_string())));
|
||||
return Ok(Dependencies::Unavailable(uncapitalize(err.to_string())));
|
||||
}
|
||||
let mut constraints = constraints?;
|
||||
|
||||
|
@ -610,10 +618,12 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
);
|
||||
}
|
||||
|
||||
Ok(Dependencies::Known(constraints.into()))
|
||||
Ok(Dependencies::Available(constraints.into()))
|
||||
}
|
||||
|
||||
PubGrubPackage::Python(_) => Ok(Dependencies::Known(DependencyConstraints::default())),
|
||||
PubGrubPackage::Python(_) => {
|
||||
Ok(Dependencies::Available(DependencyConstraints::default()))
|
||||
}
|
||||
|
||||
PubGrubPackage::Package(package_name, extra, url) => {
|
||||
// Wait for the metadata to be available.
|
||||
|
@ -640,7 +650,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
version.clone(),
|
||||
);
|
||||
constraints.insert(PubGrubPackage::Python(PubGrubPython::Target), version);
|
||||
return Ok(Dependencies::Known(constraints));
|
||||
return Ok(Dependencies::Available(constraints));
|
||||
}
|
||||
|
||||
let entry = self.index.distributions.wait(&package_id).await?;
|
||||
|
@ -670,7 +680,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
|
|||
);
|
||||
}
|
||||
|
||||
Ok(Dependencies::Known(constraints.into()))
|
||||
Ok(Dependencies::Available(constraints.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -877,8 +887,16 @@ enum Response {
|
|||
/// For each [Package] there is a set of versions allowed as a dependency.
|
||||
#[derive(Clone)]
|
||||
enum Dependencies {
|
||||
/// Package dependencies are not usable
|
||||
Unusable(Option<String>),
|
||||
/// Package dependencies are not available.
|
||||
Unavailable(String),
|
||||
/// Container for all available package versions.
|
||||
Known(DependencyConstraints<PubGrubPackage, Range<Version>>),
|
||||
Available(DependencyConstraints<PubGrubPackage, Range<Version>>),
|
||||
}
|
||||
|
||||
fn uncapitalize<T: AsRef<str>>(string: T) -> String {
|
||||
let mut chars = string.as_ref().chars();
|
||||
match chars.next() {
|
||||
None => String::new(),
|
||||
Some(first) => first.to_lowercase().chain(chars).collect(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1516,7 +1516,8 @@ fn conflicting_repeated_url_dependency_version_mismatch() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ root dependencies are unusable: Conflicting URLs for package `werkzeug`:
|
||||
╰─▶ your requirements cannot be used because there are conflicting URLs for
|
||||
package `werkzeug`:
|
||||
- https://files.pythonhosted.org/packages/bd/24/11c3ea5a7e866bf2d97f0501d0b4b1c9bbeade102bb4b588f0d2919a5212/Werkzeug-2.0.1-py3-none-any.whl
|
||||
- https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl
|
||||
"###);
|
||||
|
@ -1556,7 +1557,8 @@ fn conflicting_repeated_url_dependency_version_match() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ root dependencies are unusable: Conflicting URLs for package `werkzeug`:
|
||||
╰─▶ your requirements cannot be used because there are conflicting URLs for
|
||||
package `werkzeug`:
|
||||
- git+https://github.com/pallets/werkzeug.git@2.0.0
|
||||
- https://files.pythonhosted.org/packages/ff/1d/960bb4017c68674a1cb099534840f18d3def3ce44aed12b5ed8b78e0153e/Werkzeug-2.0.0-py3-none-any.whl
|
||||
"###);
|
||||
|
@ -1900,8 +1902,8 @@ dependencies = ["django==5.0b1", "django==5.0a1"]
|
|||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ my-project dependencies are unusable: Conflicting versions for `django`:
|
||||
`django==5.0b1` does not intersect with `django==5.0a1`
|
||||
╰─▶ my-project cannot be used because there are conflicting versions for
|
||||
`django`: `django==5.0b1` does not intersect with `django==5.0a1`
|
||||
"###);
|
||||
});
|
||||
|
||||
|
|
|
@ -1245,7 +1245,7 @@ fn direct_incompatible_versions() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ root dependencies are unusable: Conflicting versions for `albatross`: `albatross==1.0.0` does not intersect with `albatross==2.0.0`
|
||||
╰─▶ your requirements cannot be used because there are conflicting versions for `albatross`: `albatross==1.0.0` does not intersect with `albatross==2.0.0`
|
||||
"###);
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue