Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion crates/uv-distribution-types/src/prioritized_distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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<Item = &File> {
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<Item = LanguageTag> + '_ {
self.0
Expand Down
30 changes: 26 additions & 4 deletions crates/uv-resolver/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -363,6 +366,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
state.fork_indexes,
state.env,
self.current_environment.clone(),
self.options.exclude_newer,
&visited,
));
}
Expand Down Expand Up @@ -2514,6 +2518,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
fork_indexes: ForkIndexes,
env: ResolverEnvironment,
current_environment: MarkerEnvironment,
exclude_newer: Option<ExcludeNewer>,
visited: &FxHashSet<PackageName>,
) -> ResolveError {
err = NoSolutionError::collapse_local_version_segments(NoSolutionError::collapse_proxies(
Expand Down Expand Up @@ -2566,10 +2571,27 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
if let VersionsResponse::Found(ref version_maps) = *response {
// Track the available versions, across all indexes.
for version_map in version_maps {
available_versions
let package_versions = available_versions
.entry(name.clone())
.or_insert_with(BTreeSet::new)
.extend(version_map.versions().cloned());
.or_insert_with(BTreeSet::new);

for (version, dists) in version_map.iter(&Ranges::full()) {
// Don't show versions removed by excluded-newer in hints.
if let Some(exclude_newer) = exclude_newer {
let Some(prioritized_dist) = dists.prioritized_dist() else {
continue;
};
if prioritized_dist.files().all(|file| {
file.upload_time_utc_ms.is_none_or(|upload_time| {
upload_time >= exclude_newer.timestamp_millis()
})
}) {
continue;
}
}

package_versions.insert(version.clone());
}
}

// Track the indexes in which the package is available.
Expand Down
6 changes: 3 additions & 3 deletions crates/uv/tests/it/cache_prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down
23 changes: 9 additions & 14 deletions crates/uv/tests/it/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7956,29 +7956,24 @@ 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 -----

----- 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(())
}
Expand Down Expand Up @@ -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.
Expand Down
61 changes: 45 additions & 16 deletions crates/uv/tests/it/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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`.
");

Expand Down
31 changes: 24 additions & 7 deletions crates/uv/tests/it/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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(())
}
Expand Down
6 changes: 3 additions & 3 deletions crates/uv/tests/it/pip_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 -----
Expand All @@ -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(())
Expand Down
Loading