diff --git a/crates/uv-resolver/src/pubgrub/report.rs b/crates/uv-resolver/src/pubgrub/report.rs index 6ec81d72f085..24e133fb69cf 100644 --- a/crates/uv-resolver/src/pubgrub/report.rs +++ b/crates/uv-resolver/src/pubgrub/report.rs @@ -831,7 +831,7 @@ impl std::fmt::Display for PubGrubHint { } => { write!( f, - "{}{} The `Requires-Python` requirement ({}) defined in your `pyproject.toml` includes Python versions that are not supported by your dependencies (e.g., {} only supports {}). Consider using a more restrictive `Requires-Python` requirement (like {}).", + "{}{} The `Requires-Python` requirement ({}) includes Python versions that are not supported by your dependencies (e.g., {} only supports {}). Consider using a more restrictive `Requires-Python` requirement (like {}).", "hint".bold().cyan(), ":".bold(), requires_python.bold(), diff --git a/crates/uv-resolver/src/python_requirement.rs b/crates/uv-resolver/src/python_requirement.rs index 36c77360e87d..bc262f9ff9fe 100644 --- a/crates/uv-resolver/src/python_requirement.rs +++ b/crates/uv-resolver/src/python_requirement.rs @@ -1,5 +1,5 @@ -use pep440_rs::{Operator, Version, VersionSpecifier, VersionSpecifiers}; -use pep508_rs::{MarkerExpression, MarkerTree, MarkerValueVersion, StringVersion}; +use pep440_rs::VersionSpecifiers; +use pep508_rs::{MarkerTree, StringVersion}; use uv_toolchain::{Interpreter, PythonVersion}; use crate::RequiresPython; @@ -62,32 +62,12 @@ impl PythonRequirement { /// Return a [`MarkerTree`] representing the Python requirement. /// /// See: [`RequiresPython::to_marker_tree`] - pub fn to_marker_tree(&self) -> MarkerTree { - let version = match &self.target { - None => self.installed.version.clone(), - Some(PythonTarget::Version(version)) => version.version.clone(), - Some(PythonTarget::RequiresPython(requires_python)) => { - return requires_python.to_marker_tree() - } - }; - - 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::GreaterThanEqual, - version_major_minor_only, - ) - .unwrap(), - }; - let expr_python_full_version = MarkerExpression::Version { - key: MarkerValueVersion::PythonFullVersion, - specifier: VersionSpecifier::from_version(Operator::GreaterThanEqual, version).unwrap(), - }; - MarkerTree::And(vec![ - MarkerTree::Expression(expr_python_version), - MarkerTree::Expression(expr_python_full_version), - ]) + pub fn to_marker_tree(&self) -> Option { + if let Some(PythonTarget::RequiresPython(requires_python)) = self.target.as_ref() { + Some(requires_python.to_marker_tree()) + } else { + None + } } } diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 3a2525e9959b..2e69202057a7 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -191,11 +191,6 @@ impl provider: Provider, installed_packages: InstalledPackages, ) -> Result { - let requires_python = if markers.is_some() { - None - } else { - Some(python_requirement.to_marker_tree()) - }; let state = ResolverState { index: index.clone(), git: git.clone(), @@ -214,8 +209,12 @@ impl exclusions: manifest.exclusions, hasher: hasher.clone(), markers: markers.cloned(), + requires_python: if markers.is_some() { + None + } else { + python_requirement.to_marker_tree() + }, python_requirement: python_requirement.clone(), - requires_python, reporter: None, installed_packages, }; diff --git a/crates/uv/src/commands/pip/compile.rs b/crates/uv/src/commands/pip/compile.rs index 2d73bde159dd..fbb4557ab229 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -28,7 +28,8 @@ use uv_requirements::{ }; use uv_resolver::{ AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, FlatIndex, - InMemoryIndex, OptionsBuilder, PreReleaseMode, PythonRequirement, ResolutionMode, + InMemoryIndex, OptionsBuilder, PreReleaseMode, PythonRequirement, RequiresPython, + ResolutionMode, }; use uv_toolchain::{ EnvironmentPreference, PythonEnvironment, PythonVersion, Toolchain, ToolchainPreference, @@ -212,7 +213,16 @@ pub(crate) async fn pip_compile( }; // Determine the Python requirement, if the user requested a specific version. - let python_requirement = if let Some(python_version) = python_version.as_ref() { + let python_requirement = if universal { + let requires_python = RequiresPython::greater_than_equal_version( + if let Some(python_version) = python_version.as_ref() { + python_version.version.clone() + } else { + interpreter.python_version().clone() + }, + ); + PythonRequirement::from_requires_python(&interpreter, &requires_python) + } else if let Some(python_version) = python_version.as_ref() { PythonRequirement::from_python_version(&interpreter, python_version) } else { PythonRequirement::from_interpreter(&interpreter) diff --git a/crates/uv/tests/lock.rs b/crates/uv/tests/lock.rs index 983da4447709..214817509371 100644 --- a/crates/uv/tests/lock.rs +++ b/crates/uv/tests/lock.rs @@ -1650,7 +1650,7 @@ fn lock_requires_python() -> Result<()> { And because project==0.1.0 depends on pygls>=1.1.0, we can conclude that project==0.1.0 cannot be used. And because only project==0.1.0 is available and you require project, we can conclude that the requirements are unsatisfiable. - hint: The `Requires-Python` requirement (>=3.7) defined in your `pyproject.toml` includes Python versions that are not supported by your dependencies (e.g., pygls>=1.1.0,<=1.2.1 only supports >=3.7.9, <4). Consider using a more restrictive `Requires-Python` requirement (like >=3.7.9, <4). + hint: The `Requires-Python` requirement (>=3.7) includes Python versions that are not supported by your dependencies (e.g., pygls>=1.1.0,<=1.2.1 only supports >=3.7.9, <4). Consider using a more restrictive `Requires-Python` requirement (like >=3.7.9, <4). "###); // Require >=3.7, and allow locking to a version of `pygls` that is compatible (==1.0.1).