def test_conflicting_dependencies(self): # Given packages_definition = textwrap.dedent(""" MKL 10.3-1 MKL 11.4.1-1 numpy 1.9.2-1; depends (MKL == 10.3-1) numpy 1.10.4-1; depends (MKL == 11.4.1-1) scipy 0.16.0-1; depends (MKL == 10.3-1, numpy ^= 1.9.2) scipy 0.17.0-1; depends (MKL == 11.4.1-1, numpy ^= 1.10.4) """) packages = packages_from_definition(packages_definition) def callback(requirements): return requirements_are_satisfiable(packages, requirements).is_satisfiable r_min_unsat = [ Requirement._from_string("MKL < 11"), Requirement._from_string("scipy >= 0.17.0"), ] # When requirements = [ Requirement._from_string("MKL < 11"), Requirement._from_string("numpy"), Requirement._from_string("scipy >= 0.17.0"), ] min_unsat = minimal_unsatisfiable_subset(requirements, callback) # Then six.assertCountEqual(self, min_unsat, r_min_unsat)
def test_simple(self): # Given packages_definition = textwrap.dedent("""\ MKL 10.3-1 MKL 11.4.1-1 numpy 1.9.2-1; depends (MKL == 10.3-1) numpy 1.10.4-1; depends (MKL == 11.4.1-1) """) packages = packages_from_definition(packages_definition) def callback(requirements): return requirements_are_satisfiable(packages, requirements).is_satisfiable r_min_unsat = [ Requirement._from_string("numpy < 1.10"), Requirement._from_string("MKL >= 11") ] # When requirements = [ Requirement._from_string("numpy < 1.10"), Requirement._from_string("MKL >= 11") ] min_unsat = minimal_unsatisfiable_subset(requirements, callback) # Then six.assertCountEqual(self, min_unsat, r_min_unsat)
def from_yaml(cls, file_or_filename): if isinstance(file_or_filename, six.string_types): with open(file_or_filename) as fp: data = yaml.load(fp, Loader=_UnicodeLoader) else: data = yaml.load(file_or_filename, Loader=_UnicodeLoader) scenario_requests = data.get("request", []) marked = list(data.get("marked", [])) request = Request() for kind, values in data.get("modifiers", {}).items(): for value in values: getattr(request, kind)(value) update_all = False for s_request in scenario_requests: kind = s_request["operation"] if kind == 'update_all': update_all = True continue requirement = Requirement._from_string(s_request["requirement"]) try: marked.remove(requirement.name) except ValueError: pass getattr(request, kind)(requirement) if update_all: request_job = request.hard_update else: request_job = request.install for package_str in marked: request_job(Requirement._from_string(package_str)) decisions = data.get("decisions", {}) operations = cls._operations_from_transaction_list( data.get("transaction", [])) pretty_operations = cls._operations_from_transaction_list( data.get("pretty_transaction", [])) failure = data.get('failure') packages = collections.OrderedDict( parse_package_list(data.get("packages", []))) return cls(packages, [remote_repository(data, packages)], installed_repository(data, packages), request, decisions, operations, pretty_operations, failure=failure)
def from_yaml(cls, file_or_filename): if isinstance(file_or_filename, six.string_types): with open(file_or_filename) as fp: data = yaml.load(fp, Loader=_UnicodeLoader) else: data = yaml.load(file_or_filename, Loader=_UnicodeLoader) scenario_requests = data.get("request", []) marked = list(data.get("marked", [])) request = Request() for kind, values in data.get("modifiers", {}).items(): for value in values: getattr(request, kind)(value) update_all = False for s_request in scenario_requests: kind = s_request["operation"] if kind == 'update_all': update_all = True continue requirement = Requirement._from_string(s_request["requirement"]) try: marked.remove(requirement.name) except ValueError: pass getattr(request, kind)(requirement) if update_all: request_job = request.hard_update else: request_job = request.install for package_str in marked: request_job(Requirement._from_string(package_str)) decisions = data.get("decisions", {}) operations = cls._operations_from_transaction_list( data.get("transaction", [])) pretty_operations = cls._operations_from_transaction_list( data.get("pretty_transaction", [])) failure = data.get('failure') packages = collections.OrderedDict( parse_package_list(data.get("packages", []))) return cls(packages, [remote_repository(data, packages)], installed_repository(data, packages), request, decisions, operations, pretty_operations, failure=failure)
def test_constraint_modifiers(self): # Given packages_definition = textwrap.dedent(""" MKL 10.3-1 MKL 11.4.1-1 numpy 1.9.2-1; depends (MKL == 10.3-1) numpy 1.10.4-1; depends (MKL == 11.4.1-1) """) packages = packages_from_definition(packages_definition) requirements = [ Requirement._from_string("numpy < 1.10"), Requirement._from_string("MKL >= 11") ] modifiers = ConstraintModifiers(allow_newer=("MKL", )) # When/Then result = requirements_are_satisfiable(packages, requirements) self.assertFalse(result.is_satisfiable) result = requirements_are_satisfiable(packages, requirements, modifiers) self.assertTrue(result.is_satisfiable)
def _solve(self, top_core, flags={}, only_matching_vlnv=False): def eq_vln(this, that): return \ this.vendor == that.vendor and \ this.library == that.library and \ this.name == that.name repo = Repository() _flags = flags.copy() cores = [x['core'] for x in self._cores.values()] for core in cores: if only_matching_vlnv: if not eq_vln(core.name, top_core): continue package_str = "{} {}-{}".format(self._package_name(core.name), core.name.version, core.name.revision) if not only_matching_vlnv: _flags['is_toplevel'] = (core.name == top_core) _depends = core.get_depends(_flags) if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() _top_dep = "{} {} {}".format(self._package_name(top_core), top_core.relation, self._package_version(top_core)) requirement = Requirement._from_string(_top_dep) request.install(requirement) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, [repo], installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: raise DependencyError(top_core.name, msg=e.unsat.to_string(pool)) except NoPackageFound as e: raise DependencyError(top_core.name) return [op.package.core for op in transaction.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 solve(self, top_core, tool): repo = Repository() for core in self._cores.values(): package_str = "{} {}-{}".format(self._package_name(core.name), core.name.version, core.name.revision) _depends = core.depend try: _depends += getattr(core, tool).depend except (AttributeError, KeyError): pass if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() _top_dep = "{} {} {}".format(self._package_name(top_core), top_core.relation, self._package_version(top_core)) requirement = Requirement._from_string(_top_dep) request.install(requirement) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, repo, installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: msg = "UNSATISFIABLE: {}" raise RuntimeError(msg.format(e.unsat.to_string(pool))) except NoPackageFound as e: raise DependencyError(top_core.name) return [op.package.core for op in transaction.operations]
def add_repository(self, repository): """ Add the repository to this pool. Parameters ---------- repository : Repository The repository to add """ self._repositories.append(repository) for package in repository: current_id = self._id self._id += 1 self._id_to_package_[current_id] = package self._package_to_id_[package] = current_id for constraints in package.provides: req = Requirement.from_constraints(constraints) if req.has_any_version_constraint: msg = ('Version constraints are not supported for' ' package.provides metadata: {}') raise InvalidConstraint(msg.format(req)) self._packages_by_name_[req.name].append(package)
def add_repository(self, repository): """ Add the repository to this pool. Parameters ---------- repository : Repository The repository to add """ self._repositories.append(repository) for package in repository: current_id = self._id self._id += 1 self._id_to_package_[current_id] = package self._package_to_id_[package] = current_id for constraints in package.provides: req = Requirement.from_constraints(constraints) if req.has_any_version_constraint: msg = ('Version constraints are not supported for' ' package.provides metadata: {}') raise InvalidConstraint(msg.format(req)) self._packages_by_name_[req.name].append(package)
def _solve(self, top_core, flags={}, only_matching_vlnv=False): def eq_vln(this, that): return ( this.vendor == that.vendor and this.library == that.library and this.name == that.name ) # Try to return a cached result solver_cache_key = (top_core, self._hash_flags_dict(flags), only_matching_vlnv) cached_solution = self._solver_cache_lookup(solver_cache_key) if cached_solution: return cached_solution repo = Repository() _flags = flags.copy() cores = [x["core"] for x in self._cores.values()] for core in cores: if only_matching_vlnv: if not eq_vln(core.name, top_core): continue package_str = "{} {}-{}".format( self._package_name(core.name), core.name.version, core.name.revision ) if not only_matching_vlnv: _flags["is_toplevel"] = core.name == top_core _depends = core.get_depends(_flags) if _depends: _s = "; depends ( {} )" package_str += _s.format(self._parse_depend(_depends)) parser = PrettyPackageStringParser(EnpkgVersion.from_string) package = parser.parse_to_package(package_str) package.core = core repo.add_package(package) request = Request() simplevlnvs = top_core.simpleVLNVs() for sv in simplevlnvs: _top_dep = "{} {} {}".format( self._package_name(top_core), top_core.relation, self._package_version(top_core), ) request.install(Requirement._from_string(_top_dep)) installed_repository = Repository() pool = Pool([repo]) pool.add_repository(installed_repository) solver = DependencySolver(pool, [repo], installed_repository) try: transaction = solver.solve(request) except SatisfiabilityError as e: raise DependencyError(top_core.name, msg=e.unsat.to_string(pool)) except NoPackageFound as e: raise DependencyError(top_core.name) objdict = {} depdict = {} if len(transaction.operations) > 1: for op in transaction.operations: objdict[op.package._name] = str(op.package.core.name) depdict[str(op.package.core.name)] = [ objdict[n[0]] for n in op.package.install_requires ] op.package.core.direct_deps = [ objdict[n[0]] for n in op.package.install_requires ] result = [op.package.core for op in transaction.operations] # Cache the solution for further lookups self._solver_cache_store(solver_cache_key, result) return result
def from_yaml(cls, file_or_filename): if isinstance(file_or_filename, six.string_types): with open(file_or_filename) as fp: data = yaml.load(fp, Loader=_UnicodeLoader) else: data = yaml.load(file_or_filename, Loader=_UnicodeLoader) packages = collections.OrderedDict( parse_package_list(data.get("packages", [])) ) scenario_requests = data.get("request", []) marked = list(data.get("marked", [])) request = Request() update_all = False for s_request in scenario_requests: kind = s_request["operation"] if kind == 'update_all': update_all = True continue requirement = Requirement._from_string(s_request["requirement"]) try: marked.remove(requirement.name) except ValueError: pass getattr(request, kind)(requirement) if update_all: request_job = request.update else: request_job = request.install for package_str in marked: request_job(Requirement._from_string(package_str)) decisions = data.get("decisions", {}) def P(p): return next(parse_package_list([p]))[1] operations = [] for operation in data.get("transaction", []): if operation["kind"] == "install": operations.append(InstallOperation(P(operation["package"]))) elif operation["kind"] == "update": operations.append(UpdateOperation(P(operation["to"]), P(operation["from"]))) elif operation["kind"] == "remove": operations.append(RemoveOperation(P(operation["package"]))) else: msg = "invalid operation kind {!r}".format(operation["kind"]) raise ValueError(msg) failure = data.get('failure') return cls(packages, [remote_repository(data, packages)], installed_repository(data, packages), request, decisions, operations, failure)