def convert_dependency(self, dependency): # type: (Dependency) -> Constraint """Convert a user-defined dependency into a format Mixology understands.""" if isinstance(dependency.constraint, VersionRange): constraint = Range( dependency.constraint.min, dependency.constraint.max, dependency.constraint.include_min, dependency.constraint.include_max, dependency.pretty_constraint, ) else: # VersionUnion ranges = [ Range( _range.min, _range.max, _range.include_min, _range.include_max, str(_range), ) for _range in dependency.constraint.ranges ] constraint = Union.of(*ranges) return Constraint(dependency.name, constraint)
def solve(self): # type: () -> SolverResult """ Finds a set of dependencies that match the root package's constraints, or raises an error if no such set is available. """ start = time.time() self._add_incompatibility( Incompatibility( [Term(Constraint(self._source.root, Range()), False)], RootCause())) self._propagate(self._source.root) packages_tried = 0 max_tries = -1 while True: if packages_tried == max_tries: raise SolverFailure( "Stopping, {} packages tried.".format(max_tries)) if not self._run(): break packages_tried += 1 logger.info("Version solving took {:.3f} seconds.".format(time.time() - start)) logger.info("Tried {} solutions.".format( self._solution.attempted_solutions)) return SolverResult(self._solution.decisions, self._solution.attempted_solutions)
def intersect(self, other): # type: (Term) -> Term """ Returns a Term that represents the packages allowed by both this term and another """ if self.package != other.package: raise ValueError("{} should refer to {}".format( other, self.package)) if self.is_compatible_with(other): if self.is_positive() != other.is_positive(): # foo ^1.0.0 ∩ not foo ^1.5.0 → foo >=1.0.0 <1.5.0 positive = self if self.is_positive() else other negative = other if self.is_positive() else self return self._non_empty_term( positive.constraint.difference(negative.constraint), True) elif self.is_positive(): # foo ^1.0.0 ∩ foo >=1.5.0 <3.0.0 → foo ^1.5.0 return self._non_empty_term( self.constraint.intersect(other.constraint), True) else: # not foo ^1.0.0 ∩ not foo >=1.5.0 <3.0.0 → not foo >=1.0.0 <3.0.0 return self._non_empty_term( self.constraint.union(other.constraint), False) elif self.is_positive() != other.is_positive(): return self if self.is_positive() else other else: return Term(Constraint(self.package, EmptyRange()))
def decision(cls, package, version, decision_level, index): # type: (Hashable, Any, int, int) -> Assignment return cls( Constraint(package, Range(version, version, True, True)), True, decision_level, index, )
def incompatibilities_for( self, package, version ): # type: (Hashable, Any) -> List[Incompatibility] """ Returns the incompatibilities of a given package and version """ dependencies = self.dependencies_for(package, version) package_constraint = Constraint(package, Range(version, version, True, True)) incompatibilities = [] for dependency in dependencies: constraint = self.convert_dependency(dependency) if not isinstance(constraint, Constraint): constraint = Constraint(package, constraint) incompatibility = Incompatibility( [Term(package_constraint, True), Term(constraint, False)], cause=DependencyCause(), ) incompatibilities.append(incompatibility) return incompatibilities
def intersect(self, other): # type: (Term) -> Term """ Returns a Term that represents the packages allowed by both this term and another """ if self.package != other.package: raise ValueError("{} should refer to {}".format( other, self.package)) if self.is_compatible_with(other): if self.is_positive() != other.is_positive(): # foo ^1.0.0 ∩ not foo ^1.5.0 → foo >=1.0.0 <1.5.0 positive = self if self.is_positive() else other negative = other if self.is_positive() else self to_return = self._non_empty_term( positive.constraint.difference(negative.constraint), True) elif self.is_positive(): # foo ^1.0.0 ∩ foo >=1.5.0 <3.0.0 → foo ^1.5.0 to_return = self._non_empty_term( self.constraint.intersect(other.constraint), True) else: # not foo ^1.0.0 ∩ not foo >=1.5.0 <3.0.0 → not foo >=1.0.0 <3.0.0 to_return = self._non_empty_term( self.constraint.union(other.constraint), False) if to_return is not None: to_return._constraint._package._req = parse_req( to_return.constraint.package.req.__str__(), extras=self.constraint.package.req.extras | other.constraint.package.req.extras, ) to_return._package = self.constraint.package elif self.is_positive() != other.is_positive(): to_return = self if self.is_positive() else other else: to_return = Term(Constraint(self.package, EmptyRange())) return to_return
def convert_dependency(self, dependency): # type: (Dependency) -> Constraint if isinstance(dependency.constraint, VersionRange): constraint = Range( dependency.constraint.min, dependency.constraint.max, dependency.constraint.include_min, dependency.constraint.include_max, dependency.pretty_constraint, ) else: # VersionUnion ranges = [ Range( range.min, range.max, range.include_min, range.include_max, str(range), ) for range in dependency.constraint.ranges ] constraint = Union.of(*ranges) return Constraint(dependency.name, constraint)