diff --git a/pex/distribution_target.py b/pex/distribution_target.py index d1ec090d0..0ec8878a5 100644 --- a/pex/distribution_target.py +++ b/pex/distribution_target.py @@ -38,6 +38,21 @@ def get_interpreter(self): def get_platform(self): return self._platform or Platform.current() + def requirement_applies(self, requirement): + """Determines if the given requirement applies to this distribution target. + + :param requirement: The requirement to evaluate. + :type requirement: :class:`pex.third_party.pkg_resources.Requirement` + :rtype: bool + """ + if not requirement.marker: + return True + + if self._interpreter is None: + return True + + return requirement.marker.evaluate(self._interpreter.identity.env_markers) + @property def id(self): """A unique id for a resolve target suitable as a path name component. diff --git a/pex/resolver.py b/pex/resolver.py index 79a09ee24..b38e57093 100644 --- a/pex/resolver.py +++ b/pex/resolver.py @@ -33,13 +33,15 @@ class Unsatisfiable(Exception): pass -class ResolvedDistribution(namedtuple('ResolvedDistribution', ['requirement', 'distribution'])): - """A requirement and the resolved distribution that satisfies it.""" +class ResolvedDistribution(namedtuple('ResolvedDistribution', + ['target', 'requirement', 'distribution'])): + """A distribution target, requirement and the resolved distribution that satisfies them both.""" - def __new__(cls, requirement, distribution): + def __new__(cls, target, requirement, distribution): + assert isinstance(target, DistributionTarget) assert isinstance(requirement, Requirement) assert isinstance(distribution, Distribution) - return super(ResolvedDistribution, cls).__new__(cls, requirement, distribution) + return super(ResolvedDistribution, cls).__new__(cls, target, requirement, distribution) class DistributionRequirements(object): @@ -565,6 +567,7 @@ def add_requirements_requests(install_result): for distribution in requirements_request.distributions: resolved_distributions.add( ResolvedDistribution( + target=requirements_request.target, requirement=distribution_requirements.to_requirement(distribution), distribution=distribution ) @@ -575,21 +578,26 @@ def add_requirements_requests(install_result): return resolved_distributions def _check_resolve(self, resolved_distributions): - dist_by_key = OrderedDict( - (resolved_distribution.requirement.key, resolved_distribution.distribution) + resolved_distribution_by_key = OrderedDict( + (resolved_distribution.requirement.key, resolved_distribution) for resolved_distribution in resolved_distributions ) unsatisfied = [] - for dist in dist_by_key.values(): + for resolved_distribution in resolved_distribution_by_key.values(): + dist = resolved_distribution.distribution + target = resolved_distribution.target for requirement in dist.requires(): - resolved_dist = dist_by_key.get(requirement.key) + if not target.requirement_applies(requirement): + continue + + resolved_dist = resolved_distribution_by_key.get(requirement.key) if not resolved_dist or resolved_dist not in requirement: unsatisfied.append( '{dist} requires {requirement} but {resolved_dist} was resolved'.format( dist=dist.as_requirement(), requirement=requirement, - resolved_dist=resolved_dist.as_requirement() if resolved_dist else None + resolved_dist=resolved_dist.distribution.as_requirement() if resolved_dist else None ) )