summaryrefslogtreecommitdiff
path: root/pkg_resources
diff options
context:
space:
mode:
authorSteve Kowalik <steven@wedontsleep.org>2016-04-04 16:27:32 +1000
committerSteve Kowalik <steven@wedontsleep.org>2016-04-05 16:50:48 +1000
commit1cdd940877e158f2b748f67f09d1f1321a113998 (patch)
tree351c75d2535d47ab2347641de42a6a4b38b99d6b /pkg_resources
parent9803058dc72867605bdac20d41249c00e8eae415 (diff)
downloadpython-setuptools-git-1cdd940877e158f2b748f67f09d1f1321a113998.tar.gz
Restore evaluating environment markers in WorkingSet
Correctly deal with parsed requirements that include extras as a marker inside WorkingSet that are populated from METADATA inside wheels, like we get from pip>=7. This partially reverts commit 04d10ff025e1cbef7ec93a2008c930e856045c8a. Closes: #523
Diffstat (limited to 'pkg_resources')
-rw-r--r--pkg_resources/__init__.py14
-rw-r--r--pkg_resources/tests/test_resources.py79
2 files changed, 85 insertions, 8 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py
index eb84f4ba..4f0a487e 100644
--- a/pkg_resources/__init__.py
+++ b/pkg_resources/__init__.py
@@ -791,6 +791,8 @@ class WorkingSet(object):
# key -> dist
best = {}
to_activate = []
+ # Map requirement to the extras that require it
+ extra_req_mapping = {}
# Mapping of requirement to set of distributions that required it;
# useful for reporting info about conflicts.
@@ -804,9 +806,14 @@ class WorkingSet(object):
continue
# If the req has a marker, evaluate it -- skipping the req if
# it evaluates to False.
- # https://github.com/pypa/setuptools/issues/523
- _issue_523_bypass = True
- if not _issue_523_bypass and req.marker and not req.marker.evaluate():
+ if req.marker:
+ 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())
+ if not any(result):
continue
dist = best.get(req.key)
if dist is None:
@@ -840,6 +847,7 @@ 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
processed[req] = True
diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py
index 98b8dcd7..7f86c797 100644
--- a/pkg_resources/tests/test_resources.py
+++ b/pkg_resources/tests/test_resources.py
@@ -171,16 +171,85 @@ class TestDistro:
msg = 'Foo 0.9 is installed but Foo==1.2 is required'
assert vc.value.report() == msg
- @pytest.mark.xfail(reason="Functionality disabled; see #523")
- def test_environment_markers(self):
- """
- Environment markers are evaluated at resolution time.
- """
+ def test_environment_marker_evaluation_negative(self):
+ """Environment markers are evaluated at resolution time."""
ad = pkg_resources.Environment([])
ws = WorkingSet([])
res = ws.resolve(parse_requirements("Foo;python_version<'2'"), ad)
assert list(res) == []
+ def test_environment_marker_evaluation_positive(self):
+ ad = pkg_resources.Environment([])
+ ws = WorkingSet([])
+ Foo = Distribution.from_filename("/foo_dir/Foo-1.2.dist-info")
+ ad.add(Foo)
+ res = ws.resolve(parse_requirements("Foo;python_version>='2'"), ad)
+ assert list(res) == [Foo]
+
+ def test_marker_evaluation_with_extras(self):
+ """Extras are also evaluated as markers at resolution time."""
+ ad = pkg_resources.Environment([])
+ ws = WorkingSet([])
+ # Metadata needs to be native strings due to cStringIO behaviour in
+ # 2.6, so use str().
+ Foo = Distribution.from_filename(
+ "/foo_dir/Foo-1.2.dist-info",
+ metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
+ "Requires-Dist: quux; extra=='baz'")))
+ )
+ ad.add(Foo)
+ assert list(ws.resolve(parse_requirements("Foo"), ad)) == [Foo]
+ quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info")
+ ad.add(quux)
+ res = list(ws.resolve(parse_requirements("Foo[baz]"), ad))
+ assert res == [Foo,quux]
+
+ def test_marker_evaluation_with_multiple_extras(self):
+ ad = pkg_resources.Environment([])
+ ws = WorkingSet([])
+ # Metadata needs to be native strings due to cStringIO behaviour in
+ # 2.6, so use str().
+ Foo = Distribution.from_filename(
+ "/foo_dir/Foo-1.2.dist-info",
+ metadata=Metadata(("METADATA", str("Provides-Extra: baz\n"
+ "Requires-Dist: quux; extra=='baz'\n"
+ "Provides-Extra: bar\n"
+ "Requires-Dist: fred; extra=='bar'\n")))
+ )
+ ad.add(Foo)
+ quux = Distribution.from_filename("/foo_dir/quux-1.0.dist-info")
+ ad.add(quux)
+ fred = Distribution.from_filename("/foo_dir/fred-0.1.dist-info")
+ ad.add(fred)
+ res = list(ws.resolve(parse_requirements("Foo[baz,bar]"), ad))
+ assert sorted(res) == [fred,quux,Foo]
+
+ def test_marker_evaluation_with_extras_loop(self):
+ ad = pkg_resources.Environment([])
+ ws = WorkingSet([])
+ # Metadata needs to be native strings due to cStringIO behaviour in
+ # 2.6, so use str().
+ a = Distribution.from_filename(
+ "/foo_dir/a-0.2.dist-info",
+ metadata=Metadata(("METADATA", str("Requires-Dist: c[a]")))
+ )
+ b = Distribution.from_filename(
+ "/foo_dir/b-0.3.dist-info",
+ metadata=Metadata(("METADATA", str("Requires-Dist: c[b]")))
+ )
+ c = Distribution.from_filename(
+ "/foo_dir/c-1.0.dist-info",
+ metadata=Metadata(("METADATA", str("Provides-Extra: a\n"
+ "Requires-Dist: b;extra=='a'\n"
+ "Provides-Extra: b\n"
+ "Requires-Dist: foo;extra=='b'")))
+ )
+ foo = Distribution.from_filename("/foo_dir/foo-0.1.dist-info")
+ for dist in (a, b, c, foo):
+ ad.add(dist)
+ res = list(ws.resolve(parse_requirements("a"), ad))
+ assert res == [a, c, b, foo]
+
def testDistroDependsOptions(self):
d = self.distRequires("""
Twisted>=1.5