Change venv

This commit is contained in:
Ambulance Clerc
2023-05-31 08:31:22 +02:00
parent fb6f579089
commit fdbb52c96f
466 changed files with 25899 additions and 64721 deletions

View File

@@ -1,10 +1,10 @@
import collections
import itertools
import operator
from .providers import AbstractResolver
from .structs import DirectedGraph, IteratorMapping, build_iter_view
RequirementInformation = collections.namedtuple(
"RequirementInformation", ["requirement", "parent"]
)
@@ -99,7 +99,7 @@ class ResolutionTooDeep(ResolutionError):
# Resolution state in a round.
State = collections.namedtuple("State", "mapping criteria")
State = collections.namedtuple("State", "mapping criteria backtrack_causes")
class Resolution(object):
@@ -131,6 +131,7 @@ class Resolution(object):
state = State(
mapping=base.mapping.copy(),
criteria=base.criteria.copy(),
backtrack_causes=base.backtrack_causes[:],
)
self._states.append(state)
@@ -173,6 +174,31 @@ class Resolution(object):
raise RequirementsConflicted(criterion)
criteria[identifier] = criterion
def _remove_information_from_criteria(self, criteria, parents):
"""Remove information from parents of criteria.
Concretely, removes all values from each criterion's ``information``
field that have one of ``parents`` as provider of the requirement.
:param criteria: The criteria to update.
:param parents: Identifiers for which to remove information from all criteria.
"""
if not parents:
return
for key, criterion in criteria.items():
criteria[key] = Criterion(
criterion.candidates,
[
information
for information in criterion.information
if (
information.parent is None
or self._p.identify(information.parent) not in parents
)
],
criterion.incompatibilities,
)
def _get_preference(self, name):
return self._p.get_preference(
identifier=name,
@@ -185,6 +211,7 @@ class Resolution(object):
self.state.criteria,
operator.attrgetter("information"),
),
backtrack_causes=self.state.backtrack_causes,
)
def _is_current_pin_satisfying(self, name, criterion):
@@ -211,6 +238,7 @@ class Resolution(object):
try:
criteria = self._get_updated_criteria(candidate)
except RequirementsConflicted as e:
self._r.rejecting_candidate(e.criterion, candidate)
causes.append(e.criterion)
continue
@@ -239,8 +267,8 @@ class Resolution(object):
# end, signal for backtracking.
return causes
def _backtrack(self):
"""Perform backtracking.
def _backjump(self, causes):
"""Perform backjumping.
When we enter here, the stack is like this::
@@ -256,22 +284,46 @@ class Resolution(object):
Each iteration of the loop will:
1. Discard Z.
2. Discard Y but remember its incompatibility information gathered
1. Identify Z. The incompatibility is not always caused by the latest
state. For example, given three requirements A, B and C, with
dependencies A1, B1 and C1, where A1 and B1 are incompatible: the
last state might be related to C, so we want to discard the
previous state.
2. Discard Z.
3. Discard Y but remember its incompatibility information gathered
previously, and the failure we're dealing with right now.
3. Push a new state Y' based on X, and apply the incompatibility
4. Push a new state Y' based on X, and apply the incompatibility
information from Y to Y'.
4a. If this causes Y' to conflict, we need to backtrack again. Make Y'
5a. If this causes Y' to conflict, we need to backtrack again. Make Y'
the new Z and go back to step 2.
4b. If the incompatibilities apply cleanly, end backtracking.
5b. If the incompatibilities apply cleanly, end backtracking.
"""
incompatible_reqs = itertools.chain(
(c.parent for c in causes if c.parent is not None),
(c.requirement for c in causes),
)
incompatible_deps = {self._p.identify(r) for r in incompatible_reqs}
while len(self._states) >= 3:
# Remove the state that triggered backtracking.
del self._states[-1]
# Retrieve the last candidate pin and known incompatibilities.
broken_state = self._states.pop()
name, candidate = broken_state.mapping.popitem()
# Ensure to backtrack to a state that caused the incompatibility
incompatible_state = False
while not incompatible_state:
# Retrieve the last candidate pin and known incompatibilities.
try:
broken_state = self._states.pop()
name, candidate = broken_state.mapping.popitem()
except (IndexError, KeyError):
raise ResolutionImpossible(causes)
current_dependencies = {
self._p.identify(d)
for d in self._p.get_dependencies(candidate)
}
incompatible_state = not current_dependencies.isdisjoint(
incompatible_deps
)
incompatibilities_from_broken = [
(k, list(v.incompatibilities))
for k, v in broken_state.criteria.items()
@@ -280,8 +332,6 @@ class Resolution(object):
# Also mark the newly known incompatibility.
incompatibilities_from_broken.append((name, [candidate]))
self._r.backtracking(candidate=candidate)
# Create a new state from the last known-to-work one, and apply
# the previously gathered incompatibility information.
def _patch_criteria():
@@ -335,7 +385,13 @@ class Resolution(object):
self._r.starting()
# Initialize the root state.
self._states = [State(mapping=collections.OrderedDict(), criteria={})]
self._states = [
State(
mapping=collections.OrderedDict(),
criteria={},
backtrack_causes=[],
)
]
for r in requirements:
try:
self._add_to_criteria(self.state.criteria, r, parent=None)
@@ -361,20 +417,38 @@ class Resolution(object):
self._r.ending(state=self.state)
return self.state
# keep track of satisfied names to calculate diff after pinning
satisfied_names = set(self.state.criteria.keys()) - set(
unsatisfied_names
)
# Choose the most preferred unpinned criterion to try.
name = min(unsatisfied_names, key=self._get_preference)
failure_causes = self._attempt_to_pin_criterion(name)
if failure_causes:
# Backtrack if pinning fails. The backtrack process puts us in
causes = [i for c in failure_causes for i in c.information]
# Backjump if pinning fails. The backjump process puts us in
# an unpinned state, so we can work on it in the next round.
success = self._backtrack()
self._r.resolving_conflicts(causes=causes)
success = self._backjump(causes)
self.state.backtrack_causes[:] = causes
# Dead ends everywhere. Give up.
if not success:
causes = [i for c in failure_causes for i in c.information]
raise ResolutionImpossible(causes)
raise ResolutionImpossible(self.state.backtrack_causes)
else:
# discard as information sources any invalidated names
# (unsatisfied names that were previously satisfied)
newly_unsatisfied_names = {
key
for key, criterion in self.state.criteria.items()
if key in satisfied_names
and not self._is_current_pin_satisfying(key, criterion)
}
self._remove_information_from_criteria(
self.state.criteria, newly_unsatisfied_names
)
# Pinning was successful. Push a new state to do another pin.
self._push_new_state()