diff --git a/crates/uv-python/src/python_version.rs b/crates/uv-python/src/python_version.rs index 30cc8c5ddb088..d71f60cbad5b3 100644 --- a/crates/uv-python/src/python_version.rs +++ b/crates/uv-python/src/python_version.rs @@ -31,6 +31,27 @@ impl FromStr for PythonVersion { if version.epoch() != 0 { return Err(format!("Python version `{s}` has a non-zero epoch")); } + if let Some(major) = version.release().first() { + if u8::try_from(*major).is_err() { + return Err(format!( + "Python version `{s}` has an invalid major version ({major})" + )); + } + } + if let Some(minor) = version.release().get(1) { + if u8::try_from(*minor).is_err() { + return Err(format!( + "Python version `{s}` has an invalid minor version ({minor})" + )); + } + } + if let Some(patch) = version.release().get(2) { + if u8::try_from(*patch).is_err() { + return Err(format!( + "Python version `{s}` has an invalid patch version ({patch})" + )); + } + } Ok(Self(version)) } diff --git a/crates/uv/tests/it/pip_install.rs b/crates/uv/tests/it/pip_install.rs index ef96ab3b7cf8b..e4709c84dc2b3 100644 --- a/crates/uv/tests/it/pip_install.rs +++ b/crates/uv/tests/it/pip_install.rs @@ -364,6 +364,26 @@ dependencies = ["flask==1.0.x"] Ok(()) } +#[test] +fn invalid_python_version() { + let context = TestContext::new("3.12"); + + uv_snapshot!(context.filters(), context.pip_install() + .arg("flask") + .arg("--python-version") + .arg("311"), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: invalid value '311' for '--python-version ': Python version `311` has an invalid major version (311) + + For more information, try '--help'. + " + ); +} + #[test] fn missing_pip() { uv_snapshot!(Command::new(get_bin()).arg("install"), @r###"