Include more sources to avoid lowest bound warning (#9644)
In https://github.com/astral-sh/uv/issues/8155#issuecomment-2508969900, resolution lowest was complaining about missing lower bounds for a pacakge, even though the package had a URL, too: ``` uv pip install dist/pymatgen-2024.10.3.tar.gz pymatgen[ci,optional] --resolution=lowest ``` The error was raised from `pymatgen[ci,optional]`, because we were looking at it before looking at the "URL" `dist/pymatgen-2024.10.3.tar.gz`. I've also added constraints and overrides to the bounds lookup, since they are missing from the dependency graph. Fixes #8155 (again)
This commit is contained in:
@@ -190,7 +190,7 @@ impl ResolverOutput {
|
||||
graph.retain_nodes(|graph, node| !graph[node].marker().is_false());
|
||||
|
||||
if matches!(resolution_strategy, ResolutionStrategy::Lowest) {
|
||||
report_missing_lower_bounds(&graph, &mut diagnostics);
|
||||
report_missing_lower_bounds(&graph, &mut diagnostics, constraints, overrides);
|
||||
}
|
||||
|
||||
let output = Self {
|
||||
@@ -879,6 +879,8 @@ impl From<ResolverOutput> for uv_distribution_types::Resolution {
|
||||
fn report_missing_lower_bounds(
|
||||
graph: &Graph<ResolutionGraphNode, UniversalMarker>,
|
||||
diagnostics: &mut Vec<ResolutionDiagnostic>,
|
||||
constraints: &Constraints,
|
||||
overrides: &Overrides,
|
||||
) {
|
||||
for node_index in graph.node_indices() {
|
||||
let ResolutionGraphNode::Dist(dist) = graph.node_weight(node_index).unwrap() else {
|
||||
@@ -892,7 +894,8 @@ fn report_missing_lower_bounds(
|
||||
// have to drop.
|
||||
continue;
|
||||
}
|
||||
if !has_lower_bound(node_index, dist.name(), graph) {
|
||||
|
||||
if !has_lower_bound(node_index, dist.name(), graph, constraints, overrides) {
|
||||
diagnostics.push(ResolutionDiagnostic::MissingLowerBound {
|
||||
package_name: dist.name().clone(),
|
||||
});
|
||||
@@ -905,6 +908,8 @@ fn has_lower_bound(
|
||||
node_index: NodeIndex,
|
||||
package_name: &PackageName,
|
||||
graph: &Graph<ResolutionGraphNode, UniversalMarker>,
|
||||
constraints: &Constraints,
|
||||
overrides: &Overrides,
|
||||
) -> bool {
|
||||
for neighbor_index in graph.neighbors_directed(node_index, Direction::Incoming) {
|
||||
let neighbor_dist = match graph.node_weight(neighbor_index).unwrap() {
|
||||
@@ -931,7 +936,10 @@ fn has_lower_bound(
|
||||
for requirement in metadata
|
||||
.requires_dist
|
||||
.iter()
|
||||
// These bounds sources are missing from the graph.
|
||||
.chain(metadata.dependency_groups.values().flatten())
|
||||
.chain(constraints.requirements())
|
||||
.chain(overrides.requirements())
|
||||
{
|
||||
if requirement.name != *package_name {
|
||||
continue;
|
||||
|
||||
@@ -2277,11 +2277,11 @@ impl ForkState {
|
||||
for_version: &Version,
|
||||
urls: &Urls,
|
||||
indexes: &Indexes,
|
||||
mut dependencies: Vec<PubGrubDependency>,
|
||||
dependencies: Vec<PubGrubDependency>,
|
||||
git: &GitResolver,
|
||||
resolution_strategy: &ResolutionStrategy,
|
||||
) -> Result<(), ResolveError> {
|
||||
for dependency in &mut dependencies {
|
||||
for dependency in &dependencies {
|
||||
let PubGrubDependency {
|
||||
package,
|
||||
version,
|
||||
@@ -2313,6 +2313,22 @@ impl ForkState {
|
||||
// A dependency from the root package or requirements.txt.
|
||||
debug!("Adding direct dependency: {package}{version}");
|
||||
|
||||
let name = package.name_no_root().unwrap();
|
||||
|
||||
// Catch cases where we pass a package once by name with extras and then once as
|
||||
// URL for the specific distribution.
|
||||
has_url = has_url
|
||||
|| dependencies
|
||||
.iter()
|
||||
.filter(|other_dep| *other_dep != dependency)
|
||||
.filter(|other_dep| {
|
||||
other_dep
|
||||
.package
|
||||
.name()
|
||||
.is_some_and(|other_name| other_name == name)
|
||||
})
|
||||
.any(|other_dep| other_dep.url.is_some());
|
||||
|
||||
// Warn the user if a direct dependency lacks a lower bound in `--lowest` resolution.
|
||||
let missing_lower_bound = version
|
||||
.bounding_range()
|
||||
@@ -2327,7 +2343,6 @@ impl ForkState {
|
||||
"The direct dependency `{name}` is unpinned. \
|
||||
Consider setting a lower bound when using `--resolution lowest` \
|
||||
to avoid using outdated versions.",
|
||||
name = package.name_no_root().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19009,3 +19009,47 @@ fn lock_recursive_extra() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Don't show an unpinned lower bound warning if the package was provided both by name and by URL,
|
||||
/// or if the package was part of a constraints files.
|
||||
///
|
||||
/// See <https://github.com/astral-sh/uv/issues/8155>, the original example was:
|
||||
/// ```
|
||||
/// uv pip install dist/pymatgen-2024.10.3.tar.gz pymatgen[ci,optional] --resolution=lowest
|
||||
/// ```
|
||||
#[test]
|
||||
fn no_lowest_warning_with_name_and_url() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"anyio[trio]",
|
||||
"anyio @ https://files.pythonhosted.org/packages/e6/e3/c4c8d473d6780ef1853d630d581f70d655b4f8d7553c6997958c283039a2/anyio-4.4.0.tar.gz"
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
constraint-dependencies = [
|
||||
"sortedcontainers==2.4.0",
|
||||
"outcome==1.3.0.post0",
|
||||
"pycparser==2.20",
|
||||
]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 10 packages in [TIME]
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user