Skip to content

Commit

Permalink
Prefer backtracking on dependencies involved in the most recent conflict
Browse files Browse the repository at this point in the history
This can significantly reduce the amount of backtracking required, by
avoiding backtracking on unrelated packages in the dependency graph.

Co-authored-by: Pradyun Gedam <pradyunsg@gmail.com>
  • Loading branch information
notatallshaw and pradyunsg committed Oct 9, 2021
1 parent 04b9ece commit 351da10
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
1 change: 1 addition & 0 deletions news/10479.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
When backtracking during dependency resolution, prefer the dependencies which are involved in the most recent conflict. This can significantly reduce the amount of backtracking required.
20 changes: 19 additions & 1 deletion src/pip/_internal/resolution/resolvelib/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def get_preference(
identifier: str,
resolutions: Mapping[str, Candidate],
candidates: Mapping[str, Iterator[Candidate]],
information: Mapping[str, Iterable["PreferenceInformation"]],
information: Mapping[str, Iterator["PreferenceInformation"]],
backtrack_causes: Sequence["RequirementInformation"],
) -> "Preference":
"""Produce a sort key for given requirement based on preference.
Expand Down Expand Up @@ -132,11 +133,17 @@ def get_preference(
# while we work on "proper" branch pruning techniques.
delay_this = identifier == "setuptools"

# Prefer the causes of backtracking on the assumption that the problem
# resolving the dependency tree is related to the failures that caused
# the backtracking
backtrack_cause = self.is_backtrack_cause(identifier, backtrack_causes)

return (
not requires_python,
delay_this,
not direct,
not pinned,
not backtrack_cause,
inferred_depth,
requested_order,
not unfree,
Expand Down Expand Up @@ -195,3 +202,14 @@ def is_satisfied_by(self, requirement: Requirement, candidate: Candidate) -> boo
def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]:
with_requires = not self._ignore_dependencies
return [r for r in candidate.iter_dependencies(with_requires) if r is not None]

@staticmethod
def is_backtrack_cause(
identifier: str, backtrack_causes: Sequence["RequirementInformation"]
) -> bool:
for backtrack_cause in backtrack_causes:
if identifier == backtrack_cause.requirement.name:
return True
if backtrack_cause.parent and identifier == backtrack_cause.parent.name:
return True
return False

0 comments on commit 351da10

Please sign in to comment.