mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-08 03:30:35 +00:00
Fork version selection based on requires-python
requirements (#9827)
## Summary This PR addresses a significant limitation in the resolver whereby we avoid choosing the latest versions of packages when the user supports a wider range. For example, with NumPy, the latest versions only support Python 3.10 and later. If you lock a project with `requires-python = ">=3.8"`, we pick the last NumPy version that supported Python 3.8, and use that for _all_ Python versions. So you get `1.24.4` for all versions, rather than `2.2.0`. And we'll never upgrade you unless you bump your `requires-python`. (Even worse, those versions don't have wheels for Python 3.12, etc., so you end up building from source.) (As-is, this is intentional. We optimize for minimizing the number of selected versions, and the current logic does that well!) Instead, we know recognize when a version has an elevated `requires-python` specifier and fork. This is a new fork point, since we need to fork once we have the package metadata, as opposed to when we see the dependencies. In this iteration, I've made this behavior the default. I'm sort of undecided on whether I want to push on that... Previously, I'd suggested making it opt-in via a setting (https://github.com/astral-sh/uv/pull/8686). Closes https://github.com/astral-sh/uv/issues/8492.
This commit is contained in:
parent
dc0525ddd0
commit
0ee21146f4
10 changed files with 940 additions and 203 deletions
|
@ -1,3 +1,5 @@
|
|||
use std::collections::Bound;
|
||||
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::{MarkerEnvironment, MarkerTree};
|
||||
use uv_python::{Interpreter, PythonVersion};
|
||||
|
@ -84,6 +86,28 @@ impl PythonRequirement {
|
|||
})
|
||||
}
|
||||
|
||||
/// Split the [`PythonRequirement`] at the given version.
|
||||
///
|
||||
/// For example, if the current requirement is `>=3.10`, and the split point is `3.11`, then
|
||||
/// the result will be `>=3.10 and <3.11` and `>=3.11`.
|
||||
pub fn split(&self, at: Bound<Version>) -> Option<(Self, Self)> {
|
||||
let (lower, upper) = self.target.split(at)?;
|
||||
Some((
|
||||
Self {
|
||||
exact: self.exact.clone(),
|
||||
installed: self.installed.clone(),
|
||||
target: lower,
|
||||
source: self.source,
|
||||
},
|
||||
Self {
|
||||
exact: self.exact.clone(),
|
||||
installed: self.installed.clone(),
|
||||
target: upper,
|
||||
source: self.source,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns `true` if the minimum version of Python required by the target is greater than the
|
||||
/// installed version.
|
||||
pub fn raises(&self, target: &RequiresPythonRange) -> bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue