Warn about unconstrained direct deps in lowest resolution (#5142)

Warn when there is a direct dependency without a lower bound and
`--resolution lowest` is set.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
konsti 2024-07-18 05:44:53 +02:00 committed by GitHub
parent 4f73004f95
commit fbb00f701c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 1 deletions

View file

@ -38,6 +38,7 @@ use uv_distribution::{ArchiveMetadata, DistributionDatabase};
use uv_git::GitResolver;
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_types::{BuildContext, HashStrategy, InstalledPackagesProvider};
use uv_warnings::warn_user_once;
use crate::candidate_selector::{CandidateDist, CandidateSelector};
use crate::dependency_provider::UvDependencyProvider;
@ -53,6 +54,7 @@ use crate::pubgrub::{
};
use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolutionGraph;
use crate::resolution_mode::ResolutionStrategy;
pub(crate) use crate::resolver::availability::{
IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion,
};
@ -512,6 +514,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
&self.urls,
dependencies.clone(),
&self.git,
self.selector.resolution_strategy(),
)?;
// Emit a request to fetch the metadata for each registry package.
for dependency in &dependencies {
@ -585,6 +588,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
&self.urls,
fork.dependencies.clone(),
&self.git,
self.selector.resolution_strategy(),
)?;
// Emit a request to fetch the metadata for each registry package.
for dependency in &fork.dependencies {
@ -2031,6 +2035,7 @@ impl ForkState {
urls: &Urls,
dependencies: Vec<PubGrubDependency>,
git: &GitResolver,
resolution_strategy: &ResolutionStrategy,
) -> Result<(), ResolveError> {
for dependency in &dependencies {
let PubGrubDependency {
@ -2040,6 +2045,7 @@ impl ForkState {
local,
} = dependency;
let mut has_url = false;
if let Some(name) = package.name() {
// From the [`Requirement`] to [`PubGrubDependency`] conversion, we get a URL if the
// requirement was a URL requirement. `Urls` applies canonicalization to this and
@ -2047,6 +2053,7 @@ impl ForkState {
// conflicts using [`ForkUrl`].
if let Some(url) = urls.get_url(name, url.as_ref(), git)? {
self.fork_urls.insert(name, url, &self.markers)?;
has_url = true;
};
// `PubGrubDependency` also gives us a local version if specified by the user.
@ -2062,6 +2069,19 @@ impl ForkState {
} else {
// A dependency from the root package or requirements.txt.
debug!("Adding direct dependency: {package}{version}");
// Warn the user if the direct dependency lacks a lower bound in lowest resolution.
let missing_lower_bound = version
.bounding_range()
.map(|(lowest, _highest)| lowest == Bound::Unbounded)
.unwrap_or(true);
let strategy_lowest = matches!(
resolution_strategy,
ResolutionStrategy::Lowest | ResolutionStrategy::LowestDirect(..)
);
if !has_url && missing_lower_bound && strategy_lowest {
warn_user_once!("The direct dependency `{package}` is unpinned. Consider setting a lower bound when using `--resolution-strategy lowest` to avoid using outdated versions.");
}
}
// Update the package priorities.