Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions crates/uv-resolver/src/candidate_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_types::InstalledPackagesProvider;

use crate::preferences::{Entry, Preferences};
use crate::preferences::{Entry, PreferenceSource, Preferences};
use crate::prerelease::{AllowPrerelease, PrereleaseStrategy};
use crate::resolution_mode::ResolutionStrategy;
use crate::universal_marker::UniversalMarker;
use crate::version_map::{VersionMap, VersionMapDistHandle};
use crate::{Exclusions, Manifest, Options, ResolverEnvironment};

Expand Down Expand Up @@ -188,7 +187,7 @@ impl CandidateSelector {
if index.is_some_and(|index| !entry.index().matches(index)) {
return None;
}
Either::Left(std::iter::once((entry.marker(), entry.pin().version())))
Either::Left(std::iter::once((entry.pin().version(), entry.source())))
}
[..] => {
type Entries<'a> = SmallVec<[&'a Entry; 3]>;
Expand Down Expand Up @@ -219,7 +218,7 @@ impl CandidateSelector {
Either::Right(
preferences
.into_iter()
.map(|entry| (entry.marker(), entry.pin().version())),
.map(|entry| (entry.pin().version(), entry.source())),
)
}
};
Expand All @@ -238,15 +237,15 @@ impl CandidateSelector {
/// Return the first preference that satisfies the current range and is allowed.
fn get_preferred_from_iter<'a, InstalledPackages: InstalledPackagesProvider>(
&'a self,
preferences: impl Iterator<Item = (&'a UniversalMarker, &'a Version)>,
preferences: impl Iterator<Item = (&'a Version, PreferenceSource)>,
package_name: &'a PackageName,
range: &Range<Version>,
version_maps: &'a [VersionMap],
installed_packages: &'a InstalledPackages,
reinstall: bool,
env: &ResolverEnvironment,
) -> Option<Candidate<'a>> {
for (marker, version) in preferences {
for (version, source) in preferences {
// Respect the version range for this requirement.
if !range.contains(version) {
continue;
Expand Down Expand Up @@ -290,9 +289,14 @@ impl CandidateSelector {
let allow = match self.prerelease_strategy.allows(package_name, env) {
AllowPrerelease::Yes => true,
AllowPrerelease::No => false,
// If the pre-release is "global" (i.e., provided via a lockfile, rather than
// a fork), accept it unless pre-releases are completely banned.
AllowPrerelease::IfNecessary => marker.is_true(),
// If the pre-release was provided via an existing file, rather than from the
// current solve, accept it unless pre-releases are completely banned.
AllowPrerelease::IfNecessary => match source {
PreferenceSource::Resolver => false,
PreferenceSource::Lock
| PreferenceSource::Environment
| PreferenceSource::RequirementsTxt => true,
},
};
if !allow {
continue;
Expand Down
28 changes: 28 additions & 0 deletions crates/uv-resolver/src/preferences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub struct Preference {
/// is part of, otherwise `None`.
fork_markers: Vec<UniversalMarker>,
hashes: HashDigests,
/// The source of the preference.
source: PreferenceSource,
}

impl Preference {
Expand Down Expand Up @@ -73,6 +75,7 @@ impl Preference {
.map(String::as_str)
.map(HashDigest::from_str)
.collect::<Result<_, _>>()?,
source: PreferenceSource::RequirementsTxt,
}))
}

Expand All @@ -91,6 +94,7 @@ impl Preference {
index: PreferenceIndex::from(package.index(install_path)?),
fork_markers: package.fork_markers().to_vec(),
hashes: HashDigests::empty(),
source: PreferenceSource::Lock,
}))
}

Expand All @@ -112,6 +116,7 @@ impl Preference {
// `pylock.toml` doesn't have fork annotations.
fork_markers: vec![],
hashes: HashDigests::empty(),
source: PreferenceSource::Lock,
}))
}

Expand All @@ -127,6 +132,7 @@ impl Preference {
index: PreferenceIndex::Any,
fork_markers: vec![],
hashes: HashDigests::empty(),
source: PreferenceSource::Environment,
})
}

Expand Down Expand Up @@ -171,11 +177,24 @@ impl From<Option<IndexUrl>> for PreferenceIndex {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum PreferenceSource {
/// The preference is from an installed package in the environment.
Environment,
/// The preference is from a `uv.ock` file.
Lock,
/// The preference is from a `requirements.txt` file.
RequirementsTxt,
/// The preference is from the current solve.
Resolver,
}

#[derive(Debug, Clone)]
pub(crate) struct Entry {
marker: UniversalMarker,
index: PreferenceIndex,
pin: Pin,
source: PreferenceSource,
}

impl Entry {
Expand All @@ -193,6 +212,11 @@ impl Entry {
pub(crate) fn pin(&self) -> &Pin {
&self.pin
}

/// Return the source of the entry.
pub(crate) fn source(&self) -> PreferenceSource {
self.source
}
}

/// A set of pinned packages that should be preserved during resolution, if possible.
Expand Down Expand Up @@ -245,6 +269,7 @@ impl Preferences {
version: preference.version,
hashes: preference.hashes,
},
source: preference.source,
});
} else {
for fork_marker in preference.fork_markers {
Expand All @@ -255,6 +280,7 @@ impl Preferences {
version: preference.version.clone(),
hashes: preference.hashes.clone(),
},
source: preference.source,
});
}
}
Expand All @@ -270,11 +296,13 @@ impl Preferences {
index: Option<IndexUrl>,
markers: UniversalMarker,
pin: impl Into<Pin>,
source: PreferenceSource,
) {
self.0.entry(package_name).or_default().push(Entry {
marker: markers,
index: PreferenceIndex::from(index),
pin: pin.into(),
source,
});
}

Expand Down
3 changes: 2 additions & 1 deletion crates/uv-resolver/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use crate::fork_strategy::ForkStrategy;
use crate::fork_urls::ForkUrls;
use crate::manifest::Manifest;
use crate::pins::FilePins;
use crate::preferences::Preferences;
use crate::preferences::{PreferenceSource, Preferences};
use crate::pubgrub::{
PubGrubDependency, PubGrubDistribution, PubGrubPackage, PubGrubPackageInner, PubGrubPriorities,
PubGrubPython,
Expand Down Expand Up @@ -447,6 +447,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
.try_universal_markers()
.unwrap_or(UniversalMarker::TRUE),
version.clone(),
PreferenceSource::Resolver,
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ impl ValidatedLock {
lock.prerelease_mode().cyan(),
options.prerelease_mode.cyan()
);
return Ok(Self::Unusable(lock));
return Ok(Self::Preferable(lock));
}
if lock.fork_strategy() != options.fork_strategy {
let _ = writeln!(
Expand Down
12 changes: 6 additions & 6 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,7 +1730,7 @@ pub(crate) async fn resolve_names(
}

#[derive(Debug, Clone)]
pub(crate) enum PreferenceSource<'lock> {
pub(crate) enum PreferenceLocation<'lock> {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renamed to disambiguate from Source

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's good.

/// The preferences should be extracted from a lockfile.
Lock {
lock: &'lock Lock,
Expand All @@ -1745,7 +1745,7 @@ pub(crate) struct EnvironmentSpecification<'lock> {
/// The requirements to include in the environment.
requirements: RequirementsSpecification,
/// The preferences to respect when resolving.
preferences: Option<PreferenceSource<'lock>>,
preferences: Option<PreferenceLocation<'lock>>,
}

impl From<RequirementsSpecification> for EnvironmentSpecification<'_> {
Expand All @@ -1758,9 +1758,9 @@ impl From<RequirementsSpecification> for EnvironmentSpecification<'_> {
}

impl<'lock> EnvironmentSpecification<'lock> {
/// Set the [`PreferenceSource`] for the specification.
/// Set the [`PreferenceLocation`] for the specification.
#[must_use]
pub(crate) fn with_preferences(self, preferences: PreferenceSource<'lock>) -> Self {
pub(crate) fn with_preferences(self, preferences: PreferenceLocation<'lock>) -> Self {
Self {
preferences: Some(preferences),
..self
Expand Down Expand Up @@ -1869,7 +1869,7 @@ pub(crate) async fn resolve_environment(

// If an existing lockfile exists, build up a set of preferences.
let preferences = match spec.preferences {
Some(PreferenceSource::Lock { lock, install_path }) => {
Some(PreferenceLocation::Lock { lock, install_path }) => {
let LockedRequirements { preferences, git } =
read_lock_requirements(lock, install_path, &upgrade)?;

Expand All @@ -1881,7 +1881,7 @@ pub(crate) async fn resolve_environment(

preferences
}
Some(PreferenceSource::Entries(entries)) => entries,
Some(PreferenceLocation::Entries(entries)) => entries,
None => vec![],
};

Expand Down
6 changes: 3 additions & 3 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::commands::project::install_target::InstallTarget;
use crate::commands::project::lock::LockMode;
use crate::commands::project::lock_target::LockTarget;
use crate::commands::project::{
EnvironmentSpecification, PreferenceSource, ProjectEnvironment, ProjectError,
EnvironmentSpecification, PreferenceLocation, ProjectEnvironment, ProjectError,
ScriptEnvironment, ScriptInterpreter, UniversalState, WorkspacePython,
default_dependency_groups, script_specification, update_environment,
validate_project_requires_python,
Expand Down Expand Up @@ -958,10 +958,10 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
let spec = EnvironmentSpecification::from(spec).with_preferences(
if let Some((lock, install_path)) = base_lock.as_ref() {
// If we have a lockfile, use the locked versions as preferences.
PreferenceSource::Lock { lock, install_path }
PreferenceLocation::Lock { lock, install_path }
} else {
// Otherwise, extract preferences from the base environment.
PreferenceSource::Entries(
PreferenceLocation::Entries(
base_site_packages
.iter()
.filter_map(Preference::from_installed)
Expand Down
Loading