diff options
author | Steve Kowalik <steven@wedontsleep.org> | 2016-04-04 16:27:32 +1000 |
---|---|---|
committer | Steve Kowalik <steven@wedontsleep.org> | 2016-04-05 16:50:48 +1000 |
commit | 1cdd940877e158f2b748f67f09d1f1321a113998 (patch) | |
tree | 351c75d2535d47ab2347641de42a6a4b38b99d6b | |
parent | 9803058dc72867605bdac20d41249c00e8eae415 (diff) | |
download | external_python_setuptools-1cdd940877e158f2b748f67f09d1f1321a113998.tar.gz external_python_setuptools-1cdd940877e158f2b748f67f09d1f1321a113998.tar.bz2 external_python_setuptools-1cdd940877e158f2b748f67f09d1f1321a113998.zip |
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
-rw-r--r-- | pkg_resources/__init__.py | 14 | ||||
-rw-r--r-- | pkg_resources/tests/test_resources.py | 79 | ||||
-rw-r--r-- | setuptools/tests/test_egg_info.py | 3 |
3 files changed, 85 insertions, 11 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 diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index d37567b4..fd5f26fc 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -104,7 +104,6 @@ class TestEggInfo(object): 'setup.py': setup_script, }) - @pytest.mark.xfail(reason="Functionality disabled; see #523") def test_install_requires_with_markers(self, tmpdir_cwd, env): self._setup_script_with_requires( """install_requires=["barbazquux;python_version<'2'"],""") @@ -115,14 +114,12 @@ class TestEggInfo(object): requires_txt).read().split('\n') assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == [] - @pytest.mark.xfail(reason="Functionality disabled; see #523") def test_setup_requires_with_markers(self, tmpdir_cwd, env): self._setup_script_with_requires( """setup_requires=["barbazquux;python_version<'2'"],""") self._run_install_command(tmpdir_cwd, env) assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == [] - @pytest.mark.xfail(reason="Functionality disabled; see #523") def test_tests_require_with_markers(self, tmpdir_cwd, env): self._setup_script_with_requires( """tests_require=["barbazquux;python_version<'2'"],""") |