diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 888fc6444..340f82eec 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -569,8 +569,12 @@ pub struct PipCompileArgs { pub python_platform: Option, /// Perform a universal resolution, attempting to generate a single `requirements.txt` output - /// file that is compatible with all operating systems, architectures and supported Python - /// versions. + /// file that is compatible with all operating systems, architectures, and Python + /// implementations. + /// + /// In universal mode, the current Python version (or user-provided `--python-version`) will be + /// treated as a lower bound. For example, `--universal --python-version 3.7` would produce a + /// universal resolution for Python 3.7 and later. #[arg(long, overrides_with("no_universal"))] pub universal: bool, diff --git a/crates/uv-resolver/src/python_requirement.rs b/crates/uv-resolver/src/python_requirement.rs index 5035fed5f..36c77360e 100644 --- a/crates/uv-resolver/src/python_requirement.rs +++ b/crates/uv-resolver/src/python_requirement.rs @@ -74,12 +74,15 @@ impl PythonRequirement { let version_major_minor_only = Version::new(version.release().iter().take(2)); let expr_python_version = MarkerExpression::Version { key: MarkerValueVersion::PythonVersion, - specifier: VersionSpecifier::from_version(Operator::Equal, version_major_minor_only) - .unwrap(), + specifier: VersionSpecifier::from_version( + Operator::GreaterThanEqual, + version_major_minor_only, + ) + .unwrap(), }; let expr_python_full_version = MarkerExpression::Version { key: MarkerValueVersion::PythonFullVersion, - specifier: VersionSpecifier::from_version(Operator::Equal, version).unwrap(), + specifier: VersionSpecifier::from_version(Operator::GreaterThanEqual, version).unwrap(), }; MarkerTree::And(vec![ MarkerTree::Expression(expr_python_version),