diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 80bd0d4f35ec..1125e8f202a1 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -26,7 +26,7 @@ use distribution_types::{ }; pub(crate) use locals::Locals; use pep440_rs::{Version, MIN_VERSION}; -use pep508_rs::MarkerEnvironment; +use pep508_rs::{MarkerEnvironment, MarkerTree}; use platform_tags::Tags; use pypi_types::{Metadata23, Requirement}; pub(crate) use urls::Urls; @@ -476,45 +476,27 @@ impl ResolverState { - let mut forked_state = cur_state.take().unwrap(); - if !is_last { - cur_state = Some(forked_state.clone()); - } - - forked_state.pubgrub.add_incompatibility( - Incompatibility::custom_version( - package.clone(), - version.clone(), - UnavailableReason::Version(reason), - ), - ); - forked_states.push(forked_state); - continue; - } - Dependencies::Available(constraints) - if constraints - .iter() - .any(|(dependency, _)| dependency == &package) => + match forked_deps { + ForkedDependencies::Unavailable(reason) => { + state + .pubgrub + .add_incompatibility(Incompatibility::custom_version( + package.clone(), + version.clone(), + UnavailableReason::Version(reason), + )); + forked_states.push(state); + } + ForkedDependencies::Unforked(constraints) => { + if constraints + .iter() + .any(|(dependency, _)| dependency == &package) { if enabled!(Level::DEBUG) { prefetcher.log_tried_versions(); @@ -525,28 +507,69 @@ impl ResolverState constraints, - }; - - let mut forked_state = cur_state.take().unwrap(); - if !is_last { - cur_state = Some(forked_state.clone()); - } - // Add that package and version if the dependencies are not problematic. - let dep_incompats = - forked_state.pubgrub.add_incompatibility_from_dependencies( + // Add that package and version if the dependencies are not problematic. + let dep_incompats = + state.pubgrub.add_incompatibility_from_dependencies( + package.clone(), + version.clone(), + constraints, + ); + state.pubgrub.partial_solution.add_version( package.clone(), version.clone(), - dependencies, + dep_incompats, + &state.pubgrub.incompatibility_store, ); - forked_state.pubgrub.partial_solution.add_version( - package.clone(), - version.clone(), - dep_incompats, - &forked_state.pubgrub.incompatibility_store, - ); - forked_states.push(forked_state); + forked_states.push(state); + } + ForkedDependencies::Forked(forks) => { + assert!(forks.len() >= 2); + // This is a somewhat tortured technique to ensure + // that our resolver state is only cloned as much + // as it needs to be. We basically move the state + // into `forked_states`, and then only clone it if + // there it at least one more fork to visit. + let mut cur_state = Some(state); + let forks_len = forks.len(); + for (i, fork) in forks.into_iter().enumerate() { + if fork + .dependencies + .iter() + .any(|(dependency, _)| dependency == &package) + { + if enabled!(Level::DEBUG) { + prefetcher.log_tried_versions(); + } + return Err(PubGrubError::SelfDependency { + package: package.clone(), + version: version.clone(), + } + .into()); + } + + let is_last = i == forks_len - 1; + let mut forked_state = cur_state.take().unwrap(); + if !is_last { + cur_state = Some(forked_state.clone()); + } + + // Add that package and version if the dependencies are not problematic. + let dep_incompats = + forked_state.pubgrub.add_incompatibility_from_dependencies( + package.clone(), + version.clone(), + fork.dependencies, + ); + forked_state.pubgrub.partial_solution.add_version( + package.clone(), + version.clone(), + dep_incompats, + &forked_state.pubgrub.incompatibility_store, + ); + forked_states.push(forked_state); + } + } } continue 'FORK; } @@ -896,62 +919,15 @@ impl ResolverState, - ) -> Result, ResolveError> { - type Dep = (PubGrubPackage, Range); - + ) -> Result { let result = self.get_dependencies(package, version, priorities, request_sink); if self.markers.is_some() { - return result.map(|deps| vec![deps]); + return result.map(|deps| match deps { + Dependencies::Available(deps) => ForkedDependencies::Unforked(deps), + Dependencies::Unavailable(err) => ForkedDependencies::Unavailable(err), + }); } - let deps: Vec = match result? { - Dependencies::Available(deps) => deps, - Dependencies::Unavailable(err) => return Ok(vec![Dependencies::Unavailable(err)]), - }; - - let mut by_grouping: FxHashMap<&PackageName, FxHashMap<&Range, Vec<&Dep>>> = - FxHashMap::default(); - for dep in &deps { - let (ref pkg, ref range) = *dep; - let name = match &**pkg { - // A root can never be a dependency of another package, and a `Python` pubgrub - // package is never returned by `get_dependencies`. So these cases never occur. - // TODO(charlie): This might be overly conservative for `Extra` and `Group`. If - // multiple groups are enabled, we shouldn't need to fork. Similarly, if multiple - // extras are enabled, we shouldn't need to fork. - PubGrubPackageInner::Root(_) | PubGrubPackageInner::Python(_) => unreachable!(), - PubGrubPackageInner::Package { ref name, .. } - | PubGrubPackageInner::Marker { ref name, .. } - | PubGrubPackageInner::Extra { ref name, .. } - | PubGrubPackageInner::Dev { ref name, .. } => name, - }; - by_grouping - .entry(name) - .or_default() - .entry(range) - .or_default() - .push(dep); - } - let mut forks: Vec> = vec![vec![]]; - for (_, groups) in by_grouping { - if groups.len() <= 1 { - for deps in groups.into_values() { - for fork in &mut forks { - fork.extend(deps.iter().map(|dep| (*dep).clone())); - } - } - } else { - let mut new_forks: Vec> = vec![]; - for deps in groups.into_values() { - let mut new_forks_for_group = forks.clone(); - for fork in &mut new_forks_for_group { - fork.extend(deps.iter().map(|dep| (*dep).clone())); - } - new_forks.extend(new_forks_for_group); - } - forks = new_forks; - } - } - Ok(forks.into_iter().map(Dependencies::Available).collect()) + Ok(result?.fork()) } /// Given a candidate package and version, return its dependencies. @@ -1814,6 +1790,246 @@ enum Dependencies { Available(Vec<(PubGrubPackage, Range)>), } +impl Dependencies { + fn fork(self) -> ForkedDependencies { + use std::collections::hash_map::Entry; + + let deps = match self { + Dependencies::Available(deps) => deps, + Dependencies::Unavailable(err) => return ForkedDependencies::Unavailable(err), + }; + + let mut by_name: FxHashMap<&PackageName, PossibleForks> = FxHashMap::default(); + for (index, (ref pkg, _)) in deps.iter().enumerate() { + let (name, marker) = match &**pkg { + // A root can never be a dependency of another package, and a `Python` pubgrub + // package is never returned by `get_dependencies`. So these cases never occur. + PubGrubPackageInner::Root(_) | PubGrubPackageInner::Python(_) => unreachable!(), + PubGrubPackageInner::Package { name, marker, .. } + | PubGrubPackageInner::Extra { name, marker, .. } + | PubGrubPackageInner::Dev { name, marker, .. } => (name, marker.as_ref()), + PubGrubPackageInner::Marker { name, marker, .. } => (name, Some(marker)), + }; + let Some(marker) = marker else { + // When no marker is found, it implies there is a dependency on + // this package that is unconditional with respect to marker + // expressions. Therefore, it should never be the cause of a + // fork since it is necessarily overlapping with every other + // possible marker expression that isn't pathological. + match by_name.entry(name) { + Entry::Vacant(e) => { + e.insert(PossibleForks::NoForkPossible(vec![index])); + } + Entry::Occupied(mut e) => { + e.get_mut().push_unconditional_package(index); + } + } + continue; + }; + let possible_forks = match by_name.entry(name) { + // If one doesn't exist, then this is the first dependency + // with this package name. And since it has a marker, we can + // add it as the initial instance of a possibly forking set of + // dependencies. (A fork will only actually happen if another + // dependency is found with the same package name *and* where + // its marker expression is disjoint with this one.) + Entry::Vacant(e) => { + let possible_fork = PossibleFork { + packages: vec![(index, marker)], + }; + let fork_groups = PossibleForkGroups { + forks: vec![possible_fork], + }; + e.insert(PossibleForks::PossiblyForking(fork_groups)); + continue; + } + // Now that we have a marker, look for an existing entry. If + // one already exists and is "no fork possible," then we know + // we can't fork. + Entry::Occupied(e) => match *e.into_mut() { + PossibleForks::NoForkPossible(ref mut indices) => { + indices.push(index); + continue; + } + PossibleForks::PossiblyForking(ref mut possible_forks) => possible_forks, + }, + }; + // At this point, we know we 1) have a duplicate dependency on + // a package and 2) the original and this one both have marker + // expressions. This still doesn't guarantee that a fork occurs + // though. A fork can only occur when the marker expressions from + // (2) are provably disjoint. Otherwise, we could end up with + // a resolution that would result in installing two different + // versions of the same package. Specifically, this could occur in + // precisely the cases where the marker expressions intersect. + // + // By construction, the marker expressions *in* each fork group + // have some non-empty intersection, and the marker expressions + // *between* each fork group are completely disjoint. So what we do + // is look for a group in which there is some overlap. If so, this + // package gets added to that fork group. Otherwise, we create a + // new fork group. + // possible_forks.push(PossibleFork { packages: vec![] }); + let Some(possible_fork) = possible_forks.find_overlapping_fork_group(marker) else { + // Create a new fork since there was no overlap. + possible_forks.forks.push(PossibleFork { + packages: vec![(index, marker)], + }); + continue; + }; + // Add to an existing fork since there was overlap. + possible_fork.packages.push((index, marker)); + } + // If all possible forks have exactly 1 group, then there is no forking. + if !by_name.values().any(PossibleForks::has_fork) { + return ForkedDependencies::Unforked(deps); + } + let mut forks = vec![Fork { + dependencies: vec![], + }]; + for (_, possible_forks) in by_name { + let fork_groups = match possible_forks { + PossibleForks::PossiblyForking(fork_groups) => fork_groups, + PossibleForks::NoForkPossible(indices) => { + // No fork is provoked by this package, so just add + // everything in this group to each of the forks. + for index in indices { + for fork in &mut forks { + fork.dependencies.push(deps[index].clone()); + } + } + continue; + } + }; + let mut new_forks: Vec = vec![]; + for group in fork_groups.forks { + let mut new_forks_for_group = forks.clone(); + for (index, _) in group.packages { + for fork in &mut new_forks_for_group { + fork.dependencies.push(deps[index].clone()); + } + } + new_forks.extend(new_forks_for_group); + } + forks = new_forks; + } + ForkedDependencies::Forked(forks) + } +} + +#[derive(Debug)] +enum ForkedDependencies { + /// Package dependencies are not available. + Unavailable(UnavailableVersion), + /// No forking occurred. + Unforked(Vec<(PubGrubPackage, Range)>), + /// Forked containers for all available package versions. + /// + /// Note that there is always at least two forks. If there would + /// be fewer than 2 forks, then there is no fork at all and the + /// `Unforked` variant is used instead. + Forked(Vec), +} + +#[derive(Clone, Debug)] +struct Fork { + dependencies: Vec<(PubGrubPackage, Range)>, +} + +#[derive(Debug)] +enum PossibleForks<'a> { + NoForkPossible(Vec), + PossiblyForking(PossibleForkGroups<'a>), +} + +impl<'a> PossibleForks<'a> { + /// Returns true if and only if this contains a fork assuming there are + /// no other dependencies to be considered. + fn has_fork(&self) -> bool { + let PossibleForks::PossiblyForking(ref fork_groups) = *self else { + return false; + }; + fork_groups.forks.len() > 1 + } + + /// Pushes an unconditional index to a package. + /// + /// If this previously contained possible forks, those are combined into + /// one single set of dependencies that can never be forked. + /// + /// That is, adding an unconditional package means it is not disjoint with + /// all other possible dependencies using the same package name. + fn push_unconditional_package(&mut self, index: usize) { + self.make_no_forks_possible(); + let PossibleForks::NoForkPossible(ref mut indices) = *self else { + unreachable!("all forks should be eliminated") + }; + indices.push(index); + } + + /// Convert this set of possible forks into something that can never fork. + /// + /// This is useful in cases where a dependency on a package is found + /// without any marker expressions at all. In this case, it is never + /// possible for this package to provoke a fork. Since it is unconditional, + /// it implies it is never disjoint with any other dependency specification + /// on the same package. (Except for pathological cases of marker + /// expressions that always evaluate to false. But we generally ignore + /// those.) + fn make_no_forks_possible(&mut self) { + let PossibleForks::PossiblyForking(ref fork_groups) = *self else { + return; + }; + let mut indices = vec![]; + for possible_fork in &fork_groups.forks { + for &(index, _) in &possible_fork.packages { + indices.push(index); + } + } + *self = PossibleForks::NoForkPossible(indices); + } +} + +#[derive(Debug)] +struct PossibleForkGroups<'a> { + forks: Vec>, +} + +impl<'a> PossibleForkGroups<'a> { + /// Given a marker expression, if there is a fork in this set of fork + /// groups with non-empty overlap with it, then that fork group is + /// returned. Otherwise, `None` is returned. + fn find_overlapping_fork_group<'g>( + &'g mut self, + marker: &MarkerTree, + ) -> Option<&'g mut PossibleFork<'a>> { + self.forks + .iter_mut() + .find(|fork| fork.is_overlapping(marker)) + } +} + +#[derive(Debug)] +struct PossibleFork<'a> { + packages: Vec<(usize, &'a MarkerTree)>, +} + +impl<'a> PossibleFork<'a> { + /// Returns true if and only if the given marker expression has a non-empty + /// intersection with *any* of the package markers within this possible + /// fork. + fn is_overlapping(&self, marker: &MarkerTree) -> bool { + use crate::marker::is_disjoint; + + for (_, tree) in &self.packages { + if !is_disjoint(marker, tree) { + return true; + } + } + false + } +} + fn uncapitalize>(string: T) -> String { let mut chars = string.as_ref().chars(); match chars.next() { diff --git a/crates/uv/tests/common/mod.rs b/crates/uv/tests/common/mod.rs index c56676cd503d..5f25ac6a1e18 100644 --- a/crates/uv/tests/common/mod.rs +++ b/crates/uv/tests/common/mod.rs @@ -26,7 +26,7 @@ pub static EXCLUDE_NEWER: &str = "2024-03-25T00:00:00Z"; /// Using a find links url allows using `--index-url` instead of `--extra-index-url` in tests /// to prevent dependency confusion attacks against our test suite. pub const BUILD_VENDOR_LINKS_URL: &str = - "https://raw.githubusercontent.com/astral-sh/packse/0.3.17/vendor/links.html"; + "https://raw.githubusercontent.com/astral-sh/packse/0.3.18/vendor/links.html"; #[doc(hidden)] // Macro and test context only, don't use directly. pub const INSTA_FILTERS: &[(&str, &str)] = &[ diff --git a/crates/uv/tests/lock_scenarios.rs b/crates/uv/tests/lock_scenarios.rs index 3edc2a060c2e..d5701b3c0daa 100644 --- a/crates/uv/tests/lock_scenarios.rs +++ b/crates/uv/tests/lock_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi"))] #![allow(clippy::needless_raw_string_hashes)] @@ -44,7 +44,6 @@ fn fork_basic() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-basic-a>=2; sys_platform == "linux"''', '''fork-basic-a<2; sys_platform == "darwin"''', @@ -54,7 +53,7 @@ fn fork_basic() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: true exit_code: 0 @@ -62,6 +61,7 @@ fn fork_basic() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. Resolved 3 packages in [TIME] "### ); @@ -78,18 +78,18 @@ fn fork_basic() -> Result<()> { [[distribution]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'darwin'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_basic_a-1.0.0.tar.gz#sha256=3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a", hash = "sha256:3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_basic_a-1.0.0-py3-none-any.whl#sha256=b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e", hash = "sha256:b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-1.0.0.tar.gz#sha256=3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a", hash = "sha256:3e45d6136e4a52416f85b7f53f405493db8f9fea33210299e6a68895bf0acf2a" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-1.0.0-py3-none-any.whl#sha256=b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e", hash = "sha256:b81a7553af25f15c9d49ed26af9c5b86eb2be107f3dd1bd97d7a4b0e8ca0329e" }] [[distribution]] name = "package-a" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'linux'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_basic_a-2.0.0.tar.gz#sha256=ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e", hash = "sha256:ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_basic_a-2.0.0-py3-none-any.whl#sha256=9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01", hash = "sha256:9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-2.0.0.tar.gz#sha256=ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e", hash = "sha256:ceb7349a6dd7640be952c70dce8ee6a44e3442dfd9b248b96242e37623e1028e" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_basic_a-2.0.0-py3-none-any.whl#sha256=9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01", hash = "sha256:9cab1de38d28e75ac5fe5c4dda9157555c60dd03ee26e6ad51b01ca18d8a0f01" }] [[distribution]] name = "project" @@ -100,12 +100,12 @@ fn fork_basic() -> Result<()> { [[distribution.dependencies]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-a" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" "### ); }); @@ -153,7 +153,6 @@ fn fork_marker_accrue() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-marker-accrue-a==1.0.0; implementation_name == "cpython"''', '''fork-marker-accrue-b==1.0.0; implementation_name == "pypy"''', @@ -163,7 +162,7 @@ fn fork_marker_accrue() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: true exit_code: 0 @@ -171,6 +170,7 @@ fn fork_marker_accrue() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. Resolved 4 packages in [TIME] "### ); @@ -187,36 +187,36 @@ fn fork_marker_accrue() -> Result<()> { [[distribution]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "implementation_name == 'cpython'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_a-1.0.0.tar.gz#sha256=9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37", hash = "sha256:9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_a-1.0.0-py3-none-any.whl#sha256=5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a", hash = "sha256:5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_a-1.0.0.tar.gz#sha256=9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37", hash = "sha256:9096dbf9c8e8c2da4a1527be515f740f697ee833ec1492953883f36c8931bc37" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_a-1.0.0-py3-none-any.whl#sha256=5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a", hash = "sha256:5fed1607b73cc7a5e9703206c24cc3fa730600a776bf40ae264ad364ad610e0a" }] [[distribution.dependencies]] name = "package-c" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "implementation_name == 'pypy'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_b-1.0.0.tar.gz#sha256=d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859", hash = "sha256:d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_b-1.0.0-py3-none-any.whl#sha256=e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f", hash = "sha256:e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_b-1.0.0.tar.gz#sha256=d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859", hash = "sha256:d92d0083d2d5da2f83180c08dfc79a03ec9606c00bc3153566f7b577c0e6b859" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_b-1.0.0-py3-none-any.whl#sha256=e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f", hash = "sha256:e5382e438f417f2de9427296a5960f9f9631ff1fa11c93d6b0b3b9d7fb60760f" }] [[distribution.dependencies]] name = "package-c" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-c" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'darwin' or sys_platform == 'linux'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_c-1.0.0.tar.gz#sha256=81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad", hash = "sha256:81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_accrue_c-1.0.0-py3-none-any.whl#sha256=f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6", hash = "sha256:f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_c-1.0.0.tar.gz#sha256=81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad", hash = "sha256:81068ae8b43deb3165cab17eb52aa5f99cda64f51c359b4659918d86995b9cad" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_accrue_c-1.0.0-py3-none-any.whl#sha256=f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6", hash = "sha256:f5fe6d35f360ea802b3a7da030e9ed1dce776c30ed028ea7be04fafcb7ac55b6" }] [[distribution]] name = "project" @@ -227,12 +227,12 @@ fn fork_marker_accrue() -> Result<()> { [[distribution.dependencies]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" "### ); }); @@ -240,6 +240,70 @@ fn fork_marker_accrue() -> Result<()> { Ok(()) } +/// A basic test that ensures, at least in this one basic case, that forking in +/// universal resolution happens only when the corresponding marker expressions are +/// completely disjoint. Here, we provide two completely incompatible dependency +/// specifications with equivalent markers. Thus, they are trivially not disjoint, +/// and resolution should fail. NOTE: This acts a regression test for the initial +/// version of universal resolution that would fork whenever a package was repeated +/// in the list of dependency specifications. So previously, this would produce a +/// resolution with both `1.0.0` and `2.0.0` of `a`. But of course, the correct +/// behavior is to fail resolving. +/// +/// ```text +/// fork-marker-disjoint +/// ├── environment +/// │ └── python3.8 +/// ├── root +/// │ ├── requires a>=2; sys_platform == "linux" +/// │ │ └── satisfied by a-2.0.0 +/// │ └── requires a<2; sys_platform == "linux" +/// │ └── satisfied by a-1.0.0 +/// └── a +/// ├── a-1.0.0 +/// └── a-2.0.0 +/// ``` +#[test] +fn fork_marker_disjoint() -> Result<()> { + let context = TestContext::new("3.8"); + + // In addition to the standard filters, swap out package names for shorter messages + let mut filters = context.filters(); + filters.push((r"fork-marker-disjoint-", "package-")); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r###" + [project] + name = "project" + version = "0.1.0" + dependencies = [ + '''fork-marker-disjoint-a>=2; sys_platform == "linux"''', + '''fork-marker-disjoint-a<2; sys_platform == "linux"''', + ] + "###, + )?; + + let mut cmd = context.lock_without_exclude_newer(); + cmd.arg("--index-url") + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); + uv_snapshot!(filters, cmd, @r###" + success: false + exit_code: 1 + ----- stdout ----- + + ----- stderr ----- + warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. + × No solution found when resolving dependencies: + ╰─▶ Because project==0.1.0 depends on package-a{sys_platform == 'linux'}>=2 and package-a{sys_platform == 'linux'}<2, we can conclude that project==0.1.0 cannot be used. + And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable. + "### + ); + + Ok(()) +} + /// This tests a case where the resolver forks because of non-overlapping marker /// expressions on `b`. In the original universal resolver implementation, this /// resulted in multiple versions of `a` being unconditionally included in the lock @@ -281,7 +345,6 @@ fn fork_marker_selection() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-marker-selection-a''', '''fork-marker-selection-b>=2; sys_platform == "linux"''', @@ -292,7 +355,7 @@ fn fork_marker_selection() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: true exit_code: 0 @@ -300,6 +363,7 @@ fn fork_marker_selection() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. Resolved 5 packages in [TIME] "### ); @@ -316,37 +380,37 @@ fn fork_marker_selection() -> Result<()> { [[distribution]] name = "package-a" version = "0.1.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_a-0.1.0.tar.gz#sha256=03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282", hash = "sha256:03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_a-0.1.0-py3-none-any.whl#sha256=0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473", hash = "sha256:0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.1.0.tar.gz#sha256=03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282", hash = "sha256:03c464276ee75f5a1468da2a4090ee6b5fda0f26f548707c9ffcf06d3cf69282" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.1.0-py3-none-any.whl#sha256=0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473", hash = "sha256:0e45ca7b3616810a583dc9754b52b91c69aeea4070d6fe0806c67081d0e95473" }] [[distribution]] name = "package-a" version = "0.2.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_a-0.2.0.tar.gz#sha256=ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f", hash = "sha256:ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_a-0.2.0-py3-none-any.whl#sha256=78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c", hash = "sha256:78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.2.0.tar.gz#sha256=ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f", hash = "sha256:ef1d840fe2e86c6eecd4673606076d858b51a3712c1de097b7503fee0c96b97f" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_a-0.2.0-py3-none-any.whl#sha256=78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c", hash = "sha256:78797f388900cece9866aa20917c6a40040dd65f906f8ef034a8cedb4dd75e6c" }] [[distribution.dependencies]] name = "package-b" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'darwin'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_b-1.0.0.tar.gz#sha256=97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1", hash = "sha256:97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_b-1.0.0-py3-none-any.whl#sha256=aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca", hash = "sha256:aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-1.0.0.tar.gz#sha256=97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1", hash = "sha256:97f1098f4c89457ab2b16982990d487ac6ae2c664f8e22e822a086df71999dc1" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-1.0.0-py3-none-any.whl#sha256=aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca", hash = "sha256:aba998c3dfa70f4118a4587f636c96f5a2785081b733120cf81b6d762f67b1ca" }] [[distribution]] name = "package-b" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'linux'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_b-2.0.0.tar.gz#sha256=1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a", hash = "sha256:1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_selection_b-2.0.0-py3-none-any.whl#sha256=ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf", hash = "sha256:ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-2.0.0.tar.gz#sha256=1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a", hash = "sha256:1f66e4ba827d2913827fa52cc9fd08491b16ab409fa31c40a2fe4e3cde91cb4a" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_selection_b-2.0.0-py3-none-any.whl#sha256=ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf", hash = "sha256:ad1b23547813b9ac69b33d3fcf1896cd49a90cd8f957e954dbdd77b628d631cf" }] [[distribution]] name = "project" @@ -357,22 +421,22 @@ fn fork_marker_selection() -> Result<()> { [[distribution.dependencies]] name = "package-a" version = "0.1.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-a" version = "0.2.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" "### ); }); @@ -432,7 +496,6 @@ fn fork_marker_track() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-marker-track-a''', '''fork-marker-track-b>=2.8; sys_platform == "linux"''', @@ -443,7 +506,7 @@ fn fork_marker_track() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: true exit_code: 0 @@ -451,6 +514,7 @@ fn fork_marker_track() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. Resolved 6 packages in [TIME] "### ); @@ -467,50 +531,50 @@ fn fork_marker_track() -> Result<()> { [[distribution]] name = "package-a" version = "1.3.1" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_a-1.3.1.tar.gz#sha256=b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37", hash = "sha256:b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_a-1.3.1-py3-none-any.whl#sha256=8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f", hash = "sha256:8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-1.3.1.tar.gz#sha256=b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37", hash = "sha256:b88e1c256f2f3b2f3d0cff5398fd6a1a17682f3b5fd736e08d44c313ed48ef37" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-1.3.1-py3-none-any.whl#sha256=8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f", hash = "sha256:8f2bd8bcd8f3fc2cfe64621d62a3a9404db665830f7a76db60307a80cf8e632f" }] [[distribution.dependencies]] name = "package-c" version = "1.10" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-a" version = "4.3.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_a-4.3.0.tar.gz#sha256=46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75", hash = "sha256:46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_a-4.3.0-py3-none-any.whl#sha256=73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5", hash = "sha256:73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-4.3.0.tar.gz#sha256=46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75", hash = "sha256:46a0ab5d6b934f2b8c762893660483036a81ac1f8df9a6555e72a3b4859e1a75" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_a-4.3.0-py3-none-any.whl#sha256=73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5", hash = "sha256:73ad4b017bae8cb4743be03bc406f65594c92ec5038b0f56a4acb07873bfcaa5" }] [[distribution.dependencies]] name = "package-b" version = "2.8" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-b" version = "2.7" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'darwin'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_b-2.7.tar.gz#sha256=25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd", hash = "sha256:25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_b-2.7-py3-none-any.whl#sha256=be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808", hash = "sha256:be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.7.tar.gz#sha256=25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd", hash = "sha256:25258fd52c9611c9e101138f9986ada5930f5bea08988d0356645c772a8162dd" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.7-py3-none-any.whl#sha256=be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808", hash = "sha256:be56f5850a343cb02dfc22e75eaa1009db675ac2f1275b78ba4089c6ea2f2808" }] [[distribution]] name = "package-b" version = "2.8" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'linux'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_b-2.8.tar.gz#sha256=7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628", hash = "sha256:7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_b-2.8-py3-none-any.whl#sha256=d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1", hash = "sha256:d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.8.tar.gz#sha256=7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628", hash = "sha256:7ec0f88f013fa0b75a4c88097799866617de4cae558b18ad0677f7cc65ad6628" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_b-2.8-py3-none-any.whl#sha256=d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1", hash = "sha256:d9969066117d846fe3a200df5bafc3b3279cc419f36f7275e6e55b2dbde2d5d1" }] [[distribution]] name = "package-c" version = "1.10" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "implementation_name == 'iron'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_c-1.10.tar.gz#sha256=6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930", hash = "sha256:6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_marker_track_c-1.10-py3-none-any.whl#sha256=19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff", hash = "sha256:19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_c-1.10.tar.gz#sha256=6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930", hash = "sha256:6f4a62bec34fbda0e605dc9acb40af318b1d789816d81cbd0bc7c60595de5930" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_marker_track_c-1.10-py3-none-any.whl#sha256=19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff", hash = "sha256:19791f8bd3bad9a76be5477e1753dc2a4e797d163bef90fdfd99462c271ed6ff" }] [[distribution]] name = "project" @@ -521,22 +585,22 @@ fn fork_marker_track() -> Result<()> { [[distribution.dependencies]] name = "package-a" version = "1.3.1" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-a" version = "4.3.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "2.7" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "2.8" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" "### ); }); @@ -583,7 +647,6 @@ fn fork_non_fork_marker_transitive() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-non-fork-marker-transitive-a==1.0.0''', '''fork-non-fork-marker-transitive-b==1.0.0''', @@ -593,7 +656,7 @@ fn fork_non_fork_marker_transitive() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: true exit_code: 0 @@ -601,6 +664,7 @@ fn fork_non_fork_marker_transitive() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. Resolved 4 packages in [TIME] "### ); @@ -617,34 +681,34 @@ fn fork_non_fork_marker_transitive() -> Result<()> { [[distribution]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_a-1.0.0.tar.gz#sha256=017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749", hash = "sha256:017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_a-1.0.0-py3-none-any.whl#sha256=d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c", hash = "sha256:d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_a-1.0.0.tar.gz#sha256=017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749", hash = "sha256:017f775164ac5e33682262bbd44922938737bb8d7258161abb65d8d22f7f0749" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_a-1.0.0-py3-none-any.whl#sha256=d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c", hash = "sha256:d0ffdf00cba31099cc02d1419f1d2a0c8add5efe7c916b5e12bc23c8f7fdfb4c" }] [[distribution.dependencies]] name = "package-c" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_b-1.0.0.tar.gz#sha256=f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a", hash = "sha256:f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_b-1.0.0-py3-none-any.whl#sha256=d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4", hash = "sha256:d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4" }] + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_b-1.0.0.tar.gz#sha256=f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a", hash = "sha256:f930b038c81f712230deda8d3b7d2a9a9758b71e86313722747e0ecd44d86e4a" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_b-1.0.0-py3-none-any.whl#sha256=d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4", hash = "sha256:d50cf9f9bcff0c90e969d6eba899bbbcb3c09666217c2c9a8011cdef089070a4" }] [[distribution.dependencies]] name = "package-c" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution]] name = "package-c" version = "2.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" marker = "sys_platform == 'darwin' or sys_platform == 'linux'" - sdist = { url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_c-2.0.0.tar.gz#sha256=c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34", hash = "sha256:c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34" } - wheels = [{ url = "https://astral-sh.github.io/packse/0.3.17/files/fork_non_fork_marker_transitive_c-2.0.0-py3-none-any.whl#sha256=661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74", hash = "sha256:661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74" }] + sdist = { url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_c-2.0.0.tar.gz#sha256=c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34", hash = "sha256:c989314fe5534401e9b2374e9b0461c9d44c237853d9122bc7d9aee006ee0c34" } + wheels = [{ url = "https://astral-sh.github.io/packse/0.3.18/files/fork_non_fork_marker_transitive_c-2.0.0-py3-none-any.whl#sha256=661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74", hash = "sha256:661def8c77b372df8146049485a75678ecee810518fb7cba024b609920bdef74" }] [[distribution]] name = "project" @@ -655,12 +719,12 @@ fn fork_non_fork_marker_transitive() -> Result<()> { [[distribution.dependencies]] name = "package-a" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" [[distribution.dependencies]] name = "package-b" version = "1.0.0" - source = "registry+https://astral-sh.github.io/packse/0.3.17/simple-html/" + source = "registry+https://astral-sh.github.io/packse/0.3.18/simple-html/" "### ); }); @@ -708,7 +772,6 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-non-local-fork-marker-direct-a==1.0.0; sys_platform == "linux"''', '''fork-non-local-fork-marker-direct-b==1.0.0; sys_platform == "darwin"''', @@ -718,7 +781,7 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: false exit_code: 1 @@ -726,9 +789,10 @@ fn fork_non_local_fork_marker_direct() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. × No solution found when resolving dependencies: ╰─▶ Because package-b{sys_platform == 'darwin'}==1.0.0 depends on package-c>=2.0.0 and package-a{sys_platform == 'linux'}==1.0.0 depends on package-c<2.0.0, we can conclude that package-a{sys_platform == 'linux'}==1.0.0 and package-b{sys_platform == 'darwin'}==1.0.0 are incompatible. - And because project==0.1.0 depends on package-b{sys_platform == 'darwin'}==1.0.0 and package-a{sys_platform == 'linux'}==1.0.0, we can conclude that project==0.1.0 cannot be used. + And because project==0.1.0 depends on package-a{sys_platform == 'linux'}==1.0.0 and package-b{sys_platform == 'darwin'}==1.0.0, we can conclude that project==0.1.0 cannot be used. And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable. "### ); @@ -782,7 +846,6 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { [project] name = "project" version = "0.1.0" - requires-python = ">=3.8" dependencies = [ '''fork-non-local-fork-marker-transitive-a==1.0.0''', '''fork-non-local-fork-marker-transitive-b==1.0.0''', @@ -792,7 +855,7 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { let mut cmd = context.lock_without_exclude_newer(); cmd.arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/"); + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/"); uv_snapshot!(filters, cmd, @r###" success: false exit_code: 1 @@ -800,13 +863,14 @@ fn fork_non_local_fork_marker_transitive() -> Result<()> { ----- stderr ----- warning: `uv lock` is experimental and may change without warning. + warning: No `requires-python` field found in `project`. Defaulting to `>=3.8`. × No solution found when resolving dependencies: ╰─▶ Because package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}>=2.0.0 and only package-c{sys_platform == 'darwin'}<=2.0.0 is available, we can conclude that package-b==1.0.0 depends on package-c{sys_platform == 'darwin'}==2.0.0. And because only the following versions of package-c{sys_platform == 'linux'} are available: package-c{sys_platform == 'linux'}==1.0.0 package-c{sys_platform == 'linux'}>=2.0.0 and package-a==1.0.0 depends on package-c{sys_platform == 'linux'}<2.0.0, we can conclude that package-a==1.0.0 and package-b==1.0.0 are incompatible. - And because project==0.1.0 depends on package-b==1.0.0 and package-a==1.0.0, we can conclude that project==0.1.0 cannot be used. + And because project==0.1.0 depends on package-a==1.0.0 and package-b==1.0.0, we can conclude that project==0.1.0 cannot be used. And because only project==0.1.0 is available and project depends on project, we can conclude that the requirements are unsatisfiable. "### ); diff --git a/crates/uv/tests/pip_compile_scenarios.rs b/crates/uv/tests/pip_compile_scenarios.rs index 298ba4b80f29..bf282d24c793 100644 --- a/crates/uv/tests/pip_compile_scenarios.rs +++ b/crates/uv/tests/pip_compile_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi", unix))] @@ -27,9 +27,9 @@ fn command(context: &TestContext, python_versions: &[&str]) -> Command { .arg("compile") .arg("requirements.in") .arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/") + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/") .arg("--find-links") - .arg("https://raw.githubusercontent.com/astral-sh/packse/0.3.17/vendor/links.html") + .arg("https://raw.githubusercontent.com/astral-sh/packse/0.3.18/vendor/links.html") .arg("--cache-dir") .arg(context.cache_dir.path()) .env("VIRTUAL_ENV", context.venv.as_os_str()) diff --git a/crates/uv/tests/pip_install_scenarios.rs b/crates/uv/tests/pip_install_scenarios.rs index 26410373c948..5785581a833b 100644 --- a/crates/uv/tests/pip_install_scenarios.rs +++ b/crates/uv/tests/pip_install_scenarios.rs @@ -1,7 +1,7 @@ //! DO NOT EDIT //! //! Generated with `./scripts/sync_scenarios.sh` -//! Scenarios from +//! Scenarios from //! #![cfg(all(feature = "python", feature = "pypi", unix))] @@ -46,9 +46,9 @@ fn command(context: &TestContext) -> Command { .arg("pip") .arg("install") .arg("--index-url") - .arg("https://astral-sh.github.io/packse/0.3.17/simple-html/") + .arg("https://astral-sh.github.io/packse/0.3.18/simple-html/") .arg("--find-links") - .arg("https://raw.githubusercontent.com/astral-sh/packse/0.3.17/vendor/links.html") + .arg("https://raw.githubusercontent.com/astral-sh/packse/0.3.18/vendor/links.html") .arg("--cache-dir") .arg(context.cache_dir.path()) .env("VIRTUAL_ENV", context.venv.as_os_str()) diff --git a/scripts/scenarios/requirements.in b/scripts/scenarios/requirements.in index 61579afc420f..b01be6d44300 100644 --- a/scripts/scenarios/requirements.in +++ b/scripts/scenarios/requirements.in @@ -1,2 +1,2 @@ chevron-blue -packse>=0.3.17 +packse>=0.3.18 diff --git a/scripts/scenarios/requirements.txt b/scripts/scenarios/requirements.txt index b8d11a776487..55551e176095 100644 --- a/scripts/scenarios/requirements.txt +++ b/scripts/scenarios/requirements.txt @@ -46,7 +46,7 @@ nh3==0.2.17 # via readme-renderer packaging==24.0 # via hatchling -packse==0.3.17 +packse==0.3.18 # via -r scripts/scenarios/requirements.in pathspec==0.12.1 # via hatchling