Respect pre-release preferences from input files (#5736)

## Summary

Right now, if you have a `requirements.txt` with a pre-release, but the
`requirements.in` does not have a pre-release marker for that dependency
we drop the pre-release. (In the selector, we end up returning
`AllowPrerelease::IfNecessary`, the default.)

I played with a few ways of solving this... The first was to remove that
guard altogether. But if we do that,
`universal_transitive_disjoint_prerelease_requirement` fails (we use
`1.17.0rc1` in both forks, when it should only apply to one of the two).

The second was to do that, but also avoid pushing pre-releases as
preferences when we solve a fork. But then
`universal_disjoint_prereleases` fails, because we return a different
pre-release in each fork.

Finally, I settled on allowing existing pre-releases in forks if they
have no markers on them, i.e., they are "global" preferences. I believe
this is true IFF the preference came from an existing lockfile.

Closes https://github.com/astral-sh/uv/issues/5729.
This commit is contained in:
Charlie Marsh 2024-08-02 22:01:58 -04:00 committed by GitHub
parent 030d477653
commit 35b982446d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 182 additions and 13 deletions

View file

@ -206,7 +206,7 @@ impl CandidateSelector {
exclusions: &Exclusions,
resolver_markers: &ResolverMarkers,
) -> Option<Candidate<'a>> {
for (_marker, version) in preferences {
for (marker, version) in preferences {
// Respect the version range for this requirement.
if !range.contains(version) {
continue;
@ -240,13 +240,20 @@ impl CandidateSelector {
}
// Respect the pre-release strategy for this fork.
if version.any_prerelease()
&& self
if version.any_prerelease() {
let allow = match self
.prerelease_strategy
.allows(package_name, resolver_markers)
!= AllowPrerelease::Yes
{
continue;
{
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_none(),
};
if !allow {
continue;
}
}
// Check for a remote distribution that matches the preferred version

View file

@ -494,7 +494,7 @@ mod tests {
];
for (i, v1) in versions.iter().enumerate() {
for v2 in &versions[i + 1..] {
assert_eq!(v1.cmp(v2), Ordering::Less, "less: {v1:?}\ngreater: {v2:?}",);
assert_eq!(v1.cmp(v2), Ordering::Less, "less: {v1:?}\ngreater: {v2:?}");
}
}
}