Commit be663b85 authored by Jason R. Coombs's avatar Jason R. Coombs

Extract _ReqExtras to encapsulate that functionality and decouple it from WorkingSet.

parent 1bf18cc8
...@@ -791,8 +791,8 @@ class WorkingSet(object): ...@@ -791,8 +791,8 @@ class WorkingSet(object):
# key -> dist # key -> dist
best = {} best = {}
to_activate = [] to_activate = []
# Map requirement to the extras that require it
extra_req_mapping = {} req_extras = _ReqExtras()
# Mapping of requirement to set of distributions that required it; # Mapping of requirement to set of distributions that required it;
# useful for reporting info about conflicts. # useful for reporting info about conflicts.
...@@ -805,7 +805,7 @@ class WorkingSet(object): ...@@ -805,7 +805,7 @@ class WorkingSet(object):
# Ignore cyclic or redundant dependencies # Ignore cyclic or redundant dependencies
continue continue
if not self._markers_pass(req, extra_req_mapping): if not req_extras.markers_pass(req):
continue continue
dist = best.get(req.key) dist = best.get(req.key)
...@@ -840,33 +840,13 @@ class WorkingSet(object): ...@@ -840,33 +840,13 @@ class WorkingSet(object):
# Register the new requirements needed by req # Register the new requirements needed by req
for new_requirement in new_requirements: for new_requirement in new_requirements:
required_by[new_requirement].add(req.project_name) required_by[new_requirement].add(req.project_name)
extra_req_mapping[new_requirement] = req.extras req_extras[new_requirement] = req.extras
processed[req] = True processed[req] = True
# return list of distros to activate # return list of distros to activate
return to_activate return to_activate
@staticmethod
def _markers_pass(req, extra_req_mapping):
"""
Return False if the req has a marker and fails
evaluation. Otherwise, return True.
extra_req_mapping is a map of requirements to
extras.
"""
if not req.marker:
return True
result = []
if req in extra_req_mapping:
for extra in extra_req_mapping[req] or ['']:
result.append(req.marker.evaluate({'extra': extra}))
else:
result.append(req.marker.evaluate())
return any(result)
def find_plugins(self, plugin_env, full_env=None, installer=None, def find_plugins(self, plugin_env, full_env=None, installer=None,
fallback=True): fallback=True):
"""Find all activatable distributions in `plugin_env` """Find all activatable distributions in `plugin_env`
...@@ -993,6 +973,31 @@ class WorkingSet(object): ...@@ -993,6 +973,31 @@ class WorkingSet(object):
self.callbacks = callbacks[:] self.callbacks = callbacks[:]
class _ReqExtras(dict):
"""
Map each requirement to the extras that demanded it.
"""
def markers_pass(self, req):
"""
Evaluate markers for req against each extra that
demanded it.
Return False if the req has a marker and fails
evaluation. Otherwise, return True.
"""
if not req.marker:
return True
result = []
if req in self:
for extra in self[req] or ['']:
result.append(req.marker.evaluate({'extra': extra}))
else:
result.append(req.marker.evaluate())
return any(result)
class Environment(object): class Environment(object):
"""Searchable snapshot of distributions on a search path""" """Searchable snapshot of distributions on a search path"""
......
...@@ -187,10 +187,25 @@ class TestDistro: ...@@ -187,10 +187,25 @@ class TestDistro:
assert list(res) == [Foo] assert list(res) == [Foo]
def test_environment_marker_evaluation_called(self): def test_environment_marker_evaluation_called(self):
ws = WorkingSet([]) """
req, = parse_requirements("bar;python_version<'4'") If one package foo requires bar without any extras,
extra_req_mapping = {req: ()} markers should pass for bar.
assert ws._markers_pass(req, extra_req_mapping) == True """
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)
# this is a little awkward; I would want this to fail
parent_req, = parse_requirements("foo")
req, = parse_requirements("bar;python_version>='2' and extra==''")
req_extras = pkg_resources._ReqExtras({req: parent_req.extras})
assert req_extras.markers_pass(req)
def test_marker_evaluation_with_extras(self): def test_marker_evaluation_with_extras(self):
"""Extras are also evaluated as markers at resolution time.""" """Extras are also evaluated as markers at resolution time."""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment