Skip to content

Commit 56e5b4d

Browse files
authored
Improve presentation of build-time errors (#13590)
Co-authored-by: Pradyun Gedam <[email protected]>
1 parent d96a80c commit 56e5b4d

File tree

3 files changed

+39
-7
lines changed

3 files changed

+39
-7
lines changed

src/pip/_internal/build_env.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,14 @@ def install(
169169
args.append("--prefer-binary")
170170
args.append("--")
171171
args.extend(requirements)
172+
173+
identify_requirement = (
174+
f" for {for_req.name}" if for_req and for_req.name else ""
175+
)
172176
with open_spinner(f"Installing {kind}") as spinner:
173177
call_subprocess(
174178
args,
175-
command_desc=f"pip subprocess to install {kind}",
179+
command_desc=f"installing {kind}{identify_requirement}",
176180
spinner=spinner,
177181
)
178182

src/pip/_internal/exceptions.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,23 @@ class InstallationError(PipError):
190190
"""General exception during installation"""
191191

192192

193+
class FailedToPrepareCandidate(InstallationError):
194+
"""Raised when we fail to prepare a candidate (i.e. fetch and generate metadata).
195+
196+
This is intentionally not a diagnostic error, since the output will be presented
197+
above this error, when this occurs. This should instead present information to the
198+
user.
199+
"""
200+
201+
def __init__(
202+
self, *, package_name: str, requirement_chain: str, failed_step: str
203+
) -> None:
204+
super().__init__(f"Failed to build '{package_name}' when {failed_step.lower()}")
205+
self.package_name = package_name
206+
self.requirement_chain = requirement_chain
207+
self.failed_step = failed_step
208+
209+
193210
class MissingPyProjectBuildRequires(DiagnosticPipError):
194211
"""Raised when pyproject.toml has `build-system`, but no `build-system.requires`."""
195212

@@ -384,7 +401,7 @@ def __init__(
384401
output_lines: list[str] | None,
385402
) -> None:
386403
if output_lines is None:
387-
output_prompt = Text("See above for output.")
404+
output_prompt = Text("No available output.")
388405
else:
389406
output_prompt = (
390407
Text.from_markup(f"[red][{len(output_lines)} lines of output][/]\n")
@@ -412,15 +429,15 @@ def __str__(self) -> str:
412429
return f"{self.command_description} exited with {self.exit_code}"
413430

414431

415-
class MetadataGenerationFailed(InstallationSubprocessError, InstallationError):
432+
class MetadataGenerationFailed(DiagnosticPipError, InstallationError):
416433
reference = "metadata-generation-failed"
417434

418435
def __init__(
419436
self,
420437
*,
421438
package_details: str,
422439
) -> None:
423-
super(InstallationSubprocessError, self).__init__(
440+
super().__init__(
424441
message="Encountered error while generating package metadata.",
425442
context=escape(package_details),
426443
hint_stmt="See above for details.",

src/pip/_internal/resolution/resolvelib/candidates.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pip._vendor.packaging.version import Version
1111

1212
from pip._internal.exceptions import (
13+
FailedToPrepareCandidate,
1314
HashError,
1415
InstallationSubprocessError,
1516
InvalidInstalledPackage,
@@ -244,9 +245,19 @@ def _prepare(self) -> BaseDistribution:
244245
e.req = self._ireq
245246
raise
246247
except InstallationSubprocessError as exc:
247-
# The output has been presented already, so don't duplicate it.
248-
exc.context = "See above for output."
249-
raise
248+
if isinstance(self._ireq.comes_from, InstallRequirement):
249+
request_chain = self._ireq.comes_from.from_path()
250+
else:
251+
request_chain = self._ireq.comes_from
252+
253+
if request_chain is None:
254+
request_chain = "directly requested"
255+
256+
raise FailedToPrepareCandidate(
257+
package_name=self._ireq.name or str(self._link),
258+
requirement_chain=request_chain,
259+
failed_step=exc.command_description,
260+
)
250261

251262
self._check_metadata_consistency(dist)
252263
return dist

0 commit comments

Comments
 (0)