Skip to content

Commit d74c022

Browse files
committed
Don't hint at versions removed by excluded-newer
General small hint false positives that shows up as CI failure in our snapshots. Fixes #13867
1 parent 0109af1 commit d74c022

File tree

7 files changed

+92
-45
lines changed

7 files changed

+92
-45
lines changed

crates/uv-distribution-types/src/prioritized_distribution.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use uv_platform_tags::{AbiTag, IncompatibleTag, LanguageTag, PlatformTag, TagPri
1111
use uv_pypi_types::{HashDigest, Yanked};
1212

1313
use crate::{
14-
InstalledDist, KnownPlatform, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist,
14+
File, InstalledDist, KnownPlatform, RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist,
1515
ResolvedDistRef,
1616
};
1717

@@ -557,6 +557,20 @@ impl PrioritizedDist {
557557
self.0.best_wheel_index.map(|i| &self.0.wheels[i])
558558
}
559559

560+
/// Returns an iterator of all wheels and the source distribution, if any.
561+
pub fn files(&self) -> impl Iterator<Item = &File> {
562+
self.0
563+
.wheels
564+
.iter()
565+
.map(|(wheel, _)| wheel.file.as_ref())
566+
.chain(
567+
self.0
568+
.source
569+
.as_ref()
570+
.map(|(source_dist, _)| source_dist.file.as_ref()),
571+
)
572+
}
573+
560574
/// Returns an iterator over all Python tags for the distribution.
561575
pub fn python_tags(&self) -> impl Iterator<Item = LanguageTag> + '_ {
562576
self.0

crates/uv-resolver/src/resolver/mod.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ use crate::resolver::system::SystemDependency;
7676
pub(crate) use crate::resolver::urls::Urls;
7777
use crate::universal_marker::{ConflictMarker, UniversalMarker};
7878
use crate::yanks::AllowedYanks;
79-
use crate::{DependencyMode, Exclusions, FlatIndex, Options, ResolutionMode, VersionMap, marker};
79+
use crate::{
80+
DependencyMode, ExcludeNewer, Exclusions, FlatIndex, Options, ResolutionMode, VersionMap,
81+
marker,
82+
};
8083
pub(crate) use provider::MetadataUnavailable;
8184
use uv_torch::TorchStrategy;
8285

@@ -363,6 +366,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
363366
state.fork_indexes,
364367
state.env,
365368
self.current_environment.clone(),
369+
self.options.exclude_newer,
366370
&visited,
367371
));
368372
}
@@ -2514,6 +2518,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
25142518
fork_indexes: ForkIndexes,
25152519
env: ResolverEnvironment,
25162520
current_environment: MarkerEnvironment,
2521+
exclude_newer: Option<ExcludeNewer>,
25172522
visited: &FxHashSet<PackageName>,
25182523
) -> ResolveError {
25192524
err = NoSolutionError::collapse_local_version_segments(NoSolutionError::collapse_proxies(
@@ -2566,10 +2571,27 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
25662571
if let VersionsResponse::Found(ref version_maps) = *response {
25672572
// Track the available versions, across all indexes.
25682573
for version_map in version_maps {
2569-
available_versions
2574+
let package_versions = available_versions
25702575
.entry(name.clone())
2571-
.or_insert_with(BTreeSet::new)
2572-
.extend(version_map.versions().cloned());
2576+
.or_insert_with(BTreeSet::new);
2577+
2578+
for (version, dists) in version_map.iter(&Ranges::full()) {
2579+
// Don't show versions removed by excluded-newer in hints.
2580+
if let Some(exclude_newer) = exclude_newer {
2581+
let Some(prioritized_dist) = dists.prioritized_dist() else {
2582+
continue;
2583+
};
2584+
if prioritized_dist.files().all(|file| {
2585+
file.upload_time_utc_ms.is_none_or(|upload_time| {
2586+
upload_time >= exclude_newer.timestamp_millis()
2587+
})
2588+
}) {
2589+
continue;
2590+
}
2591+
}
2592+
2593+
package_versions.insert(version.clone());
2594+
}
25732595
}
25742596

25752597
// Track the indexes in which the package is available.

crates/uv/tests/it/cache_prune.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,19 +250,19 @@ fn prune_unzipped() -> Result<()> {
250250
requirements_txt.write_str(indoc! { r"
251251
iniconfig
252252
" })?;
253-
uv_snapshot!(&filters, context.pip_install().arg("-r").arg("requirements.txt").arg("--offline"), @r###"
253+
uv_snapshot!(&filters, context.pip_install().arg("-r").arg("requirements.txt").arg("--offline"), @r"
254254
success: false
255255
exit_code: 1
256256
----- stdout -----
257257
258258
----- stderr -----
259259
× No solution found when resolving dependencies:
260-
╰─▶ Because iniconfig<=2.0.0 needs to be downloaded from a registry and you require iniconfig, we can conclude that your requirements are unsatisfiable.
260+
╰─▶ Because all versions of iniconfig need to be downloaded from a registry and you require iniconfig, we can conclude that your requirements are unsatisfiable.
261261
262262
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`)
263263
264264
hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
265-
"###);
265+
");
266266

267267
Ok(())
268268
}

crates/uv/tests/it/edit.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7956,29 +7956,24 @@ fn add_shadowed_name() -> Result<()> {
79567956
"###);
79577957

79587958
// Constraint with several available versions, check for an indirect dependency loop.
7959-
uv_snapshot!(context.filters(), context.add().arg("dagster-webserver>=1.6.11,<1.7.0"), @r###"
7959+
uv_snapshot!(context.filters(), context.add().arg("dagster-webserver>=1.6.11,<1.7.0"), @r"
79607960
success: false
79617961
exit_code: 1
79627962
----- stdout -----
79637963
79647964
----- stderr -----
79657965
× No solution found when resolving dependencies:
79667966
╰─▶ Because only the following versions of dagster-webserver are available:
7967-
dagster-webserver<=1.6.13
7968-
dagster-webserver>1.7.0
7969-
and dagster-webserver==1.6.11 depends on your project, we can conclude that all of:
7970-
dagster-webserver>=1.6.11,<1.6.12
7971-
dagster-webserver>1.6.13,<1.7.0
7972-
depend on your project.
7973-
And because dagster-webserver==1.6.12 depends on your project, we can conclude that all of:
7974-
dagster-webserver>=1.6.11,<1.6.13
7975-
dagster-webserver>1.6.13,<1.7.0
7976-
depend on your project.
7977-
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.
7967+
dagster-webserver<=1.6.11
7968+
dagster-webserver==1.6.12
7969+
dagster-webserver==1.6.13
7970+
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.
7971+
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.
7972+
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.
79787973
79797974
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.
79807975
help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing.
7981-
"###);
7976+
");
79827977

79837978
Ok(())
79847979
}
@@ -8073,7 +8068,7 @@ fn add_warn_index_url() -> Result<()> {
80738068
----- stderr -----
80748069
warning: Indexes specified via `--extra-index-url` will not be persisted to the `pyproject.toml` file; use `--index` instead.
80758070
× No solution found when resolving dependencies:
8076-
╰─▶ 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.
8071+
╰─▶ 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.
80778072
80788073
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.
80798074
help: If you want to add the package regardless of the failed resolution, provide the `--frozen` flag to skip locking and syncing.

crates/uv/tests/it/lock.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3673,20 +3673,19 @@ fn lock_requires_python() -> Result<()> {
36733673
----- stderr -----
36743674
× No solution found when resolving dependencies for split (python_full_version >= '3.7' and python_full_version < '3.7.9'):
36753675
╰─▶ 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.
3676-
And because only pygls<=1.3.0 is available, we can conclude that all of:
3677-
pygls>=1.1.0,<1.3.0
3678-
pygls>1.3.0
3679-
cannot be used. (1)
3676+
And because only the following versions of pygls are available:
3677+
pygls<=1.1.0
3678+
pygls==1.1.1
3679+
pygls==1.1.2
3680+
pygls==1.2.0
3681+
pygls==1.2.1
3682+
pygls==1.3.0
3683+
we can conclude that pygls>=1.1.0,<1.3.0 cannot be used. (1)
36803684

36813685
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.
3682-
And because we know from (1) that all of:
3683-
pygls>=1.1.0,<1.3.0
3684-
pygls>1.3.0
3685-
cannot be used, we can conclude that pygls>=1.1.0 cannot be used.
3686+
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.
36863687
And because your project depends on pygls>=1.1.0, we can conclude that your project's requirements are unsatisfiable.
36873688

3688-
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`)
3689-
36903689
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).
36913690

36923691
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<()>
1173411733
"#,
1173511734
)?;
1173611735

11737-
uv_snapshot!(context.filters(), context.lock(), @r###"
11736+
uv_snapshot!(context.filters(), context.lock(), @r"
1173811737
success: false
1173911738
exit_code: 1
1174011739
----- stdout -----
1174111740

1174211741
----- stderr -----
1174311742
× No solution found when resolving dependencies:
11744-
╰─▶ 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.
11745-
"###);
11743+
╰─▶ 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.
11744+
");
1174611745

1174711746
Ok(())
1174811747
}

crates/uv/tests/it/pip_compile.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14048,16 +14048,16 @@ fn compile_enumerate_no_versions() -> Result<()> {
1404814048

1404914049
uv_snapshot!(context.filters(), context.pip_compile()
1405014050
.arg("requirements.in"),
14051-
@r###"
14051+
@r"
1405214052
success: false
1405314053
exit_code: 1
1405414054
----- stdout -----
1405514055

1405614056
----- stderr -----
1405714057
× No solution found when resolving dependencies:
14058-
╰─▶ 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.
14058+
╰─▶ 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.
1405914059
And because you require rooster-blue, we can conclude that your requirements are unsatisfiable.
14060-
"###);
14060+
");
1406114061

1406214062
Ok(())
1406314063
}
@@ -14818,20 +14818,37 @@ fn invalid_platform() -> Result<()> {
1481814818
.pip_compile()
1481914819
.arg("--python-platform")
1482014820
.arg("linux")
14821-
.arg("requirements.in"), @r###"
14821+
.arg("requirements.in"), @r"
1482214822
success: false
1482314823
exit_code: 1
1482414824
----- stdout -----
1482514825

1482614826
----- stderr -----
1482714827
× No solution found when resolving dependencies:
14828-
╰─▶ 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.
14829-
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.
14828+
╰─▶ Because only the following versions of open3d are available:
14829+
open3d==0.8.0.0
14830+
open3d==0.9.0.0
14831+
open3d==0.10.0.0
14832+
open3d==0.10.0.1
14833+
open3d==0.11.0
14834+
open3d==0.11.1
14835+
open3d==0.11.2
14836+
open3d==0.12.0
14837+
open3d==0.13.0
14838+
open3d==0.14.1
14839+
open3d==0.15.1
14840+
open3d==0.15.2
14841+
open3d==0.16.0
14842+
open3d==0.16.1
14843+
open3d==0.17.0
14844+
open3d==0.18.0
14845+
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.
14846+
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.
1483014847

1483114848
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`
1483214849

1483314850
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`
14834-
"###);
14851+
");
1483514852

1483614853
Ok(())
1483714854
}

crates/uv/tests/it/pip_install.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,7 @@ fn no_prerelease_hint_source_builds() -> Result<()> {
28492849
build-backend = "setuptools.build_meta"
28502850
"#})?;
28512851

2852-
uv_snapshot!(context.filters(), context.pip_install().arg("."), @r###"
2852+
uv_snapshot!(context.filters(), context.pip_install().arg("."), @r"
28532853
success: false
28542854
exit_code: 1
28552855
----- stdout -----
@@ -2859,8 +2859,8 @@ fn no_prerelease_hint_source_builds() -> Result<()> {
28592859
× Failed to build `project @ file://[TEMP_DIR]/`
28602860
├─▶ Failed to resolve requirements from `setup.py` build
28612861
├─▶ No solution found when resolving: `setuptools>=40.8.0`
2862-
╰─▶ Because only setuptools<40.8.0 is available and you require setuptools>=40.8.0, we can conclude that your requirements are unsatisfiable.
2863-
"###
2862+
╰─▶ Because only setuptools<=40.4.3 is available and you require setuptools>=40.8.0, we can conclude that your requirements are unsatisfiable.
2863+
"
28642864
);
28652865

28662866
Ok(())

0 commit comments

Comments
 (0)