Skip to content

Commit

Permalink
Tree pruning seems to work?
Browse files Browse the repository at this point in the history
  • Loading branch information
uranusjr committed Jan 5, 2021
1 parent 3cd67b0 commit f90b097
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
46 changes: 36 additions & 10 deletions src/resolvelib/resolvers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import collections
import itertools

from .providers import AbstractResolver
from .structs import DirectedGraph, build_iter_view
Expand Down Expand Up @@ -143,6 +144,7 @@ def __init__(self, provider, reporter):
self._p = provider
self._r = reporter
self._states = []
self._known_failures = []

@property
def state(self):
Expand Down Expand Up @@ -199,15 +201,43 @@ def _get_criteria_to_update(self, candidate):
criteria[name] = crit
return criteria

def _match_known_failure_causes(self, updating_criteria):
try:
match_identically = self._p.match_identically
except AttributeError:
return False
criteria = self.state.criteria.copy()
criteria.update(updating_criteria)
for state, causes in self._known_failures:
identical = match_identically(
itertools.chain.from_iterable(
crit.iter_requirement()
for crit in criteria.values()
),
itertools.chain.from_iterable(
crit.iter_requirement()
for crit in state.criteria.values()
),
)
if identical:
return causes
return None

def _attempt_to_pin_criterion(self, name, criterion):
causes = []

for candidate in criterion.candidates:
try:
criteria = self._get_criteria_to_update(candidate)
except RequirementsConflicted as e:
causes.append(e.criterion)
continue

known_causes = self._match_known_failure_causes(criteria)
if known_causes:
causes = known_causes
continue

# Check the newly-pinned candidate actually works. This should
# always pass under normal circumstances, but in the case of a
# faulty provider, we will raise an error to notify the implementer
Expand All @@ -232,7 +262,7 @@ def _attempt_to_pin_criterion(self, name, criterion):
# end, signal for backtracking.
return causes

def _backtrack(self):
def _backtrack(self, causes):
"""Perform backtracking.
When we enter here, the stack is like this::
Expand Down Expand Up @@ -264,6 +294,7 @@ def _backtrack(self):

# Retrieve the last candidate pin and known incompatibilities.
broken_state = self._states.pop()
self._known_failures.append((broken_state, causes))
name, candidate = broken_state.mapping.popitem()
incompatibilities_from_broken = [
(k, v.incompatibilities)
Expand Down Expand Up @@ -296,13 +327,13 @@ def _patch_criteria():

# It works! Let's work on this new state.
if success:
return True
return

# State does not work after applying known incompatibilities.
# Try the still previous state.

# No way to backtrack anymore.
return False
# No way to backtrack anymore. Give up.
raise ResolutionImpossible([i for c in causes for i in c.information])

def resolve(self, requirements, max_rounds):
if self._states:
Expand Down Expand Up @@ -348,12 +379,7 @@ def resolve(self, requirements, max_rounds):
if failure_causes:
# Backtrack if pinning fails. The backtrack process puts us in
# an unpinned state, so we can work on it in the next round.
success = self._backtrack()

# Dead ends everywhere. Give up.
if not success:
causes = [i for c in failure_causes for i in c.information]
raise ResolutionImpossible(causes)
self._backtrack(failure_causes)
else:
# Pinning was successful. Push a new state to do another pin.
self._push_new_state()
Expand Down
8 changes: 8 additions & 0 deletions tests/test_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ def is_satisfied_by(self, requirement, candidate):
and candidate.version in requirement.versions
)

def match_identically(self, reqs1, reqs2):
vers1 = collections.defaultdict(set)
vers2 = collections.defaultdict(set)
for rs, vs in [(reqs1, vers1), (reqs2, vers2)]:
for r in rs:
vs[r.name] = vs[r.name].union(r.versions)
return vers1 == vers2

def get_dependencies(self, candidate):
return candidate.dependencies

Expand Down

0 comments on commit f90b097

Please sign in to comment.