diff options
-rw-r--r-- | pkg_resources/__init__.py | 53 | ||||
-rw-r--r-- | pkg_resources/tests/test_resources.py | 23 |
2 files changed, 48 insertions, 28 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index c3e3e96c..d0ba5159 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -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""" diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 7907224e..acc8dc1e 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -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.""" |