Make version selection wheel-vs.-sdist-agnostic (#232)

Closes https://github.com/astral-sh/puffin/issues/231.
This commit is contained in:
Charlie Marsh 2023-10-30 08:21:10 -07:00 committed by GitHub
parent 8d992dca3f
commit 0be20a41a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 98 deletions

View file

@ -156,96 +156,63 @@ impl CandidateSelector {
range: &Range<PubGrubVersion>,
allow_prerelease: AllowPreRelease,
) -> Option<Candidate> {
// We prefer a stable wheel, followed by a prerelease wheel, followed by a stable sdist,
// followed by a prerelease sdist.
let mut sdist = None;
let mut prerelease_sdist = None;
let mut prerelease_wheel = None;
#[derive(Debug)]
enum PreReleaseCandidate<'a> {
NotNecessary,
IfNecessary(&'a PubGrubVersion, &'a DistributionFile),
}
let mut prerelease = None;
for (version, file) in versions {
if range.contains(version) {
match file {
DistributionFile::Wheel(_) => {
if version.any_prerelease() {
match allow_prerelease {
AllowPreRelease::Yes => {
// If prereleases are allowed, treat them equivalently
// to stable wheels.
return Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
AllowPreRelease::IfNecessary => {
// If prereleases are allowed as a fallback, store the
// first-matching prerelease wheel.
if prerelease_wheel.is_none() {
prerelease_wheel = Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
}
AllowPreRelease::No => {
continue;
}
}
} else {
// Always return the first-matching stable wheel.
if version.any_prerelease() {
if range.contains(version) {
match allow_prerelease {
AllowPreRelease::Yes => {
// If pre-releases are allowed, treat them equivalently
// to stable distributions.
return Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
}
DistributionFile::Sdist(_) => {
if version.any_prerelease() {
match allow_prerelease {
AllowPreRelease::Yes => {
// If prereleases are allowed, treat them equivalently to
// stable sdists.
if sdist.is_none() {
sdist = Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
}
AllowPreRelease::IfNecessary => {
// If prereleases are allowed as a fallback, store the
// first-matching prerelease sdist.
if prerelease_sdist.is_none() {
prerelease_sdist = Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
}
AllowPreRelease::No => {
continue;
}
}
} else {
// Store the first-matching stable sdist.
if sdist.is_none() {
sdist = Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
AllowPreRelease::IfNecessary => {
// If pre-releases are allowed as a fallback, store the
// first-matching prerelease.
if prerelease.is_none() {
prerelease = Some(PreReleaseCandidate::IfNecessary(version, file));
}
}
AllowPreRelease::No => {
continue;
}
}
}
} else {
// If we have at least one stable release, we shouldn't allow the "if-necessary"
// pre-release strategy, regardless of whether that stable release satisfies the
// current range.
prerelease = Some(PreReleaseCandidate::NotNecessary);
// Always return the first-matching stable distribution.
if range.contains(version) {
return Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
}
}
sdist.or(prerelease_wheel).or(prerelease_sdist)
match prerelease {
None => None,
Some(PreReleaseCandidate::NotNecessary) => None,
Some(PreReleaseCandidate::IfNecessary(version, file)) => Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
}),
}
}
}

View file

@ -515,11 +515,10 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
if let Ok(name) = WheelFilename::from_str(file.filename.as_str()) {
if name.is_compatible(self.tags) {
let version = PubGrubVersion::from(name.version);
match version_map.entry(version) {
std::collections::btree_map::Entry::Occupied(mut entry) => {
if let DistributionFile::Sdist(_) = entry.get() {
// Wheels get precedence over source distributions
if matches!(entry.get(), DistributionFile::Sdist(_)) {
// Wheels get precedence over source distributions.
entry.insert(DistributionFile::from(WheelFile::from(
file,
)));

View file

@ -134,7 +134,7 @@ async fn black_mypy_extensions() -> Result<()> {
let manifest = Manifest::new(
vec![Requirement::from_str("black<=23.9.1").unwrap()],
vec![Requirement::from_str("mypy-extensions<1").unwrap()],
vec![Requirement::from_str("mypy-extensions<0.4.4").unwrap()],
vec![],
ResolutionMode::default(),
PreReleaseMode::default(),
@ -158,7 +158,7 @@ async fn black_mypy_extensions_extra() -> Result<()> {
let manifest = Manifest::new(
vec![Requirement::from_str("black<=23.9.1").unwrap()],
vec![Requirement::from_str("mypy-extensions[extra]<1").unwrap()],
vec![Requirement::from_str("mypy-extensions[extra]<0.4.4").unwrap()],
vec![],
ResolutionMode::default(),
PreReleaseMode::default(),
@ -321,7 +321,7 @@ async fn black_allow_prerelease_if_necessary() -> Result<()> {
);
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?;
let resolution = resolver.resolve().await.unwrap_err();
insta::assert_display_snapshot!(resolution);

View file

@ -2,19 +2,4 @@
source: crates/puffin-resolver/tests/resolver.rs
expression: resolution
---
appdirs==1.4.4
# via black
attrs==23.1.0
# via black
black==19.10b0
click==8.1.7
# via black
pathspec==0.11.2
# via black
regex==2023.10.3
# via black
toml==0.10.2
# via black
typed-ast==1.5.5
# via black
No solution