summaryrefslogtreecommitdiff
path: root/pkg_resources
diff options
context:
space:
mode:
Diffstat (limited to 'pkg_resources')
-rw-r--r--pkg_resources/__init__.py48
-rw-r--r--pkg_resources/tests/test_resources.py28
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']),