mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Move Requires-Python
incompatibilities out of version map (#4705)
## Summary This is required to solve https://github.com/astral-sh/uv/issues/4669, because the `Requires-Python` version can now vary across a resolution. For example, within certain forks, we might have a more narrow range, which would allow us to use distributions that would not be allowed for the global resolution. This should be fine because `requires-python` is part of the package metadata, so it should be consistent between files within a package version. As such, there shouldn't be any risk that we incorrectly prioritize distributions by omitting this information. (To be more specific, the risk is something like: we prioritize some wheel over a source distribution within a package-version, so we don't track the source distribution at all. Then, later, when we choose a candidate, we see that the wheel doesn't meet the `Requires-Python` requirement, even though the source distribution _would've_ met it. If files within a distribution could have varied support, this would be a real risk.)
This commit is contained in:
parent
8dabc29d80
commit
89b3324ae1
3 changed files with 77 additions and 65 deletions
|
@ -23,9 +23,9 @@ use tokio_stream::wrappers::ReceiverStream;
|
|||
use tracing::{debug, enabled, instrument, trace, warn, Level};
|
||||
|
||||
use distribution_types::{
|
||||
BuiltDist, Dist, DistributionMetadata, IncompatibleDist, IncompatibleSource, IncompatibleWheel,
|
||||
InstalledDist, PythonRequirementKind, RemoteSource, ResolvedDist, ResolvedDistRef, SourceDist,
|
||||
VersionOrUrlRef,
|
||||
BuiltDist, CompatibleDist, Dist, DistributionMetadata, IncompatibleDist, IncompatibleSource,
|
||||
IncompatibleWheel, InstalledDist, PythonRequirementKind, RemoteSource, ResolvedDist,
|
||||
ResolvedDistRef, SourceDist, VersionOrUrlRef,
|
||||
};
|
||||
pub(crate) use locals::Locals;
|
||||
use pep440_rs::{Version, MIN_VERSION};
|
||||
|
@ -155,7 +155,6 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
|
|||
database,
|
||||
flat_index,
|
||||
tags,
|
||||
python_requirement.clone(),
|
||||
AllowedYanks::from_manifest(&manifest, markers, options.dependency_mode),
|
||||
hasher,
|
||||
options.exclude_newer,
|
||||
|
@ -922,6 +921,77 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
}
|
||||
};
|
||||
|
||||
let incompatibility = match dist {
|
||||
CompatibleDist::InstalledDist(_) => None,
|
||||
CompatibleDist::SourceDist { sdist, .. }
|
||||
| CompatibleDist::IncompatibleWheel { sdist, .. } => {
|
||||
// Source distributions must meet both the _target_ Python version and the
|
||||
// _installed_ Python version (to build successfully).
|
||||
sdist
|
||||
.file
|
||||
.requires_python
|
||||
.as_ref()
|
||||
.and_then(|requires_python| {
|
||||
if let Some(target) = self.python_requirement.target() {
|
||||
if !target.is_compatible_with(requires_python) {
|
||||
return Some(IncompatibleDist::Source(
|
||||
IncompatibleSource::RequiresPython(
|
||||
requires_python.clone(),
|
||||
PythonRequirementKind::Target,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
if !requires_python.contains(self.python_requirement.installed()) {
|
||||
return Some(IncompatibleDist::Source(
|
||||
IncompatibleSource::RequiresPython(
|
||||
requires_python.clone(),
|
||||
PythonRequirementKind::Installed,
|
||||
),
|
||||
));
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
CompatibleDist::CompatibleWheel { wheel, .. } => {
|
||||
// Wheels must meet the _target_ Python version.
|
||||
wheel
|
||||
.file
|
||||
.requires_python
|
||||
.as_ref()
|
||||
.and_then(|requires_python| {
|
||||
if let Some(target) = self.python_requirement.target() {
|
||||
if !target.is_compatible_with(requires_python) {
|
||||
return Some(IncompatibleDist::Wheel(
|
||||
IncompatibleWheel::RequiresPython(
|
||||
requires_python.clone(),
|
||||
PythonRequirementKind::Target,
|
||||
),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if !requires_python.contains(self.python_requirement.installed()) {
|
||||
return Some(IncompatibleDist::Wheel(
|
||||
IncompatibleWheel::RequiresPython(
|
||||
requires_python.clone(),
|
||||
PythonRequirementKind::Installed,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// The version is incompatible due to its Python requirement.
|
||||
if let Some(incompatibility) = incompatibility {
|
||||
return Ok(Some(ResolverVersion::Unavailable(
|
||||
candidate.version().clone(),
|
||||
UnavailableVersion::IncompatibleDist(incompatibility),
|
||||
)));
|
||||
}
|
||||
|
||||
let filename = match dist.for_installation() {
|
||||
ResolvedDistRef::InstallableRegistrySourceDist { sdist, .. } => sdist
|
||||
.filename()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue