Skip to content

Commit

Permalink
add check for ~= python versions
Browse files Browse the repository at this point in the history
  • Loading branch information
ianpaul10 committed Oct 17, 2024
1 parent 3fd5a5b commit 6930710
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 1 deletion.
11 changes: 10 additions & 1 deletion crates/uv-resolver/src/requires_python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::Bound;
use std::ops::Deref;

use uv_distribution_filename::WheelFilename;
use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers};
use uv_pep440::{Operator, Version, VersionSpecifier, VersionSpecifiers};
use uv_pep508::{MarkerExpression, MarkerTree, MarkerValueVersion};
use uv_pubgrub::PubGrubSpecifier;

Expand Down Expand Up @@ -260,6 +260,15 @@ impl RequiresPython {
}
}

/// Returns `true` if the `Requires-Python` specifier is set to a tilde-equal version
/// without specifying a patch version. (e.g. `~=3.11`)
pub fn is_tilde_exact_without_patch(&self) -> bool {
self.specifiers.len() == 1
&& self.specifiers.iter().next().map_or(false, |spec| {
*spec.operator() == Operator::TildeEqual && spec.version().release().len() == 2
})
}

/// Returns the [`RequiresPythonBound`] truncated to the major and minor version.
pub fn bound_major_minor(&self) -> LowerBound {
match self.range.lower().as_ref() {
Expand Down
22 changes: 22 additions & 0 deletions crates/uv-resolver/src/requires_python/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,25 @@ fn is_exact_without_patch() {
assert_eq!(requires_python.is_exact_without_patch(), expected);
}
}

#[test]
fn is_tilde_exact_without_patch() {
let test_cases = [
("~=3.11", true),
("~=2.7", true),
("~=3.10, <3.11", false),
("~=3.10, <=3.11", false),
("~=3.11.0", false),
("==3.12", false),
(">=3.12", false),
(">3.10", false),
("<4.0", false),
(">=3.10, <3.11", false),
("", false),
];
for (version, expected) in test_cases {
let version_specifiers = VersionSpecifiers::from_str(version).unwrap();
let requires_python = RequiresPython::from_specifiers(&version_specifiers).unwrap();
assert_eq!(requires_python.is_tilde_exact_without_patch(), expected);
}
}
4 changes: 4 additions & 0 deletions crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ async fn do_lock(
warn_user_once!("The workspace `requires-python` value (`{requires_python}`) does not contain a lower bound. Add a lower bound to indicate the minimum compatible Python version (e.g., `{default}`).");
} else if requires_python.is_exact_without_patch() {
warn_user_once!("The workspace `requires-python` value (`{requires_python}`) contains an exact match without a patch version. When omitted, the patch version is implicitly `0` (e.g., `{requires_python}.0`). Did you mean `{requires_python}.*`?");
} else if requires_python.is_tilde_exact_without_patch() {
let py_ver = interpreter.python_version();
let major_ver = interpreter.python_major();
warn_user_once!("The workspace `requires-python` value (`{requires_python}`) contains a compatible release match without a patch version. This will be interpreted as `>={py_ver}, =={major_ver}.*`. Did you mean `{requires_python}.0` to freeze the minor version?");
}
requires_python
} else {
Expand Down

0 comments on commit 6930710

Please sign in to comment.