def test_environment_marker_evaluation_called(self): """ If one package foo requires bar without any extras, markers should pass for bar without extras. """ parent_req, = parse_requirements("foo") req, = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req) parent_req, = parse_requirements("foo[]") req, = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req)
def test_environment_marker_evaluation_called(self): """ If one package foo requires bar without any extras, markers should pass for bar. """ parent_req, = parse_requirements("foo") req, = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req) parent_req, = parse_requirements("foo[]") req, = parse_requirements("bar;python_version>='2'") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) assert req_extras.markers_pass(req) # extra should not be present in the marker namespace if # no markers were supplied parent_req, = parse_requirements("foo") req, = parse_requirements("bar;extra==''") req_extras = pkg_resources._ReqExtras({req: parent_req.extras}) with pytest.raises(packaging.markers.UndefinedEnvironmentName): req_extras.markers_pass(req)
def resolve( self, requirements: Sequence[Requirement], env: Optional[Environment] = None, installer: Optional[Callable[[str], Distribution]] = None, replace_conflicting: Optional[bool] = False, extras: List[str] = None, ) -> List[Distribution]: """List all distributions needed to (recursively) meet `requirements` `requirements` must be a sequence of ``Requirement`` objects. `env`, if supplied, should be an ``Environment`` instance. If not supplied, it defaults to all distributions available within any entry or distribution in the working set. `installer`, if supplied, will be invoked with each requirement that cannot be met by an already-installed distribution; it should return a ``Distribution`` or ``None``. Unless `replace_conflicting=True`, raises a VersionConflict exception if any requirements are found on the path that have the correct name but the wrong version. Otherwise, if an `installer` is supplied it will be invoked to obtain the correct version of the requirement and activate it. `extras` is a list of the extras to be used with these requirements. This is important because extra requirements may look like `my_req; extra = "my_extra"`, which would otherwise be interpreted as a purely optional requirement. Instead, we want to be able to assert that these requirements are truly required. """ # set up the stack requirements = list(requirements)[::-1] # set of processed requirements processed = {} # key -> dist best = {} resolved = [] requirement_extras = _ReqExtras() # Mapping of requirement to set of distributions that required it; # useful for reporting info about conflicts. required_by = defaultdict(set) while requirements: # process dependencies breadth-first requirement = requirements.pop(0) if requirement in processed: # Ignore cyclic or redundant dependencies continue if not requirement_extras.markers_pass(requirement, extras): continue dist = best.get(requirement.key) if dist is None: # Find the best distribution and add it to the map dist = self.by_key.get(requirement.key) if dist is None or (dist not in requirement and replace_conflicting): ws = self if env is None: if dist is None: env = Environment(self.entries) else: # Use an empty environment and workingset to avoid # any further conflicts with the conflicting # distribution env = Environment([]) ws = WorkingSet([]) dist = best[requirement.key] = env.best_match( requirement, ws, installer, replace_conflicting=replace_conflicting, ) if dist is None: requirers = required_by.get(requirement, None) raise DistributionNotFound(requirement, requirers) resolved.append(dist) if dist not in requirement: # Oops, the "best" so far conflicts with a dependency dependent_requirement = required_by[requirement] raise VersionConflict(dist, requirement).with_context( dependent_requirement ) # push the new requirements onto the stack new_requirements = [ requirement for requirement in dist.requires(requirement.extras)[::-1] if requirement.key not in self.excludes ] requirements.extend(new_requirements) # Register the new requirements needed by requirement for new_requirement in new_requirements: required_by[new_requirement].add(requirement.project_name) requirement_extras[new_requirement] = requirement.extras processed[requirement] = True # return list of distros to activate return resolved