diff --git a/crates/uv-distribution-types/src/prioritized_distribution.rs b/crates/uv-distribution-types/src/prioritized_distribution.rs index b19061095..e3da41a67 100644 --- a/crates/uv-distribution-types/src/prioritized_distribution.rs +++ b/crates/uv-distribution-types/src/prioritized_distribution.rs @@ -11,7 +11,7 @@ use uv_platform_tags::{AbiTag, IncompatibleTag, LanguageTag, PlatformTag, TagPri use uv_pypi_types::{HashDigest, Yanked}; use crate::{ - InstalledDist, KnownPlatform, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, + File, InstalledDist, KnownPlatform, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, ResolvedDistRef, }; @@ -557,6 +557,20 @@ impl PrioritizedDist { self.0.best_wheel_index.map(|i| &self.0.wheels[i]) } + /// Returns an iterator of all wheels and the source distribution, if any. + pub fn files(&self) -> impl Iterator { + self.0 + .wheels + .iter() + .map(|(wheel, _)| wheel.file.as_ref()) + .chain( + self.0 + .source + .as_ref() + .map(|(source_dist, _)| source_dist.file.as_ref()), + ) + } + /// Returns an iterator over all Python tags for the distribution. pub fn python_tags(&self) -> impl Iterator + '_ { self.0 diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 43fcca24f..1384ce4f7 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -76,7 +76,10 @@ use crate::resolver::system::SystemDependency; pub(crate) use crate::resolver::urls::Urls; use crate::universal_marker::{ConflictMarker, UniversalMarker}; use crate::yanks::AllowedYanks; -use crate::{DependencyMode, Exclusions, FlatIndex, Options, ResolutionMode, VersionMap, marker}; +use crate::{ + DependencyMode, ExcludeNewer, Exclusions, FlatIndex, Options, ResolutionMode, VersionMap, + marker, +}; pub(crate) use provider::MetadataUnavailable; use uv_torch::TorchStrategy; @@ -363,6 +366,7 @@ impl ResolverState ResolverState, visited: &FxHashSet, ) -> ResolveError { err = NoSolutionError::collapse_local_version_segments(NoSolutionError::collapse_proxies( @@ -2566,10 +2571,27 @@ impl ResolverState= exclude_newer.timestamp_millis() + }) + }) { + continue; + } + } + + package_versions.insert(version.clone()); + } } // Track the indexes in which the package is available. diff --git a/crates/uv/tests/it/cache_prune.rs b/crates/uv/tests/it/cache_prune.rs index d760786d7..a6ec48bd4 100644 --- a/crates/uv/tests/it/cache_prune.rs +++ b/crates/uv/tests/it/cache_prune.rs @@ -250,19 +250,19 @@ fn prune_unzipped() -> Result<()> { requirements_txt.write_str(indoc! { r" iniconfig " })?; - uv_snapshot!(&filters, context.pip_install().arg("-r").arg("requirements.txt").arg("--offline"), @r###" + uv_snapshot!(&filters, context.pip_install().arg("-r").arg("requirements.txt").arg("--offline"), @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because iniconfig<=2.0.0 needs to be downloaded from a registry and you require iniconfig, we can conclude that your requirements are unsatisfiable. + ╰─▶ Because all versions of iniconfig need to be downloaded from a registry and you require iniconfig, we can conclude that your requirements are unsatisfiable. hint: Pre-releases are available for `iniconfig` in the requested range (e.g., 0.2.dev0), but pre-releases weren't enabled (try: `--prerelease=allow`) hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache. - "###); + "); Ok(()) } diff --git a/crates/uv/tests/it/edit.rs b/crates/uv/tests/it/edit.rs index e620eb850..db47b27ef 100644 --- a/crates/uv/tests/it/edit.rs +++ b/crates/uv/tests/it/edit.rs @@ -7956,7 +7956,7 @@ fn add_shadowed_name() -> Result<()> { "###); // Constraint with several available versions, check for an indirect dependency loop. - uv_snapshot!(context.filters(), context.add().arg("dagster-webserver>=1.6.11,<1.7.0"), @r###" + uv_snapshot!(context.filters(), context.add().arg("dagster-webserver>=1.6.11,<1.7.0"), @r" success: false exit_code: 1 ----- stdout ----- @@ -7964,21 +7964,16 @@ fn add_shadowed_name() -> Result<()> { ----- stderr ----- × No solution found when resolving dependencies: ╰─▶ Because only the following versions of dagster-webserver are available: - dagster-webserver<=1.6.13 - dagster-webserver>1.7.0 - and dagster-webserver==1.6.11 depends on your project, we can conclude that all of: - dagster-webserver>=1.6.11,<1.6.12 - dagster-webserver>1.6.13,<1.7.0 - depend on your project. - And because dagster-webserver==1.6.12 depends on your project, we can conclude that all of: - dagster-webserver>=1.6.11,<1.6.13 - dagster-webserver>1.6.13,<1.7.0 - depend on your project. - And because dagster-webserver==1.6.13 depends on your project and your project depends on dagster-webserver>=1.6.11,<1.7.0, we can conclude that your project's requirements are unsatisfiable. + dagster-webserver<=1.6.11 + dagster-webserver==1.6.12 + dagster-webserver==1.6.13 + and dagster-webserver==1.6.11 depends on your project, we can conclude that dagster-webserver>=1.6.11,<1.6.12 depends on your project. + And because dagster-webserver==1.6.12 depends on your project, we can conclude that dagster-webserver>=1.6.11,<1.6.13 depends on your project. + And because dagster-webserver==1.6.13 depends on your project and your project depends on dagster-webserver>=1.6.11, we can conclude that your project's requirements are unsatisfiable. hint: The package `dagster-webserver` depends on the package `dagster` but the name is shadowed by your project. Consider changing the name of the project. help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing. - "###); + "); Ok(()) } @@ -8073,7 +8068,7 @@ fn add_warn_index_url() -> Result<()> { ----- stderr ----- warning: Indexes specified via `--extra-index-url` will not be persisted to the `pyproject.toml` file; use `--index` instead. × No solution found when resolving dependencies: - ╰─▶ Because only idna<3.6 is available and your project depends on idna>=3.6, we can conclude that your project's requirements are unsatisfiable. + ╰─▶ Because only idna==2.7 is available and your project depends on idna>=3.6, we can conclude that your project's requirements are unsatisfiable. hint: `idna` was found on https://test.pypi.org/simple, but not at the requested version (idna>=3.6). A compatible version may be available on a subsequent index (e.g., https://pypi.org/simple). By default, uv will only consider versions that are published on the first index that contains a given package, to avoid dependency confusion attacks. If all indexes are equally trusted, use `--index-strategy unsafe-best-match` to consider all versions from all indexes, regardless of the order in which they were defined. help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing. diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index a1fa1721e..4387d348a 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -3673,20 +3673,19 @@ fn lock_requires_python() -> Result<()> { ----- stderr ----- × No solution found when resolving dependencies for split (python_full_version >= '3.7' and python_full_version < '3.7.9'): ╰─▶ Because the requested Python version (>=3.7) does not satisfy Python>=3.7.9 and pygls>=1.1.0,<=1.2.1 depends on Python>=3.7.9,<4, we can conclude that pygls>=1.1.0,<=1.2.1 cannot be used. - And because only pygls<=1.3.0 is available, we can conclude that all of: - pygls>=1.1.0,<1.3.0 - pygls>1.3.0 - cannot be used. (1) + And because only the following versions of pygls are available: + pygls<=1.1.0 + pygls==1.1.1 + pygls==1.1.2 + pygls==1.2.0 + pygls==1.2.1 + pygls==1.3.0 + we can conclude that pygls>=1.1.0,<1.3.0 cannot be used. (1) Because the requested Python version (>=3.7) does not satisfy Python>=3.8 and pygls==1.3.0 depends on Python>=3.8, we can conclude that pygls==1.3.0 cannot be used. - And because we know from (1) that all of: - pygls>=1.1.0,<1.3.0 - pygls>1.3.0 - cannot be used, we can conclude that pygls>=1.1.0 cannot be used. + And because we know from (1) that pygls>=1.1.0,<1.3.0 cannot be used, we can conclude that pygls>=1.1.0 cannot be used. And because your project depends on pygls>=1.1.0, we can conclude that your project's requirements are unsatisfiable. - hint: Pre-releases are available for `pygls` in the requested range (e.g., 2.0.0a4), but pre-releases weren't enabled (try: `--prerelease=allow`) - hint: The `requires-python` value (>=3.7) includes Python versions that are not supported by your dependencies (e.g., pygls>=1.1.0,<=1.2.1 only supports >=3.7.9, <4). Consider using a more restrictive `requires-python` value (like >=3.7.9, <4). hint: While the active Python version is 3.12, the resolution failed for other Python versions supported by your project. Consider limiting your project's supported Python versions using `requires-python`. @@ -11734,15 +11733,15 @@ fn unconditional_overlapping_marker_disjoint_version_constraints() -> Result<()> "#, )?; - uv_snapshot!(context.filters(), context.lock(), @r###" + uv_snapshot!(context.filters(), context.lock(), @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because only datasets<2.19 is available and your project depends on datasets>=2.19, we can conclude that your project's requirements are unsatisfiable. - "###); + ╰─▶ Because only datasets<=2.18.0 is available and your project depends on datasets>=2.19, we can conclude that your project's requirements are unsatisfiable. + "); Ok(()) } @@ -27422,11 +27421,41 @@ fn lock_conflict_for_disjoint_python_version() -> Result<()> { ----- stderr ----- × No solution found when resolving dependencies for split (python_full_version >= '3.11'): - ╰─▶ Because only numpy{python_full_version >= '3.10'}<=1.26.4 is available and pandas==1.5.3 depends on numpy{python_full_version >= '3.10'}>=1.21.0, we can conclude that pandas==1.5.3 depends on numpy>=1.21.0,<=1.26.4. + ╰─▶ Because only the following versions of numpy{python_full_version >= '3.10'} are available: + numpy{python_full_version >= '3.10'}<=1.21.0 + numpy{python_full_version >= '3.10'}==1.21.1 + numpy{python_full_version >= '3.10'}==1.21.2 + numpy{python_full_version >= '3.10'}==1.21.3 + numpy{python_full_version >= '3.10'}==1.21.4 + numpy{python_full_version >= '3.10'}==1.21.5 + numpy{python_full_version >= '3.10'}==1.21.6 + numpy{python_full_version >= '3.10'}==1.22.0 + numpy{python_full_version >= '3.10'}==1.22.1 + numpy{python_full_version >= '3.10'}==1.22.2 + numpy{python_full_version >= '3.10'}==1.22.3 + numpy{python_full_version >= '3.10'}==1.22.4 + numpy{python_full_version >= '3.10'}==1.23.0 + numpy{python_full_version >= '3.10'}==1.23.1 + numpy{python_full_version >= '3.10'}==1.23.2 + numpy{python_full_version >= '3.10'}==1.23.3 + numpy{python_full_version >= '3.10'}==1.23.4 + numpy{python_full_version >= '3.10'}==1.23.5 + numpy{python_full_version >= '3.10'}==1.24.0 + numpy{python_full_version >= '3.10'}==1.24.1 + numpy{python_full_version >= '3.10'}==1.24.2 + numpy{python_full_version >= '3.10'}==1.24.3 + numpy{python_full_version >= '3.10'}==1.24.4 + numpy{python_full_version >= '3.10'}==1.25.0 + numpy{python_full_version >= '3.10'}==1.25.1 + numpy{python_full_version >= '3.10'}==1.25.2 + numpy{python_full_version >= '3.10'}==1.26.0 + numpy{python_full_version >= '3.10'}==1.26.1 + numpy{python_full_version >= '3.10'}==1.26.2 + numpy{python_full_version >= '3.10'}==1.26.3 + numpy{python_full_version >= '3.10'}==1.26.4 + and pandas==1.5.3 depends on numpy{python_full_version >= '3.10'}>=1.21.0, we can conclude that pandas==1.5.3 depends on numpy>=1.21.0. And because your project depends on numpy==1.20.3 and pandas==1.5.3, we can conclude that your project's requirements are unsatisfiable. - hint: Pre-releases are available for `numpy` in the requested range (e.g., 2.3.0rc1), but pre-releases weren't enabled (try: `--prerelease=allow`) - hint: While the active Python version is 3.9, the resolution failed for other Python versions supported by your project. Consider limiting your project's supported Python versions using `requires-python`. "); diff --git a/crates/uv/tests/it/pip_compile.rs b/crates/uv/tests/it/pip_compile.rs index 17f336dc6..efb51e47d 100644 --- a/crates/uv/tests/it/pip_compile.rs +++ b/crates/uv/tests/it/pip_compile.rs @@ -14048,16 +14048,16 @@ fn compile_enumerate_no_versions() -> Result<()> { uv_snapshot!(context.filters(), context.pip_compile() .arg("requirements.in"), - @r###" + @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because the current Python version (3.10.[X]) does not satisfy Python>=3.11,<4.0 and rooster-blue<=0.0.8 depends on Python>=3.11,<4.0, we can conclude that rooster-blue<=0.0.8 cannot be used. + ╰─▶ Because the current Python version (3.10.[X]) does not satisfy Python>=3.11,<4.0 and all versions of rooster-blue depend on Python>=3.11,<4.0, we can conclude that all versions of rooster-blue cannot be used. And because you require rooster-blue, we can conclude that your requirements are unsatisfiable. - "###); + "); Ok(()) } @@ -14818,20 +14818,37 @@ fn invalid_platform() -> Result<()> { .pip_compile() .arg("--python-platform") .arg("linux") - .arg("requirements.in"), @r###" + .arg("requirements.in"), @r" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- × No solution found when resolving dependencies: - ╰─▶ Because only open3d<=0.18.0 is available and open3d<=0.15.2 has no wheels with a matching Python ABI tag (e.g., `cp310`), we can conclude that open3d<=0.15.2 cannot be used. - And because open3d>=0.16.0,<=0.18.0 has no wheels with a matching platform tag (e.g., `manylinux_2_17_x86_64`) and you require open3d, we can conclude that your requirements are unsatisfiable. + ╰─▶ Because only the following versions of open3d are available: + open3d==0.8.0.0 + open3d==0.9.0.0 + open3d==0.10.0.0 + open3d==0.10.0.1 + open3d==0.11.0 + open3d==0.11.1 + open3d==0.11.2 + open3d==0.12.0 + open3d==0.13.0 + open3d==0.14.1 + open3d==0.15.1 + open3d==0.15.2 + open3d==0.16.0 + open3d==0.16.1 + open3d==0.17.0 + open3d==0.18.0 + and open3d<=0.15.2 has no wheels with a matching Python ABI tag (e.g., `cp310`), we can conclude that open3d<=0.15.2 cannot be used. + And because open3d>=0.16.0 has no wheels with a matching platform tag (e.g., `manylinux_2_17_x86_64`) and you require open3d, we can conclude that your requirements are unsatisfiable. hint: You require CPython 3.10 (`cp310`), but we only found wheels for `open3d` (v0.15.2) with the following Python ABI tags: `cp36m`, `cp37m`, `cp38`, `cp39` hint: Wheels are available for `open3d` (v0.18.0) on the following platforms: `manylinux_2_27_aarch64`, `manylinux_2_27_x86_64`, `macosx_11_0_x86_64`, `macosx_13_0_arm64`, `win_amd64` - "###); + "); Ok(()) } diff --git a/crates/uv/tests/it/pip_install.rs b/crates/uv/tests/it/pip_install.rs index d1f41d882..872db659f 100644 --- a/crates/uv/tests/it/pip_install.rs +++ b/crates/uv/tests/it/pip_install.rs @@ -2849,7 +2849,7 @@ fn no_prerelease_hint_source_builds() -> Result<()> { build-backend = "setuptools.build_meta" "#})?; - uv_snapshot!(context.filters(), context.pip_install().arg("."), @r###" + uv_snapshot!(context.filters(), context.pip_install().arg("."), @r" success: false exit_code: 1 ----- stdout ----- @@ -2859,8 +2859,8 @@ fn no_prerelease_hint_source_builds() -> Result<()> { × Failed to build `project @ file://[TEMP_DIR]/` ├─▶ Failed to resolve requirements from `setup.py` build ├─▶ No solution found when resolving: `setuptools>=40.8.0` - ╰─▶ Because only setuptools<40.8.0 is available and you require setuptools>=40.8.0, we can conclude that your requirements are unsatisfiable. - "### + ╰─▶ Because only setuptools<=40.4.3 is available and you require setuptools>=40.8.0, we can conclude that your requirements are unsatisfiable. + " ); Ok(())