diff options
Diffstat (limited to 'pkg_resources')
| -rw-r--r-- | pkg_resources/__init__.py | 48 | ||||
| -rw-r--r-- | pkg_resources/tests/test_resources.py | 28 |
2 files changed, 51 insertions, 25 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 8eb697f4..be215ccf 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]: - 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,26 @@ 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. + """ + extra_evals = ( + req.marker.evaluate({'extra': extra}) + for extra in self.get(req, ()) + ) + return not req.marker or any(extra_evals) or req.marker.evaluate() + + 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 7f86c797..0a72d941 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -186,6 +186,29 @@ class TestDistro: res = ws.resolve(parse_requirements("Foo;python_version>='2'"), ad) assert list(res) == [Foo] + 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 test_marker_evaluation_with_extras(self): """Extras are also evaluated as markers at resolution time.""" ad = pkg_resources.Environment([]) @@ -382,7 +405,10 @@ class TestEntryPoints: def checkSubMap(self, m): assert len(m) == len(self.submap_expect) for key, ep in self.submap_expect.items(): - assert repr(m.get(key)) == repr(ep) + assert m.get(key).name == ep.name + assert m.get(key).module_name == ep.module_name + assert sorted(m.get(key).attrs) == sorted(ep.attrs) + assert sorted(m.get(key).extras) == sorted(ep.extras) submap_expect = dict( feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), |
