diff --git a/crates/uv-resolver/src/error.rs b/crates/uv-resolver/src/error.rs index de9c15646a9a..be35a4fc9ef5 100644 --- a/crates/uv-resolver/src/error.rs +++ b/crates/uv-resolver/src/error.rs @@ -235,7 +235,7 @@ impl NoSolutionError { match derivation_tree { DerivationTree::External(External::NotRoot(_, _)) => Some(derivation_tree), DerivationTree::External(External::NoVersions(package, versions)) => { - if SentinelRange::from(&versions).is_sentinel() { + if SentinelRange::from(&versions).is_complement() { return None; } @@ -977,13 +977,30 @@ impl<'range> From<&'range Range> for SentinelRange<'range> { } impl SentinelRange<'_> { - /// Returns `true` if the range appears to be, e.g., `>1.0.0, <1.0.0+[max]`. + /// Returns `true` if the range appears to be, e.g., `>=1.0.0, <1.0.0+[max]`. pub fn is_sentinel(&self) -> bool { + self.0.iter().all(|(lower, upper)| { + let (Bound::Included(lower), Bound::Excluded(upper)) = (lower, upper) else { + return false; + }; + if !lower.local().is_empty() { + return false; + } + if upper.local() != LocalVersionSlice::Max { + return false; + } + *lower == upper.clone().without_local() + }) + } + + /// Returns `true` if the range appears to be, e.g., `>1.0.0, <1.0.0+[max]` (i.e., a sentinel + /// range with the non-local version removed). + pub fn is_complement(&self) -> bool { self.0.iter().all(|(lower, upper)| { let (Bound::Excluded(lower), Bound::Excluded(upper)) = (lower, upper) else { return false; }; - if lower.local() == LocalVersionSlice::Max { + if !lower.local().is_empty() { return false; } if upper.local() != LocalVersionSlice::Max { diff --git a/crates/uv-resolver/src/pubgrub/priority.rs b/crates/uv-resolver/src/pubgrub/priority.rs index 80b1acc38c5b..5fc5a97575b6 100644 --- a/crates/uv-resolver/src/pubgrub/priority.rs +++ b/crates/uv-resolver/src/pubgrub/priority.rs @@ -10,6 +10,7 @@ use uv_pep440::Version; use crate::fork_urls::ForkUrls; use crate::pubgrub::package::PubGrubPackage; use crate::pubgrub::PubGrubPackageInner; +use crate::SentinelRange; /// A prioritization map to guide the PubGrub resolution process. /// @@ -57,8 +58,9 @@ impl PubGrubPriorities { // Compute the priority. let priority = if urls.get(name).is_some() { PubGrubPriority::DirectUrl(Reverse(index)) - } else if version.as_singleton().is_some() { - // TODO(charlie): Take local version ranges into account (e.g., `[2.0, 2.0+[max])`). + } else if version.as_singleton().is_some() + || SentinelRange::from(version).is_sentinel() + { PubGrubPriority::Singleton(Reverse(index)) } else { // Keep the conflict-causing packages to avoid loops where we seesaw between @@ -81,8 +83,9 @@ impl PubGrubPriorities { // Compute the priority. let priority = if urls.get(name).is_some() { PubGrubPriority::DirectUrl(Reverse(next)) - } else if version.as_singleton().is_some() { - // TODO(charlie): Take local version ranges into account (e.g., `[2.0, 2.0+[max])`). + } else if version.as_singleton().is_some() + || SentinelRange::from(version).is_sentinel() + { PubGrubPriority::Singleton(Reverse(next)) } else { PubGrubPriority::Unspecified(Reverse(next)) @@ -140,10 +143,7 @@ impl PubGrubPriorities { }; match self.package_priority.entry(name.clone()) { std::collections::hash_map::Entry::Occupied(mut entry) => { - if matches!( - entry.get(), - PubGrubPriority::ConflictEarly(_) | PubGrubPriority::Singleton(_) - ) { + if matches!(entry.get(), PubGrubPriority::ConflictEarly(_)) { // Already in the right category return false; }; @@ -178,9 +178,7 @@ impl PubGrubPriorities { // The ConflictEarly` match avoids infinite loops. if matches!( entry.get(), - PubGrubPriority::ConflictLate(_) - | PubGrubPriority::ConflictEarly(_) - | PubGrubPriority::Singleton(_) + PubGrubPriority::ConflictLate(_) | PubGrubPriority::ConflictEarly(_) ) { // Already in the right category return false; diff --git a/crates/uv-resolver/src/version_map.rs b/crates/uv-resolver/src/version_map.rs index 36ece551f3aa..bf9a87983242 100644 --- a/crates/uv-resolver/src/version_map.rs +++ b/crates/uv-resolver/src/version_map.rs @@ -162,8 +162,6 @@ impl VersionMap { range: &Ranges, ) -> impl DoubleEndedIterator { // Performance optimization: If we only have a single version, return that version directly. - // - // TODO(charlie): Now that we use local version sentinels, does this ever trigger? if let Some(version) = range.as_singleton() { either::Either::Left(match self.inner { VersionMapInner::Eager(ref eager) => { diff --git a/crates/uv/tests/it/pip_install_scenarios.rs b/crates/uv/tests/it/pip_install_scenarios.rs index 4dce0c7337e2..efd65ae30cca 100644 --- a/crates/uv/tests/it/pip_install_scenarios.rs +++ b/crates/uv/tests/it/pip_install_scenarios.rs @@ -531,17 +531,17 @@ fn excluded_only_compatible_version() { ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because only the following versions of package-a are available: + ╰─▶ Because package-a==1.0.0 depends on package-b==1.0.0 and only the following versions of package-a are available: package-a==1.0.0 package-a==2.0.0 package-a==3.0.0 - and package-a==1.0.0 depends on package-b==1.0.0, we can conclude that package-a<2.0.0 depends on package-b==1.0.0. + we can conclude that package-a<2.0.0 depends on package-b==1.0.0. And because package-a==3.0.0 depends on package-b==3.0.0, we can conclude that all of: package-a<2.0.0 package-a>2.0.0 depend on one of: - package-b==1.0.0 - package-b==3.0.0 + package-b<=1.0.0 + package-b>=3.0.0 And because you require one of: package-a<2.0.0 diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap index c0b0a9ba8d5b..2ed54f7ce7e7 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap @@ -3001,20 +3001,18 @@ wheels = [ [[package]] name = "protobuf" -version = "3.20.3" +version = "4.25.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/5b/e3d951e34f8356e5feecacd12a8e3b258a1da6d9a03ad1770f28925f29bc/protobuf-3.20.3.tar.gz", hash = "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2", size = 216768 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/ab/cb61a4b87b2e7e6c312dce33602bd5884797fd054e0e53205f1c27cf0f66/protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d", size = 380283 } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/55/b80e8567ec327c060fa39b242392e25690c8899c489ecd7bb65b46b7bb55/protobuf-3.20.3-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99", size = 918427 }, - { url = "https://files.pythonhosted.org/packages/31/be/80a9c6f16dfa4d41be3edbe655349778ae30882407fa8275eb46b4d34854/protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e", size = 1051042 }, - { url = "https://files.pythonhosted.org/packages/db/96/948d3fcc1fa816e7ae1d27af59b9d8c5c5e582f3994fd14394f31da95b99/protobuf-3.20.3-cp310-cp310-win32.whl", hash = "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c", size = 780167 }, - { url = "https://files.pythonhosted.org/packages/6f/5e/fc6feb366b0a9f28e0a2de3b062667c521cd9517d4ff55077b8f351ba2f3/protobuf-3.20.3-cp310-cp310-win_amd64.whl", hash = "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7", size = 904029 }, - { url = "https://files.pythonhosted.org/packages/00/e7/d23c439c55c90ae2e52184363162f7079ca3e7d86205b411d4e9dc266f81/protobuf-3.20.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b", size = 982826 }, - { url = "https://files.pythonhosted.org/packages/99/25/5825472ecd911f4ac2ac4e9ab039a48b6d03874e2add92fb633e080bf3eb/protobuf-3.20.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b", size = 918423 }, - { url = "https://files.pythonhosted.org/packages/c7/df/ec3ecb8c940b36121c7b77c10acebf3d1c736498aa2f1fe3b6231ee44e76/protobuf-3.20.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402", size = 1019250 }, - { url = "https://files.pythonhosted.org/packages/36/8b/433071fed0058322090a55021bdc8da76d16c7bc9823f5795797803dd6d0/protobuf-3.20.3-cp39-cp39-win32.whl", hash = "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480", size = 780270 }, - { url = "https://files.pythonhosted.org/packages/11/a5/e52b731415ad6ef3d841e9e6e337a690249e800cc7c06f0749afab26348c/protobuf-3.20.3-cp39-cp39-win_amd64.whl", hash = "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7", size = 904215 }, - { url = "https://files.pythonhosted.org/packages/8d/14/619e24a4c70df2901e1f4dbc50a6291eb63a759172558df326347dce1f0d/protobuf-3.20.3-py2.py3-none-any.whl", hash = "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db", size = 162128 }, + { url = "https://files.pythonhosted.org/packages/c8/43/27b48d9040763b78177d3083e16c70dba6e3c3ee2af64b659f6332c2b06e/protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4", size = 392409 }, + { url = "https://files.pythonhosted.org/packages/0c/d4/589d673ada9c4c62d5f155218d7ff7ac796efb9c6af95b0bd29d438ae16e/protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d", size = 413398 }, + { url = "https://files.pythonhosted.org/packages/34/ca/bf85ffe3dd16f1f2aaa6c006da8118800209af3da160ae4d4f47500eabd9/protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b", size = 394160 }, + { url = "https://files.pythonhosted.org/packages/68/1d/e8961af9a8e534d66672318d6b70ea8e3391a6b13e16a29b039e4a99c214/protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835", size = 293700 }, + { url = "https://files.pythonhosted.org/packages/ca/6c/cc7ab2fb3a4a7f07f211d8a7bbb76bba633eb09b148296dbd4281e217f95/protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040", size = 294612 }, + { url = "https://files.pythonhosted.org/packages/a4/b5/f7e2460dec8347d67e6108bef6ad3291c76e38c898a1087e2c836c02951e/protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca", size = 392490 }, + { url = "https://files.pythonhosted.org/packages/c7/0b/15bd1a224e5e5744a0dcccf11bcd5dc1405877be38e477b1359d7c2c3737/protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f", size = 413357 }, + { url = "https://files.pythonhosted.org/packages/b5/95/0ba7f66934a0a798006f06fc3d74816da2b7a2bcfd9b98c53d26f684c89e/protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978", size = 156464 }, ] [[package]] @@ -4700,18 +4698,17 @@ wheels = [ [[package]] name = "tf2onnx" -version = "1.16.1" +version = "1.8.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flatbuffers" }, { name = "numpy" }, { name = "onnx" }, - { name = "protobuf" }, { name = "requests" }, { name = "six" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/48/826db3d02645d84e7ee5d5ce8407f771057d40fe224d9c3e89536674ccef/tf2onnx-1.16.1-py3-none-any.whl", hash = "sha256:90fb5f62575896d47884d27dc313cfebff36b8783e1094335ad00824ce923a8a", size = 455820 }, + { url = "https://files.pythonhosted.org/packages/db/32/33ce509a79c207a39cf04bfa3ec3353da15d1e6553a6ad912f117cc29130/tf2onnx-1.8.4-py3-none-any.whl", hash = "sha256:1ebabb96c914da76e23222b6107a8b248a024bf259d77f027e6690099512d457", size = 345298 }, ] [[package]]