From 351da10f8758a678ff93b662fd77225fd26ddd5c Mon Sep 17 00:00:00 2001 From: Damian Shaw Date: Sat, 4 Sep 2021 19:45:19 -0400 Subject: [PATCH] Prefer backtracking on dependencies involved in the most recent conflict This can significantly reduce the amount of backtracking required, by avoiding backtracking on unrelated packages in the dependency graph. Co-authored-by: Pradyun Gedam --- news/10479.feature.rst | 1 + .../resolution/resolvelib/provider.py | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 news/10479.feature.rst diff --git a/news/10479.feature.rst b/news/10479.feature.rst new file mode 100644 index 00000000000..23eaa6c8faa --- /dev/null +++ b/news/10479.feature.rst @@ -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. diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py index c2203933e40..f0d64532861 100644 --- a/src/pip/_internal/resolution/resolvelib/provider.py +++ b/src/pip/_internal/resolution/resolvelib/provider.py @@ -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. @@ -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, @@ -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