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):
# key -> dist
best = {}
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;
# useful for reporting info about conflicts.
......@@ -805,7 +805,7 @@ class WorkingSet(object):
# Ignore cyclic or redundant dependencies
continue
if not self._markers_pass(req, extra_req_mapping):
if not req_extras.markers_pass(req):
continue
dist = best.get(req.key)
......@@ -840,33 +840,13 @@ class WorkingSet(object):
# Register the new requirements needed by req
for new_requirement in new_requirements:
required_by[new_requirement].add(req.project_name)
extra_req_mapping[new_requirement] = req.extras
req_extras[new_requirement] = req.extras
processed[req] = True
# return list of distros 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,
fallback=True):
"""Find all activatable distributions in `plugin_env`
......@@ -993,6 +973,31 @@ class WorkingSet(object):
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):
"""Searchable snapshot of distributions on a search path"""
......
......@@ -187,10 +187,25 @@ class TestDistro:
assert list(res) == [Foo]
def test_environment_marker_evaluation_called(self):
ws = WorkingSet([])
req, = parse_requirements("bar;python_version<'4'")
extra_req_mapping = {req: ()}
assert ws._markers_pass(req, extra_req_mapping) == True
"""
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)
# 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):
"""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