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