def _add_package_rules(self, package): """ Create all the rules required to satisfy installing the given package. """ work_queue = collections.deque() work_queue.append(package) while len(work_queue) > 0: p = work_queue.popleft() p_id = self._pool.package_id(p) if p_id not in self.added_package_ids: self.added_package_ids.add(p_id) self._add_dependencies_rules(p, work_queue) requirement = Requirement.from_legacy_requirement_string(p.name) obsolete_providers = self._pool.what_provides(requirement) for provider in obsolete_providers: if provider != p: if provider.name == p.name: reason = RuleType.package_same_name else: reason = RuleType.package_implicit_obsoletes rule = self._create_conflicts_rule(p, provider, reason, str(p)) self._add_rule(rule, "package")
def _add_package_rules(self, package): """ Create all the rules required to satisfy installing the given package. """ work_queue = collections.deque() work_queue.append(package) while len(work_queue) > 0: p = work_queue.popleft() p_id = self._pool.package_id(p) if p_id not in self.added_package_ids: self.added_package_ids.add(p_id) self._add_dependencies_rules(p, work_queue) requirement = Requirement.from_legacy_requirement_string( p.name) obsolete_providers = self._pool.what_provides(requirement) for provider in obsolete_providers: if provider != p: if provider.name == p.name: reason = RuleType.package_same_name else: reason = RuleType.package_implicit_obsoletes rule = self._create_conflicts_rule( p, provider, reason, str(p)) self._add_rule(rule, "package")
def _from_string(cls, rule_string, pool): """ Creates a PackageRule from a rule string, e.g. '-numpy-1.6.0 | numpy-1.7.0' Because package full name -> id is not 1-to-1 mapping, this may fail when a package has multiple ids. This is mostly used for testing, to write reference rules a bit more easily. """ packages_string = (s.strip() for s in rule_string.split("|")) package_literals = [] for package_string in packages_string: if package_string.startswith("-"): positive = False package_string = package_string[1:] else: positive = True requirement = Requirement.from_package_string(package_string) package_candidates = pool.what_provides(requirement) if len(package_candidates) == 0: msg = "No candidate for package {0!r}".format(package_string) raise EnstallerException(msg) elif len(package_candidates) > 1: msg = "> 1 candidate for package {0!r} requirement, cannot " \ "create rule from it" % package_string raise EnstallerException(msg) else: _id = pool.package_id(package_candidates[0]) if positive: package_literals.append(_id) else: package_literals.append(-_id) return cls(package_literals)
def from_yaml(cls, filename): with open(filename) as fp: data = yaml.load(fp) packages = collections.OrderedDict( parse_package_list(data.get("packages", []))) operations = data.get("request", []) request = Request() for operation in operations: kind = operation["operation"] requirement = Requirement._from_string(operation["requirement"]) getattr(request, kind)(requirement) decisions = data.get("decisions", {}) operations = [] for operation in data.get("transaction", []): if operation["kind"] == "install": operations.append(InstallOperation(operation["package"])) elif operation["kind"] == "update": operations.append( UpdateOperation(operation["from"], operation["to"])) elif operation["kind"] == "remove": operations.append(RemoveOperation(operation["package"])) else: msg = "invalid operation kind {!r}".format(operation["kind"]) raise ValueError(msg) return cls(packages, [remote_repository(data, packages)], installed_repository(data, packages), request, decisions, operations)
def from_yaml(cls, filename): with open(filename) as fp: data = yaml.load(fp) packages = collections.OrderedDict( parse_package_list(data.get("packages", [])) ) operations = data.get("request", []) request = Request() for operation in operations: kind = operation["operation"] requirement = Requirement._from_string(operation["requirement"]) getattr(request, kind)(requirement) decisions = data.get("decisions", {}) operations = [] for operation in data.get("transaction", []): if operation["kind"] == "install": operations.append(InstallOperation(operation["package"])) elif operation["kind"] == "update": operations.append(UpdateOperation(operation["from"], operation["to"])) elif operation["kind"] == "remove": operations.append(RemoveOperation(operation["package"])) else: msg = "invalid operation kind {!r}".format(operation["kind"]) raise ValueError(msg) return cls(packages, [remote_repository(data, packages)], installed_repository(data, packages), request, decisions, operations)
def dependency_to_string(dependency): req = Requirement.from_legacy_requirement_string(dependency) constraints = list(req._constraints._constraints) assert len(constraints) == 1 assert isinstance(constraints[0], (EnpkgUpstreamMatch, Any, Equal)) constraint = constraints[0] if isinstance(constraint, Any): return req.name elif isinstance(constraint, Equal): return "{0} == {1}".format(req.name, str(constraint.version)) else: # EnpkgUpstreamMatch assert isinstance(constraint.version, EnpkgVersion) return "{0} ~= {1}".format(req.name, str(constraint.version.upstream))
def _add_dependencies_rules(self, package, work_queue): for dependency in package.dependencies: requirement = Requirement.from_legacy_requirement_string(dependency) dependency_candidates = self._pool.what_provides(requirement) assert len(dependency_candidates) > 0, \ ("No candidates found for requirement {0!r}, needed for " "dependency {1!r}".format(requirement.name, package)) rule = self._create_dependency_rule(package, dependency_candidates, RuleType.package_requires, str(dependency)) self._add_rule(rule, "package") for candidate in dependency_candidates: work_queue.append(candidate)
def _add_dependencies_rules(self, package, work_queue): for dependency in package.dependencies: requirement = Requirement.from_legacy_requirement_string( dependency) dependency_candidates = self._pool.what_provides(requirement) assert len(dependency_candidates) > 0, \ ("No candidates found for requirement {0!r}, needed for " "dependency {1!r}".format(requirement.name, package)) rule = self._create_dependency_rule(package, dependency_candidates, RuleType.package_requires, str(dependency)) self._add_rule(rule, "package") for candidate in dependency_candidates: work_queue.append(candidate)
def optimize_at_level(pool, parent_package, rules, solution): new_rules = rules[:] # Step 1: optimize each dependency independently best_dependencies = [] for dependency in parent_package.dependencies: requirement = Requirement.from_legacy_requirement_string(dependency) best_candidate = find_best_candidate(pool, requirement, new_rules) new_rules.append(PackageRule((best_candidate.id,))) best_dependencies.append(best_candidate) solution.extend(best_dependencies) # Step 2: recurse for dependency in best_dependencies: solution = optimize_at_level(pool, dependency, new_rules, solution) return solution
def legacy_dependencies_to_pretty_string(dependencies): """ Convert a sequence of legacy dependency strings to a pretty constraint string. Parameters ---------- dependencies : seq Sequence of legacy dependency string (e.g. 'MKL 10.3') """ constraints_mapping = [] for dependency in dependencies: req = Requirement.from_legacy_requirement_string(dependency) constraints = req._constraints._constraints assert len(constraints) == 1 constraint = next(iter(constraints)) assert isinstance(constraint, (EnpkgUpstreamMatch, Any, Equal)) constraints_mapping.append((req.name, frozenset((constraint,)))) return constraints_to_pretty_string(constraints_mapping)
# Step 2: recurse for dependency in best_dependencies: solution = optimize_at_level(pool, dependency, new_rules, solution) return solution def optimize(pool, requirement, rules): best_package = find_best_candidate(pool, requirement, rules) solution = [best_package] return optimize_at_level(pool, best_package, rules, solution) if __name__ == '__main__': repository = repository_from_index("full_index.json") pool = Pool([repository]) requirement_str = "scikit_learn < 0.14" requirement = Requirement._from_string(requirement_str) request = Request() request.install(requirement) rules_generator = RulesGenerator(pool, request) rules = list(rules_generator.iter_rules()) solution = optimize(pool, requirement, rules) for decision in solution: print(decision.name, str(decision.version))