Commit f317b003 by Sébastien Eustace

Improve dependency resolution debugging

parent 92d0eddf
...@@ -4,6 +4,9 @@ from typing import Any ...@@ -4,6 +4,9 @@ from typing import Any
from typing import Dict from typing import Dict
from typing import List from typing import List
from poetry.packages import Dependency
from poetry.packages import Package
from .assignment import Assignment from .assignment import Assignment
from .incompatibility import Incompatibility from .incompatibility import Incompatibility
from .set_relation import SetRelation from .set_relation import SetRelation
...@@ -25,7 +28,7 @@ class PartialSolution: ...@@ -25,7 +28,7 @@ class PartialSolution:
self._assignments = [] # type: List[Assignment] self._assignments = [] # type: List[Assignment]
# The decisions made for each package. # The decisions made for each package.
self._decisions = OrderedDict() # type: Dict[str, Any] self._decisions = OrderedDict() # type: Dict[str, Package]
# The intersection of all positive Assignments for each package, minus any # The intersection of all positive Assignments for each package, minus any
# negative Assignments that refer to that package. # negative Assignments that refer to that package.
...@@ -33,38 +36,41 @@ class PartialSolution: ...@@ -33,38 +36,41 @@ class PartialSolution:
# This is derived from self._assignments. # This is derived from self._assignments.
self._positive = OrderedDict() # type: Dict[str, Term] self._positive = OrderedDict() # type: Dict[str, Term]
# The union of all negative [Assignment]s for each package. # The union of all negative Assignments for each package.
# #
# If a package has any positive [Assignment]s, it doesn't appear in this # If a package has any positive Assignments, it doesn't appear in this
# map. # map.
# #
# This is derived from self._assignments. # This is derived from self._assignments.
self._negative = OrderedDict() # type: Dict[str, Dict[str, Term]] self._negative = OrderedDict() # type: Dict[str, Dict[str, Term]]
# The number of distinct solutions that have been attempted so far.
self._attempted_solutions = 1 self._attempted_solutions = 1
# Whether the solver is currently backtracking.
self._backtracking = False self._backtracking = False
@property @property
def decisions(self): # type: () -> Any def decisions(self): # type: () -> List[Package]
return list(self._decisions.values()) return list(self._decisions.values())
@property @property
def decision_level(self): def decision_level(self): # type: () -> int
return len(self._decisions) return len(self._decisions)
@property @property
def attempted_solutions(self): def attempted_solutions(self): # type: () -> int
return self._attempted_solutions return self._attempted_solutions
@property @property
def unsatisfied(self): def unsatisfied(self): # type: () -> List[Dependency]
return [ return [
term.dependency term.dependency
for term in self._positive.values() for term in self._positive.values()
if term.dependency.name not in self._decisions if term.dependency.name not in self._decisions
] ]
def decide(self, package): # type: (Any) -> None def decide(self, package): # type: (Package) -> None
""" """
Adds an assignment of package as a decision Adds an assignment of package as a decision
and increments the decision level. and increments the decision level.
...@@ -82,7 +88,7 @@ class PartialSolution: ...@@ -82,7 +88,7 @@ class PartialSolution:
self._assign(Assignment.decision(package, self.decision_level, len(self._assignments))) self._assign(Assignment.decision(package, self.decision_level, len(self._assignments)))
def derive(self, dependency, is_positive, cause def derive(self, dependency, is_positive, cause
): # type: (Any, bool, Incompatibility) -> None ): # type: (Dependency, bool, Incompatibility) -> None
""" """
Adds an assignment of package as a derivation. Adds an assignment of package as a derivation.
""" """
...@@ -101,6 +107,10 @@ class PartialSolution: ...@@ -101,6 +107,10 @@ class PartialSolution:
self._register(assignment) self._register(assignment)
def backtrack(self, decision_level): # type: (int) -> None def backtrack(self, decision_level): # type: (int) -> None
"""
Resets the current decision level to decision_level, and removes all
assignments made after that level.
"""
self._backtracking = True self._backtracking = True
packages = set() packages = set()
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Union
from poetry.packages import Dependency from poetry.packages import Dependency
from .set_relation import SetRelation from .set_relation import SetRelation
...@@ -8,9 +10,14 @@ class Term(object): ...@@ -8,9 +10,14 @@ class Term(object):
""" """
A statement about a package which is true or false for a given selection of A statement about a package which is true or false for a given selection of
package versions. package versions.
See https://github.com/dart-lang/pub/tree/master/doc/solver.md#term.
""" """
def __init__(self, dependency, is_positive): def __init__(self,
dependency, # type: Dependency
is_positive # type: bool
):
self._dependency = dependency self._dependency = dependency
self._positive = is_positive self._positive = is_positive
...@@ -100,7 +107,7 @@ class Term(object): ...@@ -100,7 +107,7 @@ class Term(object):
# not foo ^1.5.0 is a superset of not foo ^1.0.0 # not foo ^1.5.0 is a superset of not foo ^1.0.0
return SetRelation.OVERLAPPING return SetRelation.OVERLAPPING
def intersect(self, other): # type: (Term) -> Term def intersect(self, other): # type: (Term) -> Union[Term, None]
""" """
Returns a Term that represents the packages Returns a Term that represents the packages
allowed by both this term and another allowed by both this term and another
......
...@@ -363,7 +363,7 @@ class Provider: ...@@ -363,7 +363,7 @@ class Provider:
if self.is_debugging(): if self.is_debugging():
debug_info = str(message) debug_info = str(message)
debug_info = '\n'.join([ debug_info = '\n'.join([
'<comment>:{}:</> {}'.format(str(depth).rjust(4), s) '<comment>{}:</> {}'.format(str(depth).rjust(4), s)
for s in debug_info.split('\n') for s in debug_info.split('\n')
]) + '\n' ]) + '\n'
......
...@@ -257,6 +257,8 @@ class PyPiRepository(Repository): ...@@ -257,6 +257,8 @@ class PyPiRepository(Repository):
) )
def _get_release_info(self, name, version): # type: (str, str) -> dict def _get_release_info(self, name, version): # type: (str, str) -> dict
self._log('Getting info for {} ({}) from PyPI'.format(name, version), 'debug')
json_data = self._get('pypi/{}/{}/json'.format(name, version)) json_data = self._get('pypi/{}/{}/json'.format(name, version))
if json_data is None: if json_data is None:
raise ValueError('Package [{}] not found.'.format(name)) raise ValueError('Package [{}] not found.'.format(name))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment