Skip to content

Commit 77df01f

Browse files
authored
Include more sources to avoid lowest bound warning (#9644)
In #8155 (comment), 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)
1 parent 7939d3f commit 77df01f

File tree

3 files changed

+72
-5
lines changed

3 files changed

+72
-5
lines changed

crates/uv-resolver/src/resolution/output.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ impl ResolverOutput {
190190
graph.retain_nodes(|graph, node| !graph[node].marker().is_false());
191191

192192
if matches!(resolution_strategy, ResolutionStrategy::Lowest) {
193-
report_missing_lower_bounds(&graph, &mut diagnostics);
193+
report_missing_lower_bounds(&graph, &mut diagnostics, constraints, overrides);
194194
}
195195

196196
let output = Self {
@@ -879,6 +879,8 @@ impl From<ResolverOutput> for uv_distribution_types::Resolution {
879879
fn report_missing_lower_bounds(
880880
graph: &Graph<ResolutionGraphNode, UniversalMarker>,
881881
diagnostics: &mut Vec<ResolutionDiagnostic>,
882+
constraints: &Constraints,
883+
overrides: &Overrides,
882884
) {
883885
for node_index in graph.node_indices() {
884886
let ResolutionGraphNode::Dist(dist) = graph.node_weight(node_index).unwrap() else {
@@ -892,7 +894,8 @@ fn report_missing_lower_bounds(
892894
// have to drop.
893895
continue;
894896
}
895-
if !has_lower_bound(node_index, dist.name(), graph) {
897+
898+
if !has_lower_bound(node_index, dist.name(), graph, constraints, overrides) {
896899
diagnostics.push(ResolutionDiagnostic::MissingLowerBound {
897900
package_name: dist.name().clone(),
898901
});
@@ -905,6 +908,8 @@ fn has_lower_bound(
905908
node_index: NodeIndex,
906909
package_name: &PackageName,
907910
graph: &Graph<ResolutionGraphNode, UniversalMarker>,
911+
constraints: &Constraints,
912+
overrides: &Overrides,
908913
) -> bool {
909914
for neighbor_index in graph.neighbors_directed(node_index, Direction::Incoming) {
910915
let neighbor_dist = match graph.node_weight(neighbor_index).unwrap() {
@@ -931,7 +936,10 @@ fn has_lower_bound(
931936
for requirement in metadata
932937
.requires_dist
933938
.iter()
939+
// These bounds sources are missing from the graph.
934940
.chain(metadata.dependency_groups.values().flatten())
941+
.chain(constraints.requirements())
942+
.chain(overrides.requirements())
935943
{
936944
if requirement.name != *package_name {
937945
continue;

crates/uv-resolver/src/resolver/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2277,11 +2277,11 @@ impl ForkState {
22772277
for_version: &Version,
22782278
urls: &Urls,
22792279
indexes: &Indexes,
2280-
mut dependencies: Vec<PubGrubDependency>,
2280+
dependencies: Vec<PubGrubDependency>,
22812281
git: &GitResolver,
22822282
resolution_strategy: &ResolutionStrategy,
22832283
) -> Result<(), ResolveError> {
2284-
for dependency in &mut dependencies {
2284+
for dependency in &dependencies {
22852285
let PubGrubDependency {
22862286
package,
22872287
version,
@@ -2313,6 +2313,22 @@ impl ForkState {
23132313
// A dependency from the root package or requirements.txt.
23142314
debug!("Adding direct dependency: {package}{version}");
23152315

2316+
let name = package.name_no_root().unwrap();
2317+
2318+
// Catch cases where we pass a package once by name with extras and then once as
2319+
// URL for the specific distribution.
2320+
has_url = has_url
2321+
|| dependencies
2322+
.iter()
2323+
.filter(|other_dep| *other_dep != dependency)
2324+
.filter(|other_dep| {
2325+
other_dep
2326+
.package
2327+
.name()
2328+
.is_some_and(|other_name| other_name == name)
2329+
})
2330+
.any(|other_dep| other_dep.url.is_some());
2331+
23162332
// Warn the user if a direct dependency lacks a lower bound in `--lowest` resolution.
23172333
let missing_lower_bound = version
23182334
.bounding_range()
@@ -2327,7 +2343,6 @@ impl ForkState {
23272343
"The direct dependency `{name}` is unpinned. \
23282344
Consider setting a lower bound when using `--resolution lowest` \
23292345
to avoid using outdated versions.",
2330-
name = package.name_no_root().unwrap(),
23312346
);
23322347
}
23332348
}

crates/uv/tests/it/lock.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19009,3 +19009,47 @@ fn lock_recursive_extra() -> Result<()> {
1900919009

1901019010
Ok(())
1901119011
}
19012+
19013+
/// Don't show an unpinned lower bound warning if the package was provided both by name and by URL,
19014+
/// or if the package was part of a constraints files.
19015+
///
19016+
/// See <https://github.com/astral-sh/uv/issues/8155>, the original example was:
19017+
/// ```
19018+
/// uv pip install dist/pymatgen-2024.10.3.tar.gz pymatgen[ci,optional] --resolution=lowest
19019+
/// ```
19020+
#[test]
19021+
fn no_lowest_warning_with_name_and_url() -> Result<()> {
19022+
let context = TestContext::new("3.12");
19023+
19024+
let pyproject_toml = context.temp_dir.child("pyproject.toml");
19025+
pyproject_toml.write_str(
19026+
r#"
19027+
[project]
19028+
name = "project"
19029+
version = "0.1.0"
19030+
requires-python = ">=3.12"
19031+
dependencies = [
19032+
"anyio[trio]",
19033+
"anyio @ https://files.pythonhosted.org/packages/e6/e3/c4c8d473d6780ef1853d630d581f70d655b4f8d7553c6997958c283039a2/anyio-4.4.0.tar.gz"
19034+
]
19035+
19036+
[tool.uv]
19037+
constraint-dependencies = [
19038+
"sortedcontainers==2.4.0",
19039+
"outcome==1.3.0.post0",
19040+
"pycparser==2.20",
19041+
]
19042+
"#,
19043+
)?;
19044+
19045+
uv_snapshot!(context.filters(), context.lock(), @r###"
19046+
success: true
19047+
exit_code: 0
19048+
----- stdout -----
19049+
19050+
----- stderr -----
19051+
Resolved 10 packages in [TIME]
19052+
"###);
19053+
19054+
Ok(())
19055+
}

0 commit comments

Comments
 (0)