1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4from __future__ import absolute_import, division, print_function 5 6import pytest 7 8from packaging.markers import Marker 9from packaging.requirements import InvalidRequirement, Requirement, URL 10from packaging.requirements import URL_AND_MARKER 11from packaging.specifiers import SpecifierSet 12 13 14class TestRequirements: 15 def test_string_specifier_marker(self): 16 requirement = 'name[bar]>=3; python_version == "2.7"' 17 req = Requirement(requirement) 18 assert str(req) == requirement 19 20 def test_string_url(self): 21 requirement = "name@ http://foo.com" 22 req = Requirement(requirement) 23 assert str(req) == requirement 24 25 def test_string_url_with_marker(self): 26 requirement = 'name@ http://foo.com ; extra == "feature"' 27 req = Requirement(requirement) 28 assert str(req) == requirement 29 30 def test_repr(self): 31 req = Requirement("name") 32 assert repr(req) == "<Requirement('name')>" 33 34 def _assert_requirement( 35 self, req, name, url=None, extras=[], specifier="", marker=None 36 ): 37 assert req.name == name 38 assert req.url == url 39 assert sorted(req.extras) == sorted(extras) 40 assert str(req.specifier) == specifier 41 if marker: 42 assert str(req.marker) == marker 43 else: 44 assert req.marker is None 45 46 def test_simple_names(self): 47 for name in ("A", "aa", "name"): 48 req = Requirement(name) 49 self._assert_requirement(req, name) 50 51 def test_name_with_other_characters(self): 52 name = "foo-bar.quux_baz" 53 req = Requirement(name) 54 self._assert_requirement(req, name) 55 56 def test_invalid_name(self): 57 with pytest.raises(InvalidRequirement): 58 Requirement("foo!") 59 60 def test_name_with_version(self): 61 req = Requirement("name>=3") 62 self._assert_requirement(req, "name", specifier=">=3") 63 64 def test_with_legacy_version(self): 65 req = Requirement("name==1.0.org1") 66 self._assert_requirement(req, "name", specifier="==1.0.org1") 67 68 def test_with_legacy_version_and_marker(self): 69 req = Requirement("name>=1.x.y;python_version=='2.6'") 70 self._assert_requirement( 71 req, "name", specifier=">=1.x.y", marker='python_version == "2.6"' 72 ) 73 74 def test_version_with_parens_and_whitespace(self): 75 req = Requirement("name (==4)") 76 self._assert_requirement(req, "name", specifier="==4") 77 78 def test_name_with_multiple_versions(self): 79 req = Requirement("name>=3,<2") 80 self._assert_requirement(req, "name", specifier="<2,>=3") 81 82 def test_name_with_multiple_versions_and_whitespace(self): 83 req = Requirement("name >=2, <3") 84 self._assert_requirement(req, "name", specifier="<3,>=2") 85 86 def test_extras(self): 87 req = Requirement("foobar [quux,bar]") 88 self._assert_requirement(req, "foobar", extras=["bar", "quux"]) 89 90 def test_empty_extras(self): 91 req = Requirement("foo[]") 92 self._assert_requirement(req, "foo") 93 94 def test_url(self): 95 url_section = "@ http://example.com" 96 parsed = URL.parseString(url_section) 97 assert parsed.url == "http://example.com" 98 99 def test_url_and_marker(self): 100 instring = "@ http://example.com ; os_name=='a'" 101 parsed = URL_AND_MARKER.parseString(instring) 102 assert parsed.url == "http://example.com" 103 assert str(parsed.marker) == 'os_name == "a"' 104 105 def test_invalid_url(self): 106 with pytest.raises(InvalidRequirement) as e: 107 Requirement("name @ gopher:/foo/com") 108 assert "Invalid URL: " in str(e.value) 109 assert "gopher:/foo/com" in str(e.value) 110 111 def test_file_url(self): 112 req = Requirement("name @ file:///absolute/path") 113 self._assert_requirement(req, "name", "file:///absolute/path") 114 req = Requirement("name @ file://.") 115 self._assert_requirement(req, "name", "file://.") 116 117 def test_invalid_file_urls(self): 118 with pytest.raises(InvalidRequirement): 119 Requirement("name @ file:.") 120 with pytest.raises(InvalidRequirement): 121 Requirement("name @ file:/.") 122 123 def test_extras_and_url_and_marker(self): 124 req = Requirement("name [fred,bar] @ http://foo.com ; python_version=='2.7'") 125 self._assert_requirement( 126 req, 127 "name", 128 extras=["bar", "fred"], 129 url="http://foo.com", 130 marker='python_version == "2.7"', 131 ) 132 133 def test_complex_url_and_marker(self): 134 url = "https://example.com/name;v=1.1/?query=foo&bar=baz#blah" 135 req = Requirement("foo @ %s ; python_version=='3.4'" % url) 136 self._assert_requirement(req, "foo", url=url, marker='python_version == "3.4"') 137 138 def test_multiple_markers(self): 139 req = Requirement( 140 "name[quux, strange];python_version<'2.7' and " "platform_version=='2'" 141 ) 142 marker = 'python_version < "2.7" and platform_version == "2"' 143 self._assert_requirement(req, "name", extras=["strange", "quux"], marker=marker) 144 145 def test_multiple_comparsion_markers(self): 146 req = Requirement("name; os_name=='a' and os_name=='b' or os_name=='c'") 147 marker = 'os_name == "a" and os_name == "b" or os_name == "c"' 148 self._assert_requirement(req, "name", marker=marker) 149 150 def test_invalid_marker(self): 151 with pytest.raises(InvalidRequirement): 152 Requirement("name; foobar=='x'") 153 154 def test_types(self): 155 req = Requirement("foobar[quux]<2,>=3; os_name=='a'") 156 assert isinstance(req.name, str) 157 assert isinstance(req.extras, set) 158 assert req.url is None 159 assert isinstance(req.specifier, SpecifierSet) 160 assert isinstance(req.marker, Marker) 161 162 def test_types_with_nothing(self): 163 req = Requirement("foobar") 164 assert isinstance(req.name, str) 165 assert isinstance(req.extras, set) 166 assert req.url is None 167 assert isinstance(req.specifier, SpecifierSet) 168 assert req.marker is None 169 170 def test_types_with_url(self): 171 req = Requirement("foobar @ http://foo.com") 172 assert isinstance(req.name, str) 173 assert isinstance(req.extras, set) 174 assert isinstance(req.url, str) 175 assert isinstance(req.specifier, SpecifierSet) 176 assert req.marker is None 177 178 def test_sys_platform_linux_equal(self): 179 req = Requirement('something>=1.2.3; sys_platform == "foo"') 180 181 assert req.name == "something" 182 assert req.marker is not None 183 assert req.marker.evaluate(dict(sys_platform="foo")) is True 184 assert req.marker.evaluate(dict(sys_platform="bar")) is False 185 186 def test_sys_platform_linux_in(self): 187 req = Requirement("aviato>=1.2.3; 'f' in sys_platform") 188 189 assert req.name == "aviato" 190 assert req.marker is not None 191 assert req.marker.evaluate(dict(sys_platform="foo")) is True 192 assert req.marker.evaluate(dict(sys_platform="bar")) is False 193 194 def test_parseexception_error_msg(self): 195 with pytest.raises(InvalidRequirement) as e: 196 Requirement("toto 42") 197 assert "Expected stringEnd" in str(e.value) 198