mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-11-03 21:23:54 +00:00 
			
		
		
		
	Handle universal vs. fork markers with ResolverMarkers (#5099)
				
					
				
			* Use a dedicated `ResolverMarkers` check in the fork state. This is better than the `MarkerTree::And(Vec::new())` check. * Report the timing correct naming universal resolution instead of two spaces around an empty string when there are no markers. * On resolution error, show the split that we're in. I'm not sure how to word this, since we're doing a universal resolution until we fork, so the trace may contain information from requirements that are not part of this fork.
This commit is contained in:
		
							parent
							
								
									fe403576c5
								
							
						
					
					
						commit
						a6dfd3953a
					
				
					 19 changed files with 220 additions and 133 deletions
				
			
		| 
						 | 
					@ -90,7 +90,7 @@ mod resolver {
 | 
				
			||||||
    use uv_python::PythonEnvironment;
 | 
					    use uv_python::PythonEnvironment;
 | 
				
			||||||
    use uv_resolver::{
 | 
					    use uv_resolver::{
 | 
				
			||||||
        FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, ResolutionGraph,
 | 
					        FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, ResolutionGraph,
 | 
				
			||||||
        Resolver,
 | 
					        Resolver, ResolverMarkers,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
					    use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,7 @@ mod resolver {
 | 
				
			||||||
            manifest,
 | 
					            manifest,
 | 
				
			||||||
            options,
 | 
					            options,
 | 
				
			||||||
            &python_requirement,
 | 
					            &python_requirement,
 | 
				
			||||||
            Some(&MARKERS),
 | 
					            ResolverMarkers::SpecificEnvironment(MARKERS.clone()),
 | 
				
			||||||
            Some(&TAGS),
 | 
					            Some(&TAGS),
 | 
				
			||||||
            &flat_index,
 | 
					            &flat_index,
 | 
				
			||||||
            &index,
 | 
					            &index,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@ use uv_installer::{Installer, Plan, Planner, Preparer, SitePackages};
 | 
				
			||||||
use uv_python::{Interpreter, PythonEnvironment};
 | 
					use uv_python::{Interpreter, PythonEnvironment};
 | 
				
			||||||
use uv_resolver::{
 | 
					use uv_resolver::{
 | 
				
			||||||
    ExcludeNewer, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, Resolver,
 | 
					    ExcludeNewer, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, Resolver,
 | 
				
			||||||
 | 
					    ResolverMarkers,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
					use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,7 +147,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
 | 
				
			||||||
                .index_strategy(self.index_strategy)
 | 
					                .index_strategy(self.index_strategy)
 | 
				
			||||||
                .build(),
 | 
					                .build(),
 | 
				
			||||||
            &python_requirement,
 | 
					            &python_requirement,
 | 
				
			||||||
            Some(markers),
 | 
					            ResolverMarkers::SpecificEnvironment(markers.clone()),
 | 
				
			||||||
            Some(tags),
 | 
					            Some(tags),
 | 
				
			||||||
            self.flat_index,
 | 
					            self.flat_index,
 | 
				
			||||||
            self.index,
 | 
					            self.index,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,12 @@ use thiserror::Error;
 | 
				
			||||||
use tracing::trace;
 | 
					use tracing::trace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use distribution_types::{BuiltDist, Dist, DistributionMetadata, GitSourceDist, SourceDist};
 | 
					use distribution_types::{BuiltDist, Dist, DistributionMetadata, GitSourceDist, SourceDist};
 | 
				
			||||||
use pep508_rs::MarkerEnvironment;
 | 
					 | 
				
			||||||
use pypi_types::{Requirement, RequirementSource};
 | 
					use pypi_types::{Requirement, RequirementSource};
 | 
				
			||||||
use uv_configuration::{Constraints, Overrides};
 | 
					use uv_configuration::{Constraints, Overrides};
 | 
				
			||||||
use uv_distribution::{DistributionDatabase, Reporter};
 | 
					use uv_distribution::{DistributionDatabase, Reporter};
 | 
				
			||||||
use uv_git::GitUrl;
 | 
					use uv_git::GitUrl;
 | 
				
			||||||
use uv_normalize::GroupName;
 | 
					use uv_normalize::GroupName;
 | 
				
			||||||
use uv_resolver::{InMemoryIndex, MetadataResponse};
 | 
					use uv_resolver::{InMemoryIndex, MetadataResponse, ResolverMarkers};
 | 
				
			||||||
use uv_types::{BuildContext, HashStrategy, RequestedRequirements};
 | 
					use uv_types::{BuildContext, HashStrategy, RequestedRequirements};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Error)]
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
| 
						 | 
					@ -98,7 +97,7 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
 | 
				
			||||||
    /// to "only evaluate marker expressions that reference an extra name.")
 | 
					    /// to "only evaluate marker expressions that reference an extra name.")
 | 
				
			||||||
    pub async fn resolve(
 | 
					    pub async fn resolve(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        markers: Option<&MarkerEnvironment>,
 | 
					        markers: &ResolverMarkers,
 | 
				
			||||||
    ) -> Result<Vec<RequestedRequirements>, LookaheadError> {
 | 
					    ) -> Result<Vec<RequestedRequirements>, LookaheadError> {
 | 
				
			||||||
        let mut results = Vec::new();
 | 
					        let mut results = Vec::new();
 | 
				
			||||||
        let mut futures = FuturesUnordered::new();
 | 
					        let mut futures = FuturesUnordered::new();
 | 
				
			||||||
| 
						 | 
					@ -108,7 +107,7 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
 | 
				
			||||||
        let mut queue: VecDeque<_> = self
 | 
					        let mut queue: VecDeque<_> = self
 | 
				
			||||||
            .constraints
 | 
					            .constraints
 | 
				
			||||||
            .apply(self.overrides.apply(self.requirements))
 | 
					            .apply(self.overrides.apply(self.requirements))
 | 
				
			||||||
            .filter(|requirement| requirement.evaluate_markers(markers, &[]))
 | 
					            .filter(|requirement| requirement.evaluate_markers(markers.marker_environment(), &[]))
 | 
				
			||||||
            .map(|requirement| (*requirement).clone())
 | 
					            .map(|requirement| (*requirement).clone())
 | 
				
			||||||
            .collect();
 | 
					            .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,7 +126,9 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
 | 
				
			||||||
                        .constraints
 | 
					                        .constraints
 | 
				
			||||||
                        .apply(self.overrides.apply(lookahead.requirements()))
 | 
					                        .apply(self.overrides.apply(lookahead.requirements()))
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if requirement.evaluate_markers(markers, lookahead.extras()) {
 | 
					                        if requirement
 | 
				
			||||||
 | 
					                            .evaluate_markers(markers.marker_environment(), lookahead.extras())
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
                            queue.push_back((*requirement).clone());
 | 
					                            queue.push_back((*requirement).clone());
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ use crate::pubgrub::{
 | 
				
			||||||
    PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter, PubGrubSpecifierError,
 | 
					    PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter, PubGrubSpecifierError,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::python_requirement::PythonRequirement;
 | 
					use crate::python_requirement::PythonRequirement;
 | 
				
			||||||
use crate::resolver::{IncompletePackage, UnavailablePackage, UnavailableReason};
 | 
					use crate::resolver::{IncompletePackage, ResolverMarkers, UnavailablePackage, UnavailableReason};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, thiserror::Error)]
 | 
					#[derive(Debug, thiserror::Error)]
 | 
				
			||||||
pub enum ResolveError {
 | 
					pub enum ResolveError {
 | 
				
			||||||
| 
						 | 
					@ -50,10 +50,10 @@ pub enum ResolveError {
 | 
				
			||||||
    ConflictingOverrideUrls(PackageName, String, String),
 | 
					    ConflictingOverrideUrls(PackageName, String, String),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("Requirements contain conflicting URLs for package `{0}`:\n- {}", _1.join("\n- "))]
 | 
					    #[error("Requirements contain conflicting URLs for package `{0}`:\n- {}", _1.join("\n- "))]
 | 
				
			||||||
    ConflictingUrls(PackageName, Vec<String>),
 | 
					    ConflictingUrlsUniversal(PackageName, Vec<String>),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[error("Requirements contain conflicting URLs for package `{package_name}` in split `{fork_markers}`:\n- {}", urls.join("\n- "))]
 | 
					    #[error("Requirements contain conflicting URLs for package `{package_name}` in split `{fork_markers}`:\n- {}", urls.join("\n- "))]
 | 
				
			||||||
    ConflictingUrlsInFork {
 | 
					    ConflictingUrlsFork {
 | 
				
			||||||
        package_name: PackageName,
 | 
					        package_name: PackageName,
 | 
				
			||||||
        urls: Vec<String>,
 | 
					        urls: Vec<String>,
 | 
				
			||||||
        fork_markers: MarkerTree,
 | 
					        fork_markers: MarkerTree,
 | 
				
			||||||
| 
						 | 
					@ -125,9 +125,21 @@ pub struct NoSolutionError {
 | 
				
			||||||
    unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
 | 
					    unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
 | 
				
			||||||
    incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
 | 
					    incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
 | 
				
			||||||
    fork_urls: ForkUrls,
 | 
					    fork_urls: ForkUrls,
 | 
				
			||||||
 | 
					    markers: ResolverMarkers,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl NoSolutionError {
 | 
					impl NoSolutionError {
 | 
				
			||||||
 | 
					    pub fn header(&self) -> String {
 | 
				
			||||||
 | 
					        match &self.markers {
 | 
				
			||||||
 | 
					            ResolverMarkers::Universal | ResolverMarkers::SpecificEnvironment(_) => {
 | 
				
			||||||
 | 
					                "No solution found when resolving dependencies:".to_string()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ResolverMarkers::Fork(markers) => {
 | 
				
			||||||
 | 
					                format!("No solution found when resolving dependencies for split ({markers}):")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub(crate) fn new(
 | 
					    pub(crate) fn new(
 | 
				
			||||||
        error: pubgrub::error::NoSolutionError<UvDependencyProvider>,
 | 
					        error: pubgrub::error::NoSolutionError<UvDependencyProvider>,
 | 
				
			||||||
        available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
 | 
					        available_versions: FxHashMap<PubGrubPackage, BTreeSet<Version>>,
 | 
				
			||||||
| 
						 | 
					@ -137,6 +149,7 @@ impl NoSolutionError {
 | 
				
			||||||
        unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
 | 
					        unavailable_packages: FxHashMap<PackageName, UnavailablePackage>,
 | 
				
			||||||
        incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
 | 
					        incomplete_packages: FxHashMap<PackageName, BTreeMap<Version, IncompletePackage>>,
 | 
				
			||||||
        fork_urls: ForkUrls,
 | 
					        fork_urls: ForkUrls,
 | 
				
			||||||
 | 
					        markers: ResolverMarkers,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            error,
 | 
					            error,
 | 
				
			||||||
| 
						 | 
					@ -147,6 +160,7 @@ impl NoSolutionError {
 | 
				
			||||||
            unavailable_packages,
 | 
					            unavailable_packages,
 | 
				
			||||||
            incomplete_packages,
 | 
					            incomplete_packages,
 | 
				
			||||||
            fork_urls,
 | 
					            fork_urls,
 | 
				
			||||||
 | 
					            markers,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,10 @@ use std::collections::hash_map::Entry;
 | 
				
			||||||
use rustc_hash::FxHashMap;
 | 
					use rustc_hash::FxHashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use distribution_types::Verbatim;
 | 
					use distribution_types::Verbatim;
 | 
				
			||||||
use pep508_rs::MarkerTree;
 | 
					 | 
				
			||||||
use pypi_types::VerbatimParsedUrl;
 | 
					use pypi_types::VerbatimParsedUrl;
 | 
				
			||||||
use uv_normalize::PackageName;
 | 
					use uv_normalize::PackageName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::resolver::ResolverMarkers;
 | 
				
			||||||
use crate::ResolveError;
 | 
					use crate::ResolveError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// See [`crate::resolver::SolveState`].
 | 
					/// See [`crate::resolver::SolveState`].
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ impl ForkUrls {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        package_name: &PackageName,
 | 
					        package_name: &PackageName,
 | 
				
			||||||
        url: &VerbatimParsedUrl,
 | 
					        url: &VerbatimParsedUrl,
 | 
				
			||||||
        fork_markers: &MarkerTree,
 | 
					        fork_markers: &ResolverMarkers,
 | 
				
			||||||
    ) -> Result<(), ResolveError> {
 | 
					    ) -> Result<(), ResolveError> {
 | 
				
			||||||
        match self.0.entry(package_name.clone()) {
 | 
					        match self.0.entry(package_name.clone()) {
 | 
				
			||||||
            Entry::Occupied(previous) => {
 | 
					            Entry::Occupied(previous) => {
 | 
				
			||||||
| 
						 | 
					@ -39,17 +39,20 @@ impl ForkUrls {
 | 
				
			||||||
                        url.verbatim.verbatim().to_string(),
 | 
					                        url.verbatim.verbatim().to_string(),
 | 
				
			||||||
                    ];
 | 
					                    ];
 | 
				
			||||||
                    conflicting_url.sort();
 | 
					                    conflicting_url.sort();
 | 
				
			||||||
                    return if fork_markers.is_universal() {
 | 
					                    return match fork_markers {
 | 
				
			||||||
                        Err(ResolveError::ConflictingUrls(
 | 
					                        ResolverMarkers::Universal | ResolverMarkers::SpecificEnvironment(_) => {
 | 
				
			||||||
                            package_name.clone(),
 | 
					                            Err(ResolveError::ConflictingUrlsUniversal(
 | 
				
			||||||
                            conflicting_url,
 | 
					                                package_name.clone(),
 | 
				
			||||||
                        ))
 | 
					                                conflicting_url,
 | 
				
			||||||
                    } else {
 | 
					                            ))
 | 
				
			||||||
                        Err(ResolveError::ConflictingUrlsInFork {
 | 
					                        }
 | 
				
			||||||
                            package_name: package_name.clone(),
 | 
					                        ResolverMarkers::Fork(fork_markers) => {
 | 
				
			||||||
                            urls: conflicting_url,
 | 
					                            Err(ResolveError::ConflictingUrlsFork {
 | 
				
			||||||
                            fork_markers: fork_markers.clone(),
 | 
					                                package_name: package_name.clone(),
 | 
				
			||||||
                        })
 | 
					                                urls: conflicting_url,
 | 
				
			||||||
 | 
					                                fork_markers: fork_markers.clone(),
 | 
				
			||||||
 | 
					                            })
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ pub use resolution::{AnnotationStyle, DisplayResolutionGraph, ResolutionGraph};
 | 
				
			||||||
pub use resolution_mode::ResolutionMode;
 | 
					pub use resolution_mode::ResolutionMode;
 | 
				
			||||||
pub use resolver::{
 | 
					pub use resolver::{
 | 
				
			||||||
    BuildId, DefaultResolverProvider, InMemoryIndex, MetadataResponse, PackageVersionsResult,
 | 
					    BuildId, DefaultResolverProvider, InMemoryIndex, MetadataResponse, PackageVersionsResult,
 | 
				
			||||||
    Reporter as ResolverReporter, Resolver, ResolverProvider, VersionsResponse,
 | 
					    Reporter as ResolverReporter, Resolver, ResolverMarkers, ResolverProvider, VersionsResponse,
 | 
				
			||||||
    WheelMetadataResult,
 | 
					    WheelMetadataResult,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
pub use version_map::VersionMap;
 | 
					pub use version_map::VersionMap;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,12 +7,13 @@ use petgraph::Direction;
 | 
				
			||||||
use rustc_hash::{FxBuildHasher, FxHashMap};
 | 
					use rustc_hash::{FxBuildHasher, FxHashMap};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use distribution_types::{DistributionMetadata, Name, SourceAnnotation, SourceAnnotations};
 | 
					use distribution_types::{DistributionMetadata, Name, SourceAnnotation, SourceAnnotations};
 | 
				
			||||||
use pep508_rs::MarkerEnvironment;
 | 
					 | 
				
			||||||
use pep508_rs::MarkerTree;
 | 
					use pep508_rs::MarkerTree;
 | 
				
			||||||
use uv_normalize::PackageName;
 | 
					use uv_normalize::PackageName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
 | 
					use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
 | 
				
			||||||
use crate::{marker, ResolutionGraph};
 | 
					use crate::{marker, ResolutionGraph, ResolverMarkers};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static UNIVERSAL_MARKERS: ResolverMarkers = ResolverMarkers::Universal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A [`std::fmt::Display`] implementation for the resolution graph.
 | 
					/// A [`std::fmt::Display`] implementation for the resolution graph.
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					@ -21,7 +22,7 @@ pub struct DisplayResolutionGraph<'a> {
 | 
				
			||||||
    /// The underlying graph.
 | 
					    /// The underlying graph.
 | 
				
			||||||
    resolution: &'a ResolutionGraph,
 | 
					    resolution: &'a ResolutionGraph,
 | 
				
			||||||
    /// The marker environment, used to determine the markers that apply to each package.
 | 
					    /// The marker environment, used to determine the markers that apply to each package.
 | 
				
			||||||
    marker_env: Option<&'a MarkerEnvironment>,
 | 
					    marker_env: &'a ResolverMarkers,
 | 
				
			||||||
    /// The packages to exclude from the output.
 | 
					    /// The packages to exclude from the output.
 | 
				
			||||||
    no_emit_packages: &'a [PackageName],
 | 
					    no_emit_packages: &'a [PackageName],
 | 
				
			||||||
    /// Whether to include hashes in the output.
 | 
					    /// Whether to include hashes in the output.
 | 
				
			||||||
| 
						 | 
					@ -50,7 +51,7 @@ impl<'a> From<&'a ResolutionGraph> for DisplayResolutionGraph<'a> {
 | 
				
			||||||
    fn from(resolution: &'a ResolutionGraph) -> Self {
 | 
					    fn from(resolution: &'a ResolutionGraph) -> Self {
 | 
				
			||||||
        Self::new(
 | 
					        Self::new(
 | 
				
			||||||
            resolution,
 | 
					            resolution,
 | 
				
			||||||
            None,
 | 
					            &UNIVERSAL_MARKERS,
 | 
				
			||||||
            &[],
 | 
					            &[],
 | 
				
			||||||
            false,
 | 
					            false,
 | 
				
			||||||
            false,
 | 
					            false,
 | 
				
			||||||
| 
						 | 
					@ -67,7 +68,7 @@ impl<'a> DisplayResolutionGraph<'a> {
 | 
				
			||||||
    #[allow(clippy::fn_params_excessive_bools)]
 | 
					    #[allow(clippy::fn_params_excessive_bools)]
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(
 | 
				
			||||||
        underlying: &'a ResolutionGraph,
 | 
					        underlying: &'a ResolutionGraph,
 | 
				
			||||||
        marker_env: Option<&'a MarkerEnvironment>,
 | 
					        marker_env: &'a ResolverMarkers,
 | 
				
			||||||
        no_emit_packages: &'a [PackageName],
 | 
					        no_emit_packages: &'a [PackageName],
 | 
				
			||||||
        show_hashes: bool,
 | 
					        show_hashes: bool,
 | 
				
			||||||
        include_extras: bool,
 | 
					        include_extras: bool,
 | 
				
			||||||
| 
						 | 
					@ -97,12 +98,9 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
 | 
				
			||||||
        let sources = if self.include_annotations {
 | 
					        let sources = if self.include_annotations {
 | 
				
			||||||
            let mut sources = SourceAnnotations::default();
 | 
					            let mut sources = SourceAnnotations::default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for requirement in self
 | 
					            for requirement in self.resolution.requirements.iter().filter(|requirement| {
 | 
				
			||||||
                .resolution
 | 
					                requirement.evaluate_markers(self.marker_env.marker_environment(), &[])
 | 
				
			||||||
                .requirements
 | 
					            }) {
 | 
				
			||||||
                .iter()
 | 
					 | 
				
			||||||
                .filter(|requirement| requirement.evaluate_markers(self.marker_env, &[]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                if let Some(origin) = &requirement.origin {
 | 
					                if let Some(origin) = &requirement.origin {
 | 
				
			||||||
                    sources.add(
 | 
					                    sources.add(
 | 
				
			||||||
                        &requirement.name,
 | 
					                        &requirement.name,
 | 
				
			||||||
| 
						 | 
					@ -115,7 +113,9 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
 | 
				
			||||||
                .resolution
 | 
					                .resolution
 | 
				
			||||||
                .constraints
 | 
					                .constraints
 | 
				
			||||||
                .requirements()
 | 
					                .requirements()
 | 
				
			||||||
                .filter(|requirement| requirement.evaluate_markers(self.marker_env, &[]))
 | 
					                .filter(|requirement| {
 | 
				
			||||||
 | 
					                    requirement.evaluate_markers(self.marker_env.marker_environment(), &[])
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if let Some(origin) = &requirement.origin {
 | 
					                if let Some(origin) = &requirement.origin {
 | 
				
			||||||
                    sources.add(
 | 
					                    sources.add(
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,9 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
 | 
				
			||||||
                .resolution
 | 
					                .resolution
 | 
				
			||||||
                .overrides
 | 
					                .overrides
 | 
				
			||||||
                .requirements()
 | 
					                .requirements()
 | 
				
			||||||
                .filter(|requirement| requirement.evaluate_markers(self.marker_env, &[]))
 | 
					                .filter(|requirement| {
 | 
				
			||||||
 | 
					                    requirement.evaluate_markers(self.marker_env.marker_environment(), &[])
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if let Some(origin) = &requirement.origin {
 | 
					                if let Some(origin) = &requirement.origin {
 | 
				
			||||||
                    sources.add(
 | 
					                    sources.add(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,9 +28,10 @@ use distribution_types::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
pub(crate) use locals::ForkLocals;
 | 
					pub(crate) use locals::ForkLocals;
 | 
				
			||||||
use pep440_rs::{Version, MIN_VERSION};
 | 
					use pep440_rs::{Version, MIN_VERSION};
 | 
				
			||||||
use pep508_rs::{MarkerEnvironment, MarkerTree};
 | 
					use pep508_rs::MarkerTree;
 | 
				
			||||||
use platform_tags::Tags;
 | 
					use platform_tags::Tags;
 | 
				
			||||||
use pypi_types::{Metadata23, Requirement, VerbatimParsedUrl};
 | 
					use pypi_types::{Metadata23, Requirement, VerbatimParsedUrl};
 | 
				
			||||||
 | 
					pub use resolver_markers::ResolverMarkers;
 | 
				
			||||||
pub(crate) use urls::Urls;
 | 
					pub(crate) use urls::Urls;
 | 
				
			||||||
use uv_configuration::{Constraints, Overrides};
 | 
					use uv_configuration::{Constraints, Overrides};
 | 
				
			||||||
use uv_distribution::{ArchiveMetadata, DistributionDatabase};
 | 
					use uv_distribution::{ArchiveMetadata, DistributionDatabase};
 | 
				
			||||||
| 
						 | 
					@ -73,6 +74,7 @@ mod index;
 | 
				
			||||||
mod locals;
 | 
					mod locals;
 | 
				
			||||||
mod provider;
 | 
					mod provider;
 | 
				
			||||||
mod reporter;
 | 
					mod reporter;
 | 
				
			||||||
 | 
					mod resolver_markers;
 | 
				
			||||||
mod urls;
 | 
					mod urls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Resolver<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider> {
 | 
					pub struct Resolver<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider> {
 | 
				
			||||||
| 
						 | 
					@ -94,8 +96,7 @@ struct ResolverState<InstalledPackages: InstalledPackagesProvider> {
 | 
				
			||||||
    urls: Urls,
 | 
					    urls: Urls,
 | 
				
			||||||
    dependency_mode: DependencyMode,
 | 
					    dependency_mode: DependencyMode,
 | 
				
			||||||
    hasher: HashStrategy,
 | 
					    hasher: HashStrategy,
 | 
				
			||||||
    /// When not set, the resolver is in "universal" mode.
 | 
					    markers: ResolverMarkers,
 | 
				
			||||||
    markers: Option<MarkerEnvironment>,
 | 
					 | 
				
			||||||
    python_requirement: PythonRequirement,
 | 
					    python_requirement: PythonRequirement,
 | 
				
			||||||
    /// This is derived from `PythonRequirement` once at initialization
 | 
					    /// This is derived from `PythonRequirement` once at initialization
 | 
				
			||||||
    /// time. It's used in universal mode to filter our dependencies with
 | 
					    /// time. It's used in universal mode to filter our dependencies with
 | 
				
			||||||
| 
						 | 
					@ -140,7 +141,7 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
 | 
				
			||||||
        manifest: Manifest,
 | 
					        manifest: Manifest,
 | 
				
			||||||
        options: Options,
 | 
					        options: Options,
 | 
				
			||||||
        python_requirement: &'a PythonRequirement,
 | 
					        python_requirement: &'a PythonRequirement,
 | 
				
			||||||
        markers: Option<&'a MarkerEnvironment>,
 | 
					        markers: ResolverMarkers,
 | 
				
			||||||
        tags: Option<&'a Tags>,
 | 
					        tags: Option<&'a Tags>,
 | 
				
			||||||
        flat_index: &'a FlatIndex,
 | 
					        flat_index: &'a FlatIndex,
 | 
				
			||||||
        index: &'a InMemoryIndex,
 | 
					        index: &'a InMemoryIndex,
 | 
				
			||||||
| 
						 | 
					@ -156,7 +157,11 @@ impl<'a, Context: BuildContext, InstalledPackages: InstalledPackagesProvider>
 | 
				
			||||||
            python_requirement
 | 
					            python_requirement
 | 
				
			||||||
                .target()
 | 
					                .target()
 | 
				
			||||||
                .and_then(|target| target.as_requires_python()),
 | 
					                .and_then(|target| target.as_requires_python()),
 | 
				
			||||||
            AllowedYanks::from_manifest(&manifest, markers, options.dependency_mode),
 | 
					            AllowedYanks::from_manifest(
 | 
				
			||||||
 | 
					                &manifest,
 | 
				
			||||||
 | 
					                markers.marker_environment(),
 | 
				
			||||||
 | 
					                options.dependency_mode,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            hasher,
 | 
					            hasher,
 | 
				
			||||||
            options.exclude_newer,
 | 
					            options.exclude_newer,
 | 
				
			||||||
            build_context.build_options(),
 | 
					            build_context.build_options(),
 | 
				
			||||||
| 
						 | 
					@ -184,7 +189,7 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
 | 
				
			||||||
        manifest: Manifest,
 | 
					        manifest: Manifest,
 | 
				
			||||||
        options: Options,
 | 
					        options: Options,
 | 
				
			||||||
        hasher: &HashStrategy,
 | 
					        hasher: &HashStrategy,
 | 
				
			||||||
        markers: Option<&MarkerEnvironment>,
 | 
					        markers: ResolverMarkers,
 | 
				
			||||||
        python_requirement: &PythonRequirement,
 | 
					        python_requirement: &PythonRequirement,
 | 
				
			||||||
        index: &InMemoryIndex,
 | 
					        index: &InMemoryIndex,
 | 
				
			||||||
        git: &GitResolver,
 | 
					        git: &GitResolver,
 | 
				
			||||||
| 
						 | 
					@ -196,9 +201,18 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
 | 
				
			||||||
            git: git.clone(),
 | 
					            git: git.clone(),
 | 
				
			||||||
            unavailable_packages: DashMap::default(),
 | 
					            unavailable_packages: DashMap::default(),
 | 
				
			||||||
            incomplete_packages: DashMap::default(),
 | 
					            incomplete_packages: DashMap::default(),
 | 
				
			||||||
            selector: CandidateSelector::for_resolution(options, &manifest, markers),
 | 
					            selector: CandidateSelector::for_resolution(
 | 
				
			||||||
 | 
					                options,
 | 
				
			||||||
 | 
					                &manifest,
 | 
				
			||||||
 | 
					                markers.marker_environment(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            dependency_mode: options.dependency_mode,
 | 
					            dependency_mode: options.dependency_mode,
 | 
				
			||||||
            urls: Urls::from_manifest(&manifest, markers, git, options.dependency_mode)?,
 | 
					            urls: Urls::from_manifest(
 | 
				
			||||||
 | 
					                &manifest,
 | 
				
			||||||
 | 
					                markers.marker_environment(),
 | 
				
			||||||
 | 
					                git,
 | 
				
			||||||
 | 
					                options.dependency_mode,
 | 
				
			||||||
 | 
					            )?,
 | 
				
			||||||
            project: manifest.project,
 | 
					            project: manifest.project,
 | 
				
			||||||
            requirements: manifest.requirements,
 | 
					            requirements: manifest.requirements,
 | 
				
			||||||
            constraints: manifest.constraints,
 | 
					            constraints: manifest.constraints,
 | 
				
			||||||
| 
						 | 
					@ -207,12 +221,12 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
 | 
				
			||||||
            preferences: manifest.preferences,
 | 
					            preferences: manifest.preferences,
 | 
				
			||||||
            exclusions: manifest.exclusions,
 | 
					            exclusions: manifest.exclusions,
 | 
				
			||||||
            hasher: hasher.clone(),
 | 
					            hasher: hasher.clone(),
 | 
				
			||||||
            markers: markers.cloned(),
 | 
					            requires_python: if markers.marker_environment().is_some() {
 | 
				
			||||||
            requires_python: if markers.is_some() {
 | 
					 | 
				
			||||||
                None
 | 
					                None
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                python_requirement.to_marker_tree()
 | 
					                python_requirement.to_marker_tree()
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            markers,
 | 
				
			||||||
            python_requirement: python_requirement.clone(),
 | 
					            python_requirement: python_requirement.clone(),
 | 
				
			||||||
            reporter: None,
 | 
					            reporter: None,
 | 
				
			||||||
            installed_packages,
 | 
					            installed_packages,
 | 
				
			||||||
| 
						 | 
					@ -296,7 +310,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
            fork_locals: ForkLocals::default(),
 | 
					            fork_locals: ForkLocals::default(),
 | 
				
			||||||
            priorities: PubGrubPriorities::default(),
 | 
					            priorities: PubGrubPriorities::default(),
 | 
				
			||||||
            added_dependencies: FxHashMap::default(),
 | 
					            added_dependencies: FxHashMap::default(),
 | 
				
			||||||
            markers: MarkerTree::And(vec![]),
 | 
					            markers: self.markers.clone(),
 | 
				
			||||||
            python_requirement: self.python_requirement.clone(),
 | 
					            python_requirement: self.python_requirement.clone(),
 | 
				
			||||||
            requires_python: self.requires_python.clone(),
 | 
					            requires_python: self.requires_python.clone(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
| 
						 | 
					@ -305,14 +319,14 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        let mut resolutions = vec![];
 | 
					        let mut resolutions = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'FORK: while let Some(mut state) = forked_states.pop() {
 | 
					        'FORK: while let Some(mut state) = forked_states.pop() {
 | 
				
			||||||
            if !state.markers.is_universal() {
 | 
					            if let ResolverMarkers::Fork(markers) = &state.markers {
 | 
				
			||||||
                if let Some(requires_python) = state.requires_python.as_ref() {
 | 
					                if let Some(requires_python) = state.requires_python.as_ref() {
 | 
				
			||||||
                    debug!(
 | 
					                    debug!(
 | 
				
			||||||
                        "Solving split {} (requires-python: {})",
 | 
					                        "Solving split {} (requires-python: {})",
 | 
				
			||||||
                        state.markers, requires_python
 | 
					                        markers, requires_python
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    debug!("Solving split {}", state.markers);
 | 
					                    debug!("Solving split {}", markers);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            let start = Instant::now();
 | 
					            let start = Instant::now();
 | 
				
			||||||
| 
						 | 
					@ -321,7 +335,8 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                if let Err(err) = state.pubgrub.unit_propagation(state.next.clone()) {
 | 
					                if let Err(err) = state.pubgrub.unit_propagation(state.next.clone()) {
 | 
				
			||||||
                    return Err(self.convert_no_solution_err(
 | 
					                    return Err(self.convert_no_solution_err(
 | 
				
			||||||
                        err,
 | 
					                        err,
 | 
				
			||||||
                        state.fork_urls.clone(),
 | 
					                        state.fork_urls,
 | 
				
			||||||
 | 
					                        state.markers,
 | 
				
			||||||
                        &visited,
 | 
					                        &visited,
 | 
				
			||||||
                        &index_locations,
 | 
					                        &index_locations,
 | 
				
			||||||
                    ));
 | 
					                    ));
 | 
				
			||||||
| 
						 | 
					@ -348,7 +363,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                        prefetcher.log_tried_versions();
 | 
					                        prefetcher.log_tried_versions();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    debug!(
 | 
					                    debug!(
 | 
				
			||||||
                        "Split {} took {:.3}s",
 | 
					                        "Split {} resolution took {:.3}s",
 | 
				
			||||||
                        state.markers,
 | 
					                        state.markers,
 | 
				
			||||||
                        start.elapsed().as_secs_f32()
 | 
					                        start.elapsed().as_secs_f32()
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
| 
						 | 
					@ -540,15 +555,15 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                                    cur_state = Some(forked_state.clone());
 | 
					                                    cur_state = Some(forked_state.clone());
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                forked_state.markers.and(fork.markers);
 | 
					                                let combined_markers = forked_state.markers.and(fork.markers);
 | 
				
			||||||
                                forked_state.markers = normalize(forked_state.markers, None)
 | 
					                                let combined_markers = normalize(combined_markers, None)
 | 
				
			||||||
                                    .unwrap_or(MarkerTree::And(Vec::new()));
 | 
					                                    .expect("Fork markers are universal");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                // If the fork contains a narrowed Python requirement, apply it.
 | 
					                                // If the fork contains a narrowed Python requirement, apply it.
 | 
				
			||||||
                                let python_requirement = requires_python_marker(
 | 
					                                let python_requirement = requires_python_marker(&combined_markers)
 | 
				
			||||||
                                    &forked_state.markers,
 | 
					                                    .and_then(|marker| {
 | 
				
			||||||
                                )
 | 
					                                        forked_state.python_requirement.narrow(&marker)
 | 
				
			||||||
                                .and_then(|marker| forked_state.python_requirement.narrow(&marker));
 | 
					                                    });
 | 
				
			||||||
                                if let Some(python_requirement) = python_requirement {
 | 
					                                if let Some(python_requirement) = python_requirement {
 | 
				
			||||||
                                    if let Some(target) = python_requirement.target() {
 | 
					                                    if let Some(target) = python_requirement.target() {
 | 
				
			||||||
                                        debug!("Narrowed `requires-python` bound to: {target}");
 | 
					                                        debug!("Narrowed `requires-python` bound to: {target}");
 | 
				
			||||||
| 
						 | 
					@ -562,6 +577,8 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                                    forked_state.python_requirement = python_requirement;
 | 
					                                    forked_state.python_requirement = python_requirement;
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                forked_state.markers = ResolverMarkers::Fork(combined_markers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                forked_state.add_package_version_dependencies(
 | 
					                                forked_state.add_package_version_dependencies(
 | 
				
			||||||
                                    for_package.as_deref(),
 | 
					                                    for_package.as_deref(),
 | 
				
			||||||
                                    &version,
 | 
					                                    &version,
 | 
				
			||||||
| 
						 | 
					@ -584,18 +601,11 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                forked_states.push(forked_state);
 | 
					                                forked_states.push(forked_state);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            if markers.is_universal() {
 | 
					                            debug!(
 | 
				
			||||||
                                debug!(
 | 
					                                "Pre-fork split {} took {:.3}s",
 | 
				
			||||||
                                    "Pre-fork split universal took {:.3}s",
 | 
					                                markers,
 | 
				
			||||||
                                    start.elapsed().as_secs_f32()
 | 
					                                start.elapsed().as_secs_f32()
 | 
				
			||||||
                                );
 | 
					                            );
 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                debug!(
 | 
					 | 
				
			||||||
                                    "Pre-fork split {} took {:.3}s",
 | 
					 | 
				
			||||||
                                    markers,
 | 
					 | 
				
			||||||
                                    start.elapsed().as_secs_f32()
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            continue 'FORK;
 | 
					                            continue 'FORK;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -1083,7 +1093,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        version: &Version,
 | 
					        version: &Version,
 | 
				
			||||||
        fork_urls: &ForkUrls,
 | 
					        fork_urls: &ForkUrls,
 | 
				
			||||||
        fork_locals: &ForkLocals,
 | 
					        fork_locals: &ForkLocals,
 | 
				
			||||||
        markers: &MarkerTree,
 | 
					        markers: &ResolverMarkers,
 | 
				
			||||||
        requires_python: Option<&MarkerTree>,
 | 
					        requires_python: Option<&MarkerTree>,
 | 
				
			||||||
    ) -> Result<ForkedDependencies, ResolveError> {
 | 
					    ) -> Result<ForkedDependencies, ResolveError> {
 | 
				
			||||||
        let result = self.get_dependencies(
 | 
					        let result = self.get_dependencies(
 | 
				
			||||||
| 
						 | 
					@ -1094,13 +1104,13 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
            markers,
 | 
					            markers,
 | 
				
			||||||
            requires_python,
 | 
					            requires_python,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        if self.markers.is_some() {
 | 
					        match markers {
 | 
				
			||||||
            return result.map(|deps| match deps {
 | 
					            ResolverMarkers::SpecificEnvironment(_) => result.map(|deps| match deps {
 | 
				
			||||||
                Dependencies::Available(deps) => ForkedDependencies::Unforked(deps),
 | 
					                Dependencies::Available(deps) => ForkedDependencies::Unforked(deps),
 | 
				
			||||||
                Dependencies::Unavailable(err) => ForkedDependencies::Unavailable(err),
 | 
					                Dependencies::Unavailable(err) => ForkedDependencies::Unavailable(err),
 | 
				
			||||||
            });
 | 
					            }),
 | 
				
			||||||
 | 
					            ResolverMarkers::Universal | ResolverMarkers::Fork(_) => Ok(result?.fork()),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(result?.fork())
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Given a candidate package and version, return its dependencies.
 | 
					    /// Given a candidate package and version, return its dependencies.
 | 
				
			||||||
| 
						 | 
					@ -1111,7 +1121,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        version: &Version,
 | 
					        version: &Version,
 | 
				
			||||||
        fork_urls: &ForkUrls,
 | 
					        fork_urls: &ForkUrls,
 | 
				
			||||||
        fork_locals: &ForkLocals,
 | 
					        fork_locals: &ForkLocals,
 | 
				
			||||||
        markers: &MarkerTree,
 | 
					        markers: &ResolverMarkers,
 | 
				
			||||||
        requires_python: Option<&MarkerTree>,
 | 
					        requires_python: Option<&MarkerTree>,
 | 
				
			||||||
    ) -> Result<Dependencies, ResolveError> {
 | 
					    ) -> Result<Dependencies, ResolveError> {
 | 
				
			||||||
        let url = package.name().and_then(|name| fork_urls.get(name));
 | 
					        let url = package.name().and_then(|name| fork_urls.get(name));
 | 
				
			||||||
| 
						 | 
					@ -1383,7 +1393,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        extra: Option<&'a ExtraName>,
 | 
					        extra: Option<&'a ExtraName>,
 | 
				
			||||||
        dev: Option<&'a GroupName>,
 | 
					        dev: Option<&'a GroupName>,
 | 
				
			||||||
        name: Option<&PackageName>,
 | 
					        name: Option<&PackageName>,
 | 
				
			||||||
        markers: &'a MarkerTree,
 | 
					        markers: &'a ResolverMarkers,
 | 
				
			||||||
        requires_python: Option<&'a MarkerTree>,
 | 
					        requires_python: Option<&'a MarkerTree>,
 | 
				
			||||||
    ) -> Vec<Cow<'a, Requirement>> {
 | 
					    ) -> Vec<Cow<'a, Requirement>> {
 | 
				
			||||||
        // Start with the requirements for the current extra of the package (for an extra
 | 
					        // Start with the requirements for the current extra of the package (for an extra
 | 
				
			||||||
| 
						 | 
					@ -1448,7 +1458,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        &'data self,
 | 
					        &'data self,
 | 
				
			||||||
        dependencies: impl IntoIterator<Item = &'data Requirement> + 'parameters,
 | 
					        dependencies: impl IntoIterator<Item = &'data Requirement> + 'parameters,
 | 
				
			||||||
        extra: Option<&'parameters ExtraName>,
 | 
					        extra: Option<&'parameters ExtraName>,
 | 
				
			||||||
        markers: &'parameters MarkerTree,
 | 
					        markers: &'parameters ResolverMarkers,
 | 
				
			||||||
        requires_python: Option<&'parameters MarkerTree>,
 | 
					        requires_python: Option<&'parameters MarkerTree>,
 | 
				
			||||||
    ) -> impl Iterator<Item = Cow<'data, Requirement>> + 'parameters
 | 
					    ) -> impl Iterator<Item = Cow<'data, Requirement>> + 'parameters
 | 
				
			||||||
    where
 | 
					    where
 | 
				
			||||||
| 
						 | 
					@ -1469,31 +1479,31 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                    return false;
 | 
					                    return false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // If we're in universal mode, `fork_markers` might correspond to a
 | 
					                // If we're in a fork in universal mode, ignore any dependency that isn't part of
 | 
				
			||||||
                // non-trivial marker expression that provoked the resolver to fork.
 | 
					                // this fork (but will be part of another fork).
 | 
				
			||||||
                // In that case, we should ignore any dependency that cannot possibly
 | 
					                if let ResolverMarkers::Fork(markers) = markers {
 | 
				
			||||||
                // satisfy the markers that provoked the fork.
 | 
					                    if !possible_to_satisfy_markers(markers, requirement) {
 | 
				
			||||||
                if !possible_to_satisfy_markers(markers, requirement) {
 | 
					                        trace!("skipping {requirement} because of context resolver markers {markers}");
 | 
				
			||||||
                    trace!("skipping {requirement} because of context resolver markers {markers}");
 | 
					                        return false;
 | 
				
			||||||
                    return false;
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // If the requirement isn't relevant for the current platform, skip it.
 | 
					                // If the requirement isn't relevant for the current platform, skip it.
 | 
				
			||||||
                match extra {
 | 
					                match extra {
 | 
				
			||||||
                    Some(source_extra) => {
 | 
					                    Some(source_extra) => {
 | 
				
			||||||
                        // Only include requirements that are relevant for the current extra.
 | 
					                        // Only include requirements that are relevant for the current extra.
 | 
				
			||||||
                        if requirement.evaluate_markers(self.markers.as_ref(), &[]) {
 | 
					                        if requirement.evaluate_markers(markers.marker_environment(), &[]) {
 | 
				
			||||||
                            return false;
 | 
					                            return false;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        if !requirement.evaluate_markers(
 | 
					                        if !requirement.evaluate_markers(
 | 
				
			||||||
                            self.markers.as_ref(),
 | 
					                            markers.marker_environment(),
 | 
				
			||||||
                            std::slice::from_ref(source_extra),
 | 
					                            std::slice::from_ref(source_extra),
 | 
				
			||||||
                        ) {
 | 
					                        ) {
 | 
				
			||||||
                            return false;
 | 
					                            return false;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    None => {
 | 
					                    None => {
 | 
				
			||||||
                        if !requirement.evaluate_markers(self.markers.as_ref(), &[]) {
 | 
					                        if !requirement.evaluate_markers(markers.marker_environment(), &[]) {
 | 
				
			||||||
                            return false;
 | 
					                            return false;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -1516,23 +1526,27 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
                                return false;
 | 
					                                return false;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if !possible_to_satisfy_markers(markers, constraint) {
 | 
					                            // If we're in a fork in universal mode, ignore any dependency that isn't part of
 | 
				
			||||||
                                trace!("skipping {constraint} because of context resolver markers {markers}");
 | 
					                            // this fork (but will be part of another fork).
 | 
				
			||||||
                                return false;
 | 
					                            if let ResolverMarkers::Fork(markers) = markers {
 | 
				
			||||||
 | 
					                                if !possible_to_satisfy_markers(markers, constraint) {
 | 
				
			||||||
 | 
					                                    trace!("skipping {constraint} because of context resolver markers {markers}");
 | 
				
			||||||
 | 
					                                    return false;
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            // If the constraint isn't relevant for the current platform, skip it.
 | 
					                            // If the constraint isn't relevant for the current platform, skip it.
 | 
				
			||||||
                            match extra {
 | 
					                            match extra {
 | 
				
			||||||
                                Some(source_extra) => {
 | 
					                                Some(source_extra) => {
 | 
				
			||||||
                                    if !constraint.evaluate_markers(
 | 
					                                    if !constraint.evaluate_markers(
 | 
				
			||||||
                                        self.markers.as_ref(),
 | 
					                                        markers.marker_environment(),
 | 
				
			||||||
                                        std::slice::from_ref(source_extra),
 | 
					                                        std::slice::from_ref(source_extra),
 | 
				
			||||||
                                    ) {
 | 
					                                    ) {
 | 
				
			||||||
                                        return false;
 | 
					                                        return false;
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                None => {
 | 
					                                None => {
 | 
				
			||||||
                                    if !constraint.evaluate_markers(self.markers.as_ref(), &[]) {
 | 
					                                    if !constraint.evaluate_markers(markers.marker_environment(), &[]) {
 | 
				
			||||||
                                        return false;
 | 
					                                        return false;
 | 
				
			||||||
                                    }
 | 
					                                    }
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
| 
						 | 
					@ -1835,6 +1849,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        mut err: pubgrub::error::NoSolutionError<UvDependencyProvider>,
 | 
					        mut err: pubgrub::error::NoSolutionError<UvDependencyProvider>,
 | 
				
			||||||
        fork_urls: ForkUrls,
 | 
					        fork_urls: ForkUrls,
 | 
				
			||||||
 | 
					        markers: ResolverMarkers,
 | 
				
			||||||
        visited: &FxHashSet<PackageName>,
 | 
					        visited: &FxHashSet<PackageName>,
 | 
				
			||||||
        index_locations: &IndexLocations,
 | 
					        index_locations: &IndexLocations,
 | 
				
			||||||
    ) -> ResolveError {
 | 
					    ) -> ResolveError {
 | 
				
			||||||
| 
						 | 
					@ -1897,6 +1912,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
 | 
				
			||||||
            unavailable_packages,
 | 
					            unavailable_packages,
 | 
				
			||||||
            incomplete_packages,
 | 
					            incomplete_packages,
 | 
				
			||||||
            fork_urls,
 | 
					            fork_urls,
 | 
				
			||||||
 | 
					            markers,
 | 
				
			||||||
        ))
 | 
					        ))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1976,7 +1992,7 @@ struct ForkState {
 | 
				
			||||||
    /// completely disjoint marker expression (i.e., it can never be true given
 | 
					    /// completely disjoint marker expression (i.e., it can never be true given
 | 
				
			||||||
    /// that the marker expression that provoked the fork is true), then that
 | 
					    /// that the marker expression that provoked the fork is true), then that
 | 
				
			||||||
    /// dependency is completely ignored.
 | 
					    /// dependency is completely ignored.
 | 
				
			||||||
    markers: MarkerTree,
 | 
					    markers: ResolverMarkers,
 | 
				
			||||||
    /// The Python requirement for this fork. Defaults to the Python requirement for
 | 
					    /// The Python requirement for this fork. Defaults to the Python requirement for
 | 
				
			||||||
    /// the resolution, but may be narrowed if a `python_version` marker is present
 | 
					    /// the resolution, but may be narrowed if a `python_version` marker is present
 | 
				
			||||||
    /// in a given fork.
 | 
					    /// in a given fork.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								crates/uv-resolver/src/resolver/resolver_markers.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								crates/uv-resolver/src/resolver/resolver_markers.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					use pep508_rs::{MarkerEnvironment, MarkerTree};
 | 
				
			||||||
 | 
					use std::fmt::{Display, Formatter};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					/// Whether we're solving for a specific environment, universally or for a specific fork.
 | 
				
			||||||
 | 
					pub enum ResolverMarkers {
 | 
				
			||||||
 | 
					    /// We're solving for this specific environment only.
 | 
				
			||||||
 | 
					    SpecificEnvironment(MarkerEnvironment),
 | 
				
			||||||
 | 
					    /// We're doing a universal resolution for all environments (a python version
 | 
				
			||||||
 | 
					    /// constraint is expressed separately).
 | 
				
			||||||
 | 
					    Universal,
 | 
				
			||||||
 | 
					    /// We're in a fork of the universal resolution solving only for specific markers.
 | 
				
			||||||
 | 
					    Fork(MarkerTree),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ResolverMarkers {
 | 
				
			||||||
 | 
					    /// Add the markers of an initial or subsequent fork to the current markers.
 | 
				
			||||||
 | 
					    pub(crate) fn and(self, other: MarkerTree) -> MarkerTree {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            ResolverMarkers::Universal => other,
 | 
				
			||||||
 | 
					            ResolverMarkers::Fork(mut current) => {
 | 
				
			||||||
 | 
					                current.and(other);
 | 
				
			||||||
 | 
					                current
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ResolverMarkers::SpecificEnvironment(_) => {
 | 
				
			||||||
 | 
					                unreachable!("Specific environment mode must not fork")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// If solving for a specific environment, return this environment
 | 
				
			||||||
 | 
					    pub fn marker_environment(&self) -> Option<&MarkerEnvironment> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            ResolverMarkers::Universal | ResolverMarkers::Fork(_) => None,
 | 
				
			||||||
 | 
					            ResolverMarkers::SpecificEnvironment(env) => Some(env),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for ResolverMarkers {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            ResolverMarkers::Universal => f.write_str("universal"),
 | 
				
			||||||
 | 
					            ResolverMarkers::SpecificEnvironment(_) => f.write_str("specific environment"),
 | 
				
			||||||
 | 
					            ResolverMarkers::Fork(markers) => {
 | 
				
			||||||
 | 
					                write!(f, "({markers})")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -174,7 +174,7 @@ impl Urls {
 | 
				
			||||||
                .chain(iter::once(verbatim_url.verbatim().to_string()))
 | 
					                .chain(iter::once(verbatim_url.verbatim().to_string()))
 | 
				
			||||||
                .collect();
 | 
					                .collect();
 | 
				
			||||||
            conflicting_urls.sort();
 | 
					            conflicting_urls.sort();
 | 
				
			||||||
            return Err(ResolveError::ConflictingUrls(
 | 
					            return Err(ResolveError::ConflictingUrlsUniversal(
 | 
				
			||||||
                package_name.clone(),
 | 
					                package_name.clone(),
 | 
				
			||||||
                conflicting_urls,
 | 
					                conflicting_urls,
 | 
				
			||||||
            ));
 | 
					            ));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,7 @@ use uv_requirements::{
 | 
				
			||||||
use uv_resolver::{
 | 
					use uv_resolver::{
 | 
				
			||||||
    AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, FlatIndex,
 | 
					    AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, FlatIndex,
 | 
				
			||||||
    InMemoryIndex, OptionsBuilder, PreReleaseMode, PythonRequirement, RequiresPython,
 | 
					    InMemoryIndex, OptionsBuilder, PreReleaseMode, PythonRequirement, RequiresPython,
 | 
				
			||||||
    ResolutionMode,
 | 
					    ResolutionMode, ResolverMarkers,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
					use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
 | 
				
			||||||
use uv_warnings::warn_user;
 | 
					use uv_warnings::warn_user;
 | 
				
			||||||
| 
						 | 
					@ -230,11 +230,14 @@ pub(crate) async fn pip_compile(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Determine the environment for the resolution.
 | 
					    // Determine the environment for the resolution.
 | 
				
			||||||
    let (tags, markers) = if universal {
 | 
					    let (tags, markers) = if universal {
 | 
				
			||||||
        (None, None)
 | 
					        (None, ResolverMarkers::Universal)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        let (tags, markers) =
 | 
					        let (tags, markers) =
 | 
				
			||||||
            resolution_environment(python_version, python_platform, &interpreter)?;
 | 
					            resolution_environment(python_version, python_platform, &interpreter)?;
 | 
				
			||||||
        (Some(tags), Some(markers))
 | 
					        (
 | 
				
			||||||
 | 
					            Some(tags),
 | 
				
			||||||
 | 
					            ResolverMarkers::SpecificEnvironment((*markers).clone()),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate, but don't enforce hashes for the requirements.
 | 
					    // Generate, but don't enforce hashes for the requirements.
 | 
				
			||||||
| 
						 | 
					@ -335,7 +338,7 @@ pub(crate) async fn pip_compile(
 | 
				
			||||||
        &Reinstall::None,
 | 
					        &Reinstall::None,
 | 
				
			||||||
        &upgrade,
 | 
					        &upgrade,
 | 
				
			||||||
        tags.as_deref(),
 | 
					        tags.as_deref(),
 | 
				
			||||||
        markers.as_deref(),
 | 
					        markers.clone(),
 | 
				
			||||||
        python_requirement,
 | 
					        python_requirement,
 | 
				
			||||||
        &client,
 | 
					        &client,
 | 
				
			||||||
        &flat_index,
 | 
					        &flat_index,
 | 
				
			||||||
| 
						 | 
					@ -351,8 +354,7 @@ pub(crate) async fn pip_compile(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Ok(resolution) => resolution,
 | 
					        Ok(resolution) => resolution,
 | 
				
			||||||
        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
					        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
				
			||||||
            let report = miette::Report::msg(format!("{err}"))
 | 
					            let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
            eprint!("{report:?}");
 | 
					            eprint!("{report:?}");
 | 
				
			||||||
            return Ok(ExitStatus::Failure);
 | 
					            return Ok(ExitStatus::Failure);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -384,7 +386,7 @@ pub(crate) async fn pip_compile(
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if include_marker_expression {
 | 
					    if include_marker_expression {
 | 
				
			||||||
        if let Some(markers) = markers.as_deref() {
 | 
					        if let ResolverMarkers::SpecificEnvironment(markers) = &markers {
 | 
				
			||||||
            let relevant_markers = resolution.marker_tree(&top_level_index, markers)?;
 | 
					            let relevant_markers = resolution.marker_tree(&top_level_index, markers)?;
 | 
				
			||||||
            writeln!(
 | 
					            writeln!(
 | 
				
			||||||
                writer,
 | 
					                writer,
 | 
				
			||||||
| 
						 | 
					@ -457,7 +459,7 @@ pub(crate) async fn pip_compile(
 | 
				
			||||||
        "{}",
 | 
					        "{}",
 | 
				
			||||||
        DisplayResolutionGraph::new(
 | 
					        DisplayResolutionGraph::new(
 | 
				
			||||||
            &resolution,
 | 
					            &resolution,
 | 
				
			||||||
            markers.as_deref(),
 | 
					            &markers,
 | 
				
			||||||
            &no_emit_packages,
 | 
					            &no_emit_packages,
 | 
				
			||||||
            generate_hashes,
 | 
					            generate_hashes,
 | 
				
			||||||
            include_extras,
 | 
					            include_extras,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ use uv_python::{
 | 
				
			||||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
 | 
					use uv_requirements::{RequirementsSource, RequirementsSpecification};
 | 
				
			||||||
use uv_resolver::{
 | 
					use uv_resolver::{
 | 
				
			||||||
    DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PreReleaseMode, PythonRequirement,
 | 
					    DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PreReleaseMode, PythonRequirement,
 | 
				
			||||||
    ResolutionMode,
 | 
					    ResolutionMode, ResolverMarkers,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_types::{BuildIsolation, HashStrategy};
 | 
					use uv_types::{BuildIsolation, HashStrategy};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,7 +326,7 @@ pub(crate) async fn pip_install(
 | 
				
			||||||
        &reinstall,
 | 
					        &reinstall,
 | 
				
			||||||
        &upgrade,
 | 
					        &upgrade,
 | 
				
			||||||
        Some(&tags),
 | 
					        Some(&tags),
 | 
				
			||||||
        Some(&markers),
 | 
					        ResolverMarkers::SpecificEnvironment((*markers).clone()),
 | 
				
			||||||
        python_requirement,
 | 
					        python_requirement,
 | 
				
			||||||
        &client,
 | 
					        &client,
 | 
				
			||||||
        &flat_index,
 | 
					        &flat_index,
 | 
				
			||||||
| 
						 | 
					@ -342,8 +342,7 @@ pub(crate) async fn pip_install(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Ok(resolution) => Resolution::from(resolution),
 | 
					        Ok(resolution) => Resolution::from(resolution),
 | 
				
			||||||
        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
					        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
				
			||||||
            let report = miette::Report::msg(format!("{err}"))
 | 
					            let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
            eprint!("{report:?}");
 | 
					            eprint!("{report:?}");
 | 
				
			||||||
            return Ok(ExitStatus::Failure);
 | 
					            return Ok(ExitStatus::Failure);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,6 @@ use distribution_types::{
 | 
				
			||||||
    DistributionMetadata, IndexLocations, InstalledMetadata, LocalDist, Name, Resolution,
 | 
					    DistributionMetadata, IndexLocations, InstalledMetadata, LocalDist, Name, Resolution,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use install_wheel_rs::linker::LinkMode;
 | 
					use install_wheel_rs::linker::LinkMode;
 | 
				
			||||||
use pep508_rs::MarkerEnvironment;
 | 
					 | 
				
			||||||
use platform_tags::Tags;
 | 
					use platform_tags::Tags;
 | 
				
			||||||
use pypi_types::Requirement;
 | 
					use pypi_types::Requirement;
 | 
				
			||||||
use uv_cache::Cache;
 | 
					use uv_cache::Cache;
 | 
				
			||||||
| 
						 | 
					@ -37,7 +36,7 @@ use uv_requirements::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_resolver::{
 | 
					use uv_resolver::{
 | 
				
			||||||
    DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, Preference,
 | 
					    DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, Preference,
 | 
				
			||||||
    Preferences, PythonRequirement, ResolutionGraph, Resolver,
 | 
					    Preferences, PythonRequirement, ResolutionGraph, Resolver, ResolverMarkers,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_types::{HashStrategy, InFlight, InstalledPackagesProvider};
 | 
					use uv_types::{HashStrategy, InFlight, InstalledPackagesProvider};
 | 
				
			||||||
use uv_warnings::warn_user;
 | 
					use uv_warnings::warn_user;
 | 
				
			||||||
| 
						 | 
					@ -88,7 +87,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
 | 
				
			||||||
    reinstall: &Reinstall,
 | 
					    reinstall: &Reinstall,
 | 
				
			||||||
    upgrade: &Upgrade,
 | 
					    upgrade: &Upgrade,
 | 
				
			||||||
    tags: Option<&Tags>,
 | 
					    tags: Option<&Tags>,
 | 
				
			||||||
    markers: Option<&MarkerEnvironment>,
 | 
					    markers: ResolverMarkers,
 | 
				
			||||||
    python_requirement: PythonRequirement,
 | 
					    python_requirement: PythonRequirement,
 | 
				
			||||||
    client: &RegistryClient,
 | 
					    client: &RegistryClient,
 | 
				
			||||||
    flat_index: &FlatIndex,
 | 
					    flat_index: &FlatIndex,
 | 
				
			||||||
| 
						 | 
					@ -188,7 +187,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
 | 
				
			||||||
            .chain(upgrade.constraints().cloned()),
 | 
					            .chain(upgrade.constraints().cloned()),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    let overrides = Overrides::from_requirements(overrides);
 | 
					    let overrides = Overrides::from_requirements(overrides);
 | 
				
			||||||
    let preferences = Preferences::from_iter(preferences, markers);
 | 
					    let preferences = Preferences::from_iter(preferences, markers.marker_environment());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Determine any lookahead requirements.
 | 
					    // Determine any lookahead requirements.
 | 
				
			||||||
    let lookaheads = match options.dependency_mode {
 | 
					    let lookaheads = match options.dependency_mode {
 | 
				
			||||||
| 
						 | 
					@ -203,7 +202,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
 | 
				
			||||||
                DistributionDatabase::new(client, build_dispatch, concurrency.downloads, preview),
 | 
					                DistributionDatabase::new(client, build_dispatch, concurrency.downloads, preview),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .with_reporter(ResolverReporter::from(printer))
 | 
					            .with_reporter(ResolverReporter::from(printer))
 | 
				
			||||||
            .resolve(markers)
 | 
					            .resolve(&markers)
 | 
				
			||||||
            .await?
 | 
					            .await?
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        DependencyMode::Direct => Vec::new(),
 | 
					        DependencyMode::Direct => Vec::new(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ use uv_python::{
 | 
				
			||||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
 | 
					use uv_requirements::{RequirementsSource, RequirementsSpecification};
 | 
				
			||||||
use uv_resolver::{
 | 
					use uv_resolver::{
 | 
				
			||||||
    DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PreReleaseMode, PythonRequirement,
 | 
					    DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PreReleaseMode, PythonRequirement,
 | 
				
			||||||
    ResolutionMode,
 | 
					    ResolutionMode, ResolverMarkers,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_types::{BuildIsolation, HashStrategy};
 | 
					use uv_types::{BuildIsolation, HashStrategy};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -281,7 +281,7 @@ pub(crate) async fn pip_sync(
 | 
				
			||||||
        &reinstall,
 | 
					        &reinstall,
 | 
				
			||||||
        &upgrade,
 | 
					        &upgrade,
 | 
				
			||||||
        Some(&tags),
 | 
					        Some(&tags),
 | 
				
			||||||
        Some(&markers),
 | 
					        ResolverMarkers::SpecificEnvironment((*markers).clone()),
 | 
				
			||||||
        python_requirement,
 | 
					        python_requirement,
 | 
				
			||||||
        &client,
 | 
					        &client,
 | 
				
			||||||
        &flat_index,
 | 
					        &flat_index,
 | 
				
			||||||
| 
						 | 
					@ -297,8 +297,7 @@ pub(crate) async fn pip_sync(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Ok(resolution) => Resolution::from(resolution),
 | 
					        Ok(resolution) => Resolution::from(resolution),
 | 
				
			||||||
        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
					        Err(operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err))) => {
 | 
				
			||||||
            let report = miette::Report::msg(format!("{err}"))
 | 
					            let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
            eprint!("{report:?}");
 | 
					            eprint!("{report:?}");
 | 
				
			||||||
            return Ok(ExitStatus::Failure);
 | 
					            return Ok(ExitStatus::Failure);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,9 @@ use uv_git::ResolvedRepositoryReference;
 | 
				
			||||||
use uv_normalize::PackageName;
 | 
					use uv_normalize::PackageName;
 | 
				
			||||||
use uv_python::{Interpreter, PythonFetch, PythonPreference, PythonRequest};
 | 
					use uv_python::{Interpreter, PythonFetch, PythonPreference, PythonRequest};
 | 
				
			||||||
use uv_requirements::upgrade::{read_lock_requirements, LockedRequirements};
 | 
					use uv_requirements::upgrade::{read_lock_requirements, LockedRequirements};
 | 
				
			||||||
use uv_resolver::{FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython};
 | 
					use uv_resolver::{
 | 
				
			||||||
 | 
					    FlatIndex, Lock, OptionsBuilder, PythonRequirement, RequiresPython, ResolverMarkers,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
 | 
					use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
 | 
				
			||||||
use uv_warnings::{warn_user, warn_user_once};
 | 
					use uv_warnings::{warn_user, warn_user_once};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,8 +90,7 @@ pub(crate) async fn lock(
 | 
				
			||||||
        Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
					        Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
				
			||||||
            uv_resolver::ResolveError::NoSolution(err),
 | 
					            uv_resolver::ResolveError::NoSolution(err),
 | 
				
			||||||
        ))) => {
 | 
					        ))) => {
 | 
				
			||||||
            let report = miette::Report::msg(format!("{err}"))
 | 
					            let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
            eprint!("{report:?}");
 | 
					            eprint!("{report:?}");
 | 
				
			||||||
            Ok(ExitStatus::Failure)
 | 
					            Ok(ExitStatus::Failure)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -274,7 +275,7 @@ pub(super) async fn do_lock(
 | 
				
			||||||
                &Reinstall::default(),
 | 
					                &Reinstall::default(),
 | 
				
			||||||
                upgrade,
 | 
					                upgrade,
 | 
				
			||||||
                None,
 | 
					                None,
 | 
				
			||||||
                None,
 | 
					                ResolverMarkers::Universal,
 | 
				
			||||||
                python_requirement.clone(),
 | 
					                python_requirement.clone(),
 | 
				
			||||||
                &client,
 | 
					                &client,
 | 
				
			||||||
                &flat_index,
 | 
					                &flat_index,
 | 
				
			||||||
| 
						 | 
					@ -350,7 +351,7 @@ pub(super) async fn do_lock(
 | 
				
			||||||
                &Reinstall::default(),
 | 
					                &Reinstall::default(),
 | 
				
			||||||
                upgrade,
 | 
					                upgrade,
 | 
				
			||||||
                None,
 | 
					                None,
 | 
				
			||||||
                None,
 | 
					                ResolverMarkers::Universal,
 | 
				
			||||||
                python_requirement,
 | 
					                python_requirement,
 | 
				
			||||||
                &client,
 | 
					                &client,
 | 
				
			||||||
                &flat_index,
 | 
					                &flat_index,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,9 @@ use uv_python::{
 | 
				
			||||||
    PythonInstallation, PythonPreference, PythonRequest, VersionRequest,
 | 
					    PythonInstallation, PythonPreference, PythonRequest, VersionRequest,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
 | 
					use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
 | 
				
			||||||
use uv_resolver::{FlatIndex, OptionsBuilder, PythonRequirement, RequiresPython, ResolutionGraph};
 | 
					use uv_resolver::{
 | 
				
			||||||
 | 
					    FlatIndex, OptionsBuilder, PythonRequirement, RequiresPython, ResolutionGraph, ResolverMarkers,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
 | 
					use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
 | 
				
			||||||
use uv_warnings::warn_user;
 | 
					use uv_warnings::warn_user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -485,7 +487,7 @@ pub(crate) async fn resolve_environment<'a>(
 | 
				
			||||||
        &reinstall,
 | 
					        &reinstall,
 | 
				
			||||||
        &upgrade,
 | 
					        &upgrade,
 | 
				
			||||||
        Some(tags),
 | 
					        Some(tags),
 | 
				
			||||||
        Some(markers),
 | 
					        ResolverMarkers::SpecificEnvironment(markers.clone()),
 | 
				
			||||||
        python_requirement,
 | 
					        python_requirement,
 | 
				
			||||||
        &client,
 | 
					        &client,
 | 
				
			||||||
        &flat_index,
 | 
					        &flat_index,
 | 
				
			||||||
| 
						 | 
					@ -737,7 +739,7 @@ pub(crate) async fn update_environment(
 | 
				
			||||||
        reinstall,
 | 
					        reinstall,
 | 
				
			||||||
        upgrade,
 | 
					        upgrade,
 | 
				
			||||||
        Some(tags),
 | 
					        Some(tags),
 | 
				
			||||||
        Some(markers),
 | 
					        ResolverMarkers::SpecificEnvironment(markers.clone()),
 | 
				
			||||||
        python_requirement,
 | 
					        python_requirement,
 | 
				
			||||||
        &client,
 | 
					        &client,
 | 
				
			||||||
        &flat_index,
 | 
					        &flat_index,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,8 +92,7 @@ pub(crate) async fn sync(
 | 
				
			||||||
            Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
					            Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
				
			||||||
                uv_resolver::ResolveError::NoSolution(err),
 | 
					                uv_resolver::ResolveError::NoSolution(err),
 | 
				
			||||||
            ))) => {
 | 
					            ))) => {
 | 
				
			||||||
                let report = miette::Report::msg(format!("{err}"))
 | 
					                let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                    .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
                anstream::eprint!("{report:?}");
 | 
					                anstream::eprint!("{report:?}");
 | 
				
			||||||
                return Ok(ExitStatus::Failure);
 | 
					                return Ok(ExitStatus::Failure);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -133,8 +132,7 @@ pub(crate) async fn sync(
 | 
				
			||||||
            Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
					            Err(ProjectError::Operation(pip::operations::Error::Resolve(
 | 
				
			||||||
                uv_resolver::ResolveError::NoSolution(err),
 | 
					                uv_resolver::ResolveError::NoSolution(err),
 | 
				
			||||||
            ))) => {
 | 
					            ))) => {
 | 
				
			||||||
                let report = miette::Report::msg(format!("{err}"))
 | 
					                let report = miette::Report::msg(format!("{err}")).context(err.header());
 | 
				
			||||||
                    .context("No solution found when resolving dependencies:");
 | 
					 | 
				
			||||||
                anstream::eprint!("{report:?}");
 | 
					                anstream::eprint!("{report:?}");
 | 
				
			||||||
                return Ok(ExitStatus::Failure);
 | 
					                return Ok(ExitStatus::Failure);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -362,7 +362,7 @@ fn conflict_in_fork() -> Result<()> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ----- stderr -----
 | 
					    ----- stderr -----
 | 
				
			||||||
    warning: `uv lock` is experimental and may change without warning.
 | 
					    warning: `uv lock` is experimental and may change without warning.
 | 
				
			||||||
      × No solution found when resolving dependencies:
 | 
					      × No solution found when resolving dependencies for split (sys_platform == 'darwin'):
 | 
				
			||||||
      ╰─▶ Because only package-b==1.0.0 is available and package-b==1.0.0 depends on package-d==1, we can conclude that all versions of package-b depend on package-d==1.
 | 
					      ╰─▶ Because only package-b==1.0.0 is available and package-b==1.0.0 depends on package-d==1, we can conclude that all versions of package-b depend on package-d==1.
 | 
				
			||||||
          And because package-c==1.0.0 depends on package-d==2 and only package-c==1.0.0 is available, we can conclude that all versions of package-b and all versions of package-c are incompatible.
 | 
					          And because package-c==1.0.0 depends on package-d==2 and only package-c==1.0.0 is available, we can conclude that all versions of package-b and all versions of package-c are incompatible.
 | 
				
			||||||
          And because package-a{sys_platform == 'darwin'}==1.0.0 depends on package-b and package-c, we can conclude that package-a{sys_platform == 'darwin'}==1.0.0 cannot be used.
 | 
					          And because package-a{sys_platform == 'darwin'}==1.0.0 depends on package-b and package-c, we can conclude that package-a{sys_platform == 'darwin'}==1.0.0 cannot be used.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6872,7 +6872,7 @@ fn universal_requires_python() -> Result<()> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ----- stderr -----
 | 
					    ----- stderr -----
 | 
				
			||||||
    warning: The requested Python version 3.8 is not available; 3.12.[X] will be used to build dependencies instead.
 | 
					    warning: The requested Python version 3.8 is not available; 3.12.[X] will be used to build dependencies instead.
 | 
				
			||||||
      × No solution found when resolving dependencies:
 | 
					      × No solution found when resolving dependencies for split (python_version >= '3.9'):
 | 
				
			||||||
      ╰─▶ Because only the following versions of numpy{python_version >= '3.9'} are available:
 | 
					      ╰─▶ Because only the following versions of numpy{python_version >= '3.9'} are available:
 | 
				
			||||||
              numpy{python_version >= '3.9'}<=1.26.0
 | 
					              numpy{python_version >= '3.9'}<=1.26.0
 | 
				
			||||||
              numpy{python_version >= '3.9'}==1.26.1
 | 
					              numpy{python_version >= '3.9'}==1.26.1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue