Skip to content

Commit 43b7f3f

Browse files
authored
Merge pull request #9300
2 parents 0ffff03 + 32376bf commit 43b7f3f

File tree

6 files changed

+54
-15
lines changed

6 files changed

+54
-15
lines changed

news/9300.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
New resolver: Show relevant entries from user-supplied constraint files in the
2+
error message to improve debuggability.

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

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,24 @@ def _report_requires_python_error(
404404
)
405405
return UnsupportedPythonVersion(message)
406406

407-
def get_installation_error(self, e):
408-
# type: (ResolutionImpossible) -> InstallationError
407+
def _report_single_requirement_conflict(self, req, parent):
408+
# type: (Requirement, Candidate) -> DistributionNotFound
409+
if parent is None:
410+
req_disp = str(req)
411+
else:
412+
req_disp = f"{req} (from {parent.name})"
413+
logger.critical(
414+
"Could not find a version that satisfies the requirement %s",
415+
req_disp,
416+
)
417+
return DistributionNotFound(f"No matching distribution found for {req}")
418+
419+
def get_installation_error(
420+
self,
421+
e, # type: ResolutionImpossible
422+
constraints, # type: Dict[str, Constraint]
423+
):
424+
# type: (...) -> InstallationError
409425

410426
assert e.causes, "Installation error reported with no cause"
411427

@@ -425,15 +441,8 @@ def get_installation_error(self, e):
425441
# satisfied. We just report that case.
426442
if len(e.causes) == 1:
427443
req, parent = e.causes[0]
428-
if parent is None:
429-
req_disp = str(req)
430-
else:
431-
req_disp = f"{req} (from {parent.name})"
432-
logger.critical(
433-
"Could not find a version that satisfies the requirement %s",
434-
req_disp,
435-
)
436-
return DistributionNotFound(f"No matching distribution found for {req}")
444+
if req.name not in constraints:
445+
return self._report_single_requirement_conflict(req, parent)
437446

438447
# OK, we now have a list of requirements that can't all be
439448
# satisfied at once.
@@ -475,13 +484,20 @@ def describe_trigger(parent):
475484
)
476485
logger.critical(msg)
477486
msg = "\nThe conflict is caused by:"
487+
488+
relevant_constraints = set()
478489
for req, parent in e.causes:
490+
if req.name in constraints:
491+
relevant_constraints.add(req.name)
479492
msg = msg + "\n "
480493
if parent:
481494
msg = msg + "{} {} depends on ".format(parent.name, parent.version)
482495
else:
483496
msg = msg + "The user requested "
484497
msg = msg + req.format_for_error()
498+
for key in relevant_constraints:
499+
spec = constraints[key].specifier
500+
msg += f"\n The user requested (constraint) {key}{spec}"
485501

486502
msg = (
487503
msg

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def resolve(self, root_reqs, check_supported_wheels):
122122
)
123123

124124
except ResolutionImpossible as e:
125-
error = self.factory.get_installation_error(e)
125+
error = self.factory.get_installation_error(e, constraints)
126126
six.raise_from(error, e)
127127

128128
req_set = RequirementSet(check_supported_wheels=check_supported_wheels)

tests/functional/test_install_reqs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ def test_constraints_local_editable_install_causes_error(
357357
assert 'Could not satisfy constraints' in result.stderr, str(result)
358358
else:
359359
# Because singlemodule only has 0.0.1 available.
360-
assert 'No matching distribution found' in result.stderr, str(result)
360+
assert 'Cannot install singlemodule 0.0.1' in result.stderr, str(result)
361361

362362

363363
@pytest.mark.network
@@ -386,7 +386,7 @@ def test_constraints_local_install_causes_error(
386386
assert 'Could not satisfy constraints' in result.stderr, str(result)
387387
else:
388388
# Because singlemodule only has 0.0.1 available.
389-
assert 'No matching distribution found' in result.stderr, str(result)
389+
assert 'Cannot install singlemodule 0.0.1' in result.stderr, str(result)
390390

391391

392392
def test_constraints_constrain_to_local_editable(

tests/functional/test_new_resolver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ def test_new_resolver_constraint_on_dependency(script):
687687
@pytest.mark.parametrize(
688688
"constraint_version, expect_error, message",
689689
[
690-
("1.0", True, "ERROR: No matching distribution found for foo 2.0"),
690+
("1.0", True, "Cannot install foo 2.0"),
691691
("2.0", False, "Successfully installed foo-2.0"),
692692
],
693693
)

tests/functional/test_new_resolver_errors.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,24 @@ def test_new_resolver_conflict_requirements_file(tmpdir, script):
2424

2525
message = "package versions have conflicting dependencies"
2626
assert message in result.stderr, str(result)
27+
28+
29+
def test_new_resolver_conflict_constraints_file(tmpdir, script):
30+
create_basic_wheel_for_package(script, "pkg", "1.0")
31+
32+
constrats_file = tmpdir.joinpath("constraints.txt")
33+
constrats_file.write_text("pkg!=1.0")
34+
35+
result = script.pip(
36+
"install",
37+
"--no-cache-dir", "--no-index",
38+
"--find-links", script.scratch_path,
39+
"-c", constrats_file,
40+
"pkg==1.0",
41+
expect_error=True,
42+
)
43+
44+
assert "ResolutionImpossible" in result.stderr, str(result)
45+
46+
message = "The user requested (constraint) pkg!=1.0"
47+
assert message in result.stdout, str(result)

0 commit comments

Comments
 (0)