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
8 changes: 2 additions & 6 deletions crates/uv-distribution-types/src/prioritized_distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ impl Display for IncompatibleDist {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Wheel(incompatibility) => match incompatibility {
IncompatibleWheel::NoBinary => {
f.write_str("no source distribution and using wheels is disabled")
}
IncompatibleWheel::NoBinary => f.write_str("no source distribution"),
IncompatibleWheel::Tag(tag) => match tag {
IncompatibleTag::Invalid => f.write_str("no wheels with valid tags"),
IncompatibleTag::Python => {
Expand Down Expand Up @@ -175,9 +173,7 @@ impl Display for IncompatibleDist {
}
},
Self::Source(incompatibility) => match incompatibility {
IncompatibleSource::NoBuild => {
f.write_str("no usable wheels and building from source is disabled")
}
IncompatibleSource::NoBuild => f.write_str("no usable wheels"),
IncompatibleSource::Yanked(yanked) => match yanked {
Yanked::Bool(_) => f.write_str("yanked"),
Yanked::Reason(reason) => write!(
Expand Down
94 changes: 89 additions & 5 deletions crates/uv-resolver/src/pubgrub/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use pubgrub::{DerivationTree, Derived, External, Map, Range, ReportFormatter, Te
use rustc_hash::FxHashMap;

use uv_configuration::IndexStrategy;
use uv_distribution_types::{Index, IndexCapabilities, IndexLocations, IndexUrl};
use uv_distribution_types::{
IncompatibleDist, IncompatibleSource, IncompatibleWheel, Index, IndexCapabilities,
IndexLocations, IndexUrl,
};
use uv_normalize::PackageName;
use uv_pep440::{Version, VersionSpecifiers};

Expand All @@ -18,7 +21,9 @@ use crate::error::ErrorTree;
use crate::fork_urls::ForkUrls;
use crate::prerelease::AllowPrerelease;
use crate::python_requirement::{PythonRequirement, PythonRequirementSource};
use crate::resolver::{MetadataUnavailable, UnavailablePackage, UnavailableReason};
use crate::resolver::{
MetadataUnavailable, UnavailablePackage, UnavailableReason, UnavailableVersion,
};
use crate::{Flexibility, Options, RequiresPython, ResolverEnvironment};

use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
Expand Down Expand Up @@ -556,9 +561,58 @@ impl PubGrubReportFormatter<'_> {
output_hints: &mut IndexSet<PubGrubHint>,
) {
match derivation_tree {
DerivationTree::External(
External::Custom(package, set, _) | External::NoVersions(package, set),
) => {
DerivationTree::External(External::Custom(package, set, reason)) => {
if let PubGrubPackageInner::Package { name, .. } = &**package {
// Check for no versions due to pre-release options.
if options.flexibility == Flexibility::Configurable {
if !fork_urls.contains_key(name) {
self.prerelease_available_hint(
package,
name,
set,
selector,
env,
output_hints,
);
}
}

// Check for no versions due to no `--find-links` flat index.
Self::index_hints(
package,
name,
set,
selector,
index_locations,
index_capabilities,
available_indexes,
unavailable_packages,
incomplete_packages,
output_hints,
);
}

// Check for unavailable versions due to `--no-build` or `--no-binary`.
if let UnavailableReason::Version(UnavailableVersion::IncompatibleDist(
incompatibility,
)) = reason
{
match incompatibility {
IncompatibleDist::Wheel(IncompatibleWheel::NoBinary) => {
output_hints.insert(PubGrubHint::NoBinary {
package: package.clone(),
});
}
IncompatibleDist::Source(IncompatibleSource::NoBuild) => {
output_hints.insert(PubGrubHint::NoBuild {
package: package.clone(),
});
}
_ => {}
}
}
}
DerivationTree::External(External::NoVersions(package, set)) => {
if let PubGrubPackageInner::Package { name, .. } = &**package {
// Check for no versions due to pre-release options.
if options.flexibility == Flexibility::Configurable {
Expand Down Expand Up @@ -954,6 +1008,10 @@ pub(crate) enum PubGrubHint {
// excluded from `PartialEq` and `Hash`
next_index: IndexUrl,
},
/// No wheels are available for a package, and using source distributions was disabled.
NoBuild { package: PubGrubPackage },
/// No source distributions are available for a package, and using pre-built wheels was disabled.
NoBinary { package: PubGrubPackage },
/// An index returned an Unauthorized (401) response.
UnauthorizedIndex { index: IndexUrl },
/// An index returned a Forbidden (403) response.
Expand Down Expand Up @@ -1013,6 +1071,12 @@ enum PubGrubHintCore {
ForbiddenIndex {
index: IndexUrl,
},
NoBuild {
package: PubGrubPackage,
},
NoBinary {
package: PubGrubPackage,
},
}

impl From<PubGrubHint> for PubGrubHintCore {
Expand Down Expand Up @@ -1068,6 +1132,8 @@ impl From<PubGrubHint> for PubGrubHintCore {
PubGrubHint::UncheckedIndex { package, .. } => Self::UncheckedIndex { package },
PubGrubHint::UnauthorizedIndex { index } => Self::UnauthorizedIndex { index },
PubGrubHint::ForbiddenIndex { index } => Self::ForbiddenIndex { index },
PubGrubHint::NoBuild { package } => Self::NoBuild { package },
PubGrubHint::NoBinary { package } => Self::NoBinary { package },
}
}
}
Expand Down Expand Up @@ -1342,6 +1408,24 @@ impl std::fmt::Display for PubGrubHint {
"403 Forbidden".red(),
)
}
Self::NoBuild { package } => {
write!(
f,
"{}{} Wheels are required for `{}` because building from source is disabled",
"hint".bold().cyan(),
":".bold(),
package.cyan(),
)
}
Self::NoBinary { package } => {
write!(
f,
"{}{} A source distributions is required for `{}` because using pre-built wheels is disabled",
"hint".bold().cyan(),
":".bold(),
package.cyan(),
)
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion crates/uv/tests/it/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12807,8 +12807,10 @@ fn no_binary_only_binary() -> Result<()> {

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only source-distribution>=0.0.1 is available and source-distribution==0.0.1 has no usable wheels and building from source is disabled, we can conclude that source-distribution<=0.0.1 cannot be used.
╰─▶ Because only source-distribution>=0.0.1 is available and source-distribution==0.0.1 has no usable wheels, we can conclude that source-distribution<=0.0.1 cannot be used.
And because you require source-distribution<=0.0.1, we can conclude that your requirements are unsatisfiable.

hint: Wheels are required for `source-distribution` because building from source is disabled
"###
);

Expand Down
8 changes: 6 additions & 2 deletions crates/uv/tests/it/pip_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2181,7 +2181,7 @@ fn install_only_binary_all_and_no_binary_all() {
anyio>=3.0.0,<=3.6.2
anyio>=3.7.0,<=3.7.1
anyio>=4.0.0
have no usable wheels and building from source is disabled, we can conclude that all of:
have no usable wheels, we can conclude that all of:
anyio>=1.0.0,<=1.4.0
anyio>=2.0.0,<=2.2.0
anyio>=3.0.0,<=3.6.2
Expand All @@ -2191,6 +2191,8 @@ fn install_only_binary_all_and_no_binary_all() {
And because you require anyio, we can conclude that your requirements are unsatisfiable.

hint: Pre-releases are available for `anyio` in the requested range (e.g., 4.0.0rc1), but pre-releases weren't enabled (try: `--prerelease=allow`)

hint: Wheels are required for `anyio` because building from source is disabled
"###
);

Expand Down Expand Up @@ -2281,7 +2283,9 @@ fn only_binary_requirements_txt() {

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because django-allauth==0.51.0 has no usable wheels and building from source is disabled and you require django-allauth==0.51.0, we can conclude that your requirements are unsatisfiable.
╰─▶ Because django-allauth==0.51.0 has no usable wheels and you require django-allauth==0.51.0, we can conclude that your requirements are unsatisfiable.

hint: Wheels are required for `django-allauth` because building from source is disabled
"###
);
}
Expand Down
8 changes: 6 additions & 2 deletions crates/uv/tests/it/pip_install_scenarios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4202,8 +4202,10 @@ fn no_wheels_no_build() {

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no usable wheels and building from source is disabled, we can conclude that all versions of package-a cannot be used.
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no usable wheels, we can conclude that all versions of package-a cannot be used.
And because you require package-a, we can conclude that your requirements are unsatisfiable.

hint: Wheels are required for `package-a` because building from source is disabled
"###);

assert_not_installed(&context.venv, "no_wheels_no_build_a", &context.temp_dir);
Expand Down Expand Up @@ -4310,8 +4312,10 @@ fn only_wheels_no_binary() {

----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no source distribution and using wheels is disabled, we can conclude that all versions of package-a cannot be used.
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no source distribution, we can conclude that all versions of package-a cannot be used.
And because you require package-a, we can conclude that your requirements are unsatisfiable.

hint: A source distributions is required for `package-a` because using pre-built wheels is disabled
"###);

assert_not_installed(&context.venv, "only_wheels_no_binary_a", &context.temp_dir);
Expand Down