Skip to content

Commit 66ded3b

Browse files
authored
Merge pull request #13570 from ShubhamNagure/fix-constraint-reporting-13545
Fix constraint reporting in dependency conflict resolution logs #13545
2 parents 67e8ac2 + fab4240 commit 66ded3b

File tree

4 files changed

+33
-9
lines changed

4 files changed

+33
-9
lines changed

news/13545.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Include relevant user-supplied constraints in logs when reporting dependency conflicts.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ def __init__(
100100
self._upgrade_strategy = upgrade_strategy
101101
self._user_requested = user_requested
102102

103+
@property
104+
def constraints(self) -> dict[str, Constraint]:
105+
"""Public view of user-specified constraints.
106+
107+
Exposes the provider's constraints mapping without encouraging
108+
external callers to reach into private attributes.
109+
"""
110+
return self._constraints
111+
103112
def identify(self, requirement_or_candidate: Requirement | Candidate) -> str:
104113
return requirement_or_candidate.name
105114

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
from __future__ import annotations
22

33
from collections import defaultdict
4+
from collections.abc import Mapping
45
from logging import getLogger
56
from typing import Any
67

78
from pip._vendor.resolvelib.reporters import BaseReporter
89

9-
from .base import Candidate, Requirement
10+
from .base import Candidate, Constraint, Requirement
1011

1112
logger = getLogger(__name__)
1213

1314

1415
class PipReporter(BaseReporter[Requirement, Candidate, str]):
15-
def __init__(self) -> None:
16+
def __init__(self, constraints: Mapping[str, Constraint] | None = None) -> None:
1617
self.reject_count_by_package: defaultdict[str, int] = defaultdict(int)
18+
self._constraints = constraints or {}
1719

1820
self._messages_at_reject_count = {
1921
1: (
@@ -35,25 +37,36 @@ def __init__(self) -> None:
3537
}
3638

3739
def rejecting_candidate(self, criterion: Any, candidate: Candidate) -> None:
40+
"""Report a candidate being rejected.
41+
42+
Logs both the rejection count message (if applicable) and details about
43+
the requirements and constraints that caused the rejection.
44+
"""
3845
self.reject_count_by_package[candidate.name] += 1
3946

4047
count = self.reject_count_by_package[candidate.name]
41-
if count not in self._messages_at_reject_count:
42-
return
43-
44-
message = self._messages_at_reject_count[count]
45-
logger.info("INFO: %s", message.format(package_name=candidate.name))
48+
if count in self._messages_at_reject_count:
49+
message = self._messages_at_reject_count[count]
50+
logger.info("INFO: %s", message.format(package_name=candidate.name))
4651

4752
msg = "Will try a different candidate, due to conflict:"
4853
for req_info in criterion.information:
4954
req, parent = req_info.requirement, req_info.parent
50-
# Inspired by Factory.get_installation_error
5155
msg += "\n "
5256
if parent:
5357
msg += f"{parent.name} {parent.version} depends on "
5458
else:
5559
msg += "The user requested "
5660
msg += req.format_for_error()
61+
62+
# Add any relevant constraints
63+
if self._constraints:
64+
name = candidate.name
65+
constraint = self._constraints.get(name)
66+
if constraint and constraint.specifier:
67+
constraint_text = f"{name}{constraint.specifier}"
68+
msg += f"\n The user requested (constraint) {constraint_text}"
69+
5770
logger.debug(msg)
5871

5972

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ def resolve(
8787
if "PIP_RESOLVER_DEBUG" in os.environ:
8888
reporter: BaseReporter[Requirement, Candidate, str] = PipDebuggingReporter()
8989
else:
90-
reporter = PipReporter()
90+
reporter = PipReporter(constraints=provider.constraints)
91+
9192
resolver: RLResolver[Requirement, Candidate, str] = RLResolver(
9293
provider,
9394
reporter,

0 commit comments

Comments
 (0)