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
9 changes: 6 additions & 3 deletions crates/uv-errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ impl Hints<'_> {
}

/// Extend with another set of hints, converting borrowed hints to owned.
pub fn extend(&mut self, other: Hints<'_>) {
for hint in other.0 {
let hint = Cow::Owned(hint.into_owned());
pub fn extend<T>(&mut self, other: impl IntoIterator<Item = T>)
where
T: Into<String>,
{
for hint in other {
let hint = Cow::Owned(hint.into());
if !self.0.iter().any(|existing| existing == &hint) {
self.0.push(hint);
}
Expand Down
61 changes: 26 additions & 35 deletions crates/uv/src/commands/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,65 +68,54 @@ impl OperationDiagnostic {
///
/// Returns `Some` if the error was not handled.
pub(crate) fn report(self, err: pip::operations::Error) -> Option<pip::operations::Error> {
let result = match err {
let mut hints = match err {
pip::operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(err)) => {
no_solution(&err, self.context);
None
no_solution(&err, self.context)
}
pip::operations::Error::Resolve(uv_resolver::ResolveError::Dist(
kind,
dist,
chain,
err,
)) => {
requested_dist_error(kind, dist, &chain, err);
None
}
)) => requested_dist_error(kind, dist, &chain, err),
pip::operations::Error::Resolve(uv_resolver::ResolveError::Dependencies(
error,
name,
version,
chain,
)) => {
dependencies_error(error, &name, &version, &chain);
None
}
)) => dependencies_error(error, &name, &version, &chain),
pip::operations::Error::Requirements(uv_requirements::Error::Dist(kind, dist, err)) => {
dist_error(kind, dist, &DerivationChain::default(), Arc::new(*err));
None
dist_error(kind, dist, &DerivationChain::default(), Arc::new(*err))
}
pip::operations::Error::Prepare(uv_installer::PrepareError::Dist(
kind,
dist,
chain,
err,
)) => {
dist_error(kind, dist, &chain, Arc::new(*err));
None
}
)) => dist_error(kind, dist, &chain, Arc::new(*err)),
pip::operations::Error::Requirements(err) if let Some(context) = self.context => {
let err = miette::Report::msg(format!("{err}"))
.context(format!("Failed to resolve {context} requirement"));
anstream::eprint!("{err:?}");
None
Hints::none()
}
pip::operations::Error::Requirements(err) => {
Some(pip::operations::Error::Requirements(err))
return Some(pip::operations::Error::Requirements(err));
}
err @ pip::operations::Error::OutdatedEnvironment(..) => {
anstream::eprintln!("{}", err);
None
Hints::none()
}
err => Some(err),
err => return Some(err),
};

// Render the caller-provided hints after the error output.
if result.is_none() {
let hints: Hints<'_> = self.hints.into_iter().collect();
anstream::eprint!("{hints}");
// Render all hints after the error output.
hints.extend(self.hints);
if !hints.is_empty() {
anstream::eprintln!("{hints}");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit strange that we do write!(f, "\n{HintPrefix} {hint}")?; internally when there's no reason to keep have a hint without a trailing newline, but this is the smaller fix.

}

result
None
}
}

Expand All @@ -138,7 +127,7 @@ fn dist_error(
dist: Box<Dist>,
chain: &DerivationChain,
cause: Arc<uv_distribution::Error>,
) {
) -> Hints<'static> {
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("{kind} `{dist}`")]
#[diagnostic()]
Expand All @@ -152,7 +141,7 @@ fn dist_error(
let hints = dist_hints(dist.name(), dist.version(), chain, cause.hints());
let report = miette::Report::new(Diagnostic { kind, dist, cause });
anstream::eprint!("{report:?}");
anstream::eprint!("{hints}");
hints
}

/// Render a requested distribution failure (read, download or build) with a help message.
Expand All @@ -163,7 +152,7 @@ fn requested_dist_error(
dist: Box<RequestedDist>,
chain: &DerivationChain,
cause: Arc<uv_distribution::Error>,
) {
) -> Hints<'static> {
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("{kind} `{dist}`")]
#[diagnostic()]
Expand All @@ -177,7 +166,7 @@ fn requested_dist_error(
let hints = dist_hints(dist.name(), dist.version(), chain, cause.hints());
let report = miette::Report::new(Diagnostic { kind, dist, cause });
anstream::eprint!("{report:?}");
anstream::eprint!("{hints}");
hints
}

/// Render an error in fetching a package's dependencies.
Expand All @@ -188,7 +177,7 @@ fn dependencies_error(
name: &PackageName,
version: &Version,
chain: &DerivationChain,
) {
) -> Hints<'static> {
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("Failed to resolve dependencies for `{}` ({})", name.cyan(), format!("v{version}").cyan())]
#[diagnostic()]
Expand All @@ -206,11 +195,14 @@ fn dependencies_error(
cause: error,
});
anstream::eprint!("{report:?}");
anstream::eprint!("{hints}");
hints
}

/// Render a [`uv_resolver::NoSolutionError`].
fn no_solution(err: &uv_resolver::NoSolutionError, context: Option<&'static str>) {
fn no_solution(
err: &uv_resolver::NoSolutionError,
context: Option<&'static str>,
) -> Hints<'static> {
let header = uv_resolver::NoSolutionHeader::new(err.environment().clone());
let header = if let Some(context) = context {
header.with_context(context)
Expand All @@ -219,8 +211,7 @@ fn no_solution(err: &uv_resolver::NoSolutionError, context: Option<&'static str>
};
let report = miette::Report::msg(err.report().to_string()).context(header);
anstream::eprint!("{report:?}");
let hints = err.hints();
anstream::eprint!("{hints}");
err.hints().into_owned()
}

/// Format an error chain with the default user-facing hints and output settings.
Expand Down
3 changes: 2 additions & 1 deletion crates/uv/tests/pip_compile/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6893,7 +6893,7 @@ fn no_index_requirements_txt() -> Result<()> {
let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str("--no-index\ntqdm")?;

uv_snapshot!(context.filters(), context.pip_compile()
let output = uv_snapshot!(context.filters(), context.pip_compile()
.arg("requirements.in"), @"
exit_code: 1 (failure)
----- stderr -----
Expand All @@ -6903,6 +6903,7 @@ fn no_index_requirements_txt() -> Result<()> {
hint: Packages were unavailable because index lookups were disabled and no additional package locations were provided (try: `--find-links <uri>`)
"
);
assert_eq!(output.stderr.last(), Some(&b'\n'));

Ok(())
}
Expand Down
Loading