| 1 | n/a | """Tests for the packaging.pypi.dist module.""" |
|---|
| 2 | n/a | |
|---|
| 3 | n/a | import os |
|---|
| 4 | n/a | import shutil |
|---|
| 5 | n/a | from packaging.version import VersionPredicate |
|---|
| 6 | n/a | from packaging.pypi.dist import (ReleaseInfo, ReleasesList, DistInfo, |
|---|
| 7 | n/a | split_archive_name, get_infos_from_url) |
|---|
| 8 | n/a | from packaging.pypi.errors import HashDoesNotMatch, UnsupportedHashName |
|---|
| 9 | n/a | |
|---|
| 10 | n/a | from packaging.tests import unittest |
|---|
| 11 | n/a | from packaging.tests.support import TempdirManager, requires_zlib, fake_dec |
|---|
| 12 | n/a | try: |
|---|
| 13 | n/a | import threading |
|---|
| 14 | n/a | from packaging.tests.pypi_server import use_pypi_server |
|---|
| 15 | n/a | except ImportError: |
|---|
| 16 | n/a | threading = None |
|---|
| 17 | n/a | use_pypi_server = fake_dec |
|---|
| 18 | n/a | |
|---|
| 19 | n/a | |
|---|
| 20 | n/a | def Dist(*args, **kwargs): |
|---|
| 21 | n/a | # DistInfo takes a release as a first parameter, avoid this in tests. |
|---|
| 22 | n/a | return DistInfo(None, *args, **kwargs) |
|---|
| 23 | n/a | |
|---|
| 24 | n/a | |
|---|
| 25 | n/a | class TestReleaseInfo(unittest.TestCase): |
|---|
| 26 | n/a | |
|---|
| 27 | n/a | def test_instantiation(self): |
|---|
| 28 | n/a | # Test the DistInfo class provides us the good attributes when |
|---|
| 29 | n/a | # given on construction |
|---|
| 30 | n/a | release = ReleaseInfo("FooBar", "1.1") |
|---|
| 31 | n/a | self.assertEqual("FooBar", release.name) |
|---|
| 32 | n/a | self.assertEqual("1.1", "%s" % release.version) |
|---|
| 33 | n/a | |
|---|
| 34 | n/a | def test_add_dist(self): |
|---|
| 35 | n/a | # empty distribution type should assume "sdist" |
|---|
| 36 | n/a | release = ReleaseInfo("FooBar", "1.1") |
|---|
| 37 | n/a | release.add_distribution(url="http://example.org/") |
|---|
| 38 | n/a | # should not fail |
|---|
| 39 | n/a | release['sdist'] |
|---|
| 40 | n/a | |
|---|
| 41 | n/a | def test_get_unknown_distribution(self): |
|---|
| 42 | n/a | # should raise a KeyError |
|---|
| 43 | n/a | pass |
|---|
| 44 | n/a | |
|---|
| 45 | n/a | def test_get_infos_from_url(self): |
|---|
| 46 | n/a | # Test that the the URLs are parsed the right way |
|---|
| 47 | n/a | url_list = { |
|---|
| 48 | n/a | 'FooBar-1.1.0.tar.gz': { |
|---|
| 49 | n/a | 'name': 'foobar', # lowercase the name |
|---|
| 50 | n/a | 'version': '1.1.0', |
|---|
| 51 | n/a | }, |
|---|
| 52 | n/a | 'Foo-Bar-1.1.0.zip': { |
|---|
| 53 | n/a | 'name': 'foo-bar', # keep the dash |
|---|
| 54 | n/a | 'version': '1.1.0', |
|---|
| 55 | n/a | }, |
|---|
| 56 | n/a | 'foobar-1.1b2.tar.gz#md5=123123123123123': { |
|---|
| 57 | n/a | 'name': 'foobar', |
|---|
| 58 | n/a | 'version': '1.1b2', |
|---|
| 59 | n/a | 'url': 'http://example.org/foobar-1.1b2.tar.gz', # no hash |
|---|
| 60 | n/a | 'hashval': '123123123123123', |
|---|
| 61 | n/a | 'hashname': 'md5', |
|---|
| 62 | n/a | }, |
|---|
| 63 | n/a | 'foobar-1.1-rc2.tar.gz': { # use suggested name |
|---|
| 64 | n/a | 'name': 'foobar', |
|---|
| 65 | n/a | 'version': '1.1c2', |
|---|
| 66 | n/a | 'url': 'http://example.org/foobar-1.1-rc2.tar.gz', |
|---|
| 67 | n/a | } |
|---|
| 68 | n/a | } |
|---|
| 69 | n/a | |
|---|
| 70 | n/a | for url, attributes in url_list.items(): |
|---|
| 71 | n/a | # for each url |
|---|
| 72 | n/a | infos = get_infos_from_url("http://example.org/" + url) |
|---|
| 73 | n/a | for attribute, expected in attributes.items(): |
|---|
| 74 | n/a | got = infos.get(attribute) |
|---|
| 75 | n/a | if attribute == "version": |
|---|
| 76 | n/a | self.assertEqual("%s" % got, expected) |
|---|
| 77 | n/a | else: |
|---|
| 78 | n/a | self.assertEqual(got, expected) |
|---|
| 79 | n/a | |
|---|
| 80 | n/a | def test_split_archive_name(self): |
|---|
| 81 | n/a | # Test we can split the archive names |
|---|
| 82 | n/a | names = { |
|---|
| 83 | n/a | 'foo-bar-baz-1.0-rc2': ('foo-bar-baz', '1.0c2'), |
|---|
| 84 | n/a | 'foo-bar-baz-1.0': ('foo-bar-baz', '1.0'), |
|---|
| 85 | n/a | 'foobarbaz-1.0': ('foobarbaz', '1.0'), |
|---|
| 86 | n/a | } |
|---|
| 87 | n/a | for name, results in names.items(): |
|---|
| 88 | n/a | self.assertEqual(results, split_archive_name(name)) |
|---|
| 89 | n/a | |
|---|
| 90 | n/a | |
|---|
| 91 | n/a | class TestDistInfo(TempdirManager, unittest.TestCase): |
|---|
| 92 | n/a | srcpath = "/packages/source/f/foobar/foobar-0.1.tar.gz" |
|---|
| 93 | n/a | |
|---|
| 94 | n/a | def test_get_url(self): |
|---|
| 95 | n/a | # Test that the url property works well |
|---|
| 96 | n/a | |
|---|
| 97 | n/a | d = Dist(url="test_url") |
|---|
| 98 | n/a | self.assertDictEqual(d.url, { |
|---|
| 99 | n/a | "url": "test_url", |
|---|
| 100 | n/a | "is_external": True, |
|---|
| 101 | n/a | "hashname": None, |
|---|
| 102 | n/a | "hashval": None, |
|---|
| 103 | n/a | }) |
|---|
| 104 | n/a | |
|---|
| 105 | n/a | # add a new url |
|---|
| 106 | n/a | d.add_url(url="internal_url", is_external=False) |
|---|
| 107 | n/a | self.assertEqual(d._url, None) |
|---|
| 108 | n/a | self.assertDictEqual(d.url, { |
|---|
| 109 | n/a | "url": "internal_url", |
|---|
| 110 | n/a | "is_external": False, |
|---|
| 111 | n/a | "hashname": None, |
|---|
| 112 | n/a | "hashval": None, |
|---|
| 113 | n/a | }) |
|---|
| 114 | n/a | self.assertEqual(2, len(d.urls)) |
|---|
| 115 | n/a | |
|---|
| 116 | n/a | def test_comparison(self): |
|---|
| 117 | n/a | # Test that we can compare DistInfoributionInfoList |
|---|
| 118 | n/a | foo1 = ReleaseInfo("foo", "1.0") |
|---|
| 119 | n/a | foo2 = ReleaseInfo("foo", "2.0") |
|---|
| 120 | n/a | bar = ReleaseInfo("bar", "2.0") |
|---|
| 121 | n/a | # assert we use the version to compare |
|---|
| 122 | n/a | self.assertTrue(foo1 < foo2) |
|---|
| 123 | n/a | self.assertFalse(foo1 > foo2) |
|---|
| 124 | n/a | self.assertFalse(foo1 == foo2) |
|---|
| 125 | n/a | |
|---|
| 126 | n/a | # assert we can't compare dists with different names |
|---|
| 127 | n/a | self.assertRaises(TypeError, foo1.__eq__, bar) |
|---|
| 128 | n/a | |
|---|
| 129 | n/a | @unittest.skipIf(threading is None, 'needs threading') |
|---|
| 130 | n/a | @use_pypi_server("downloads_with_md5") |
|---|
| 131 | n/a | def test_download(self, server): |
|---|
| 132 | n/a | # Download is possible, and the md5 is checked if given |
|---|
| 133 | n/a | |
|---|
| 134 | n/a | url = server.full_address + self.srcpath |
|---|
| 135 | n/a | |
|---|
| 136 | n/a | # check that a md5 if given |
|---|
| 137 | n/a | dist = Dist(url=url, hashname="md5", |
|---|
| 138 | n/a | hashval="fe18804c5b722ff024cabdf514924fc4") |
|---|
| 139 | n/a | dist.download(self.mkdtemp()) |
|---|
| 140 | n/a | |
|---|
| 141 | n/a | # a wrong md5 fails |
|---|
| 142 | n/a | dist2 = Dist(url=url, hashname="md5", hashval="wrongmd5") |
|---|
| 143 | n/a | |
|---|
| 144 | n/a | self.assertRaises(HashDoesNotMatch, dist2.download, self.mkdtemp()) |
|---|
| 145 | n/a | |
|---|
| 146 | n/a | # we can omit the md5 hash |
|---|
| 147 | n/a | dist3 = Dist(url=url) |
|---|
| 148 | n/a | dist3.download(self.mkdtemp()) |
|---|
| 149 | n/a | |
|---|
| 150 | n/a | # and specify a temporary location |
|---|
| 151 | n/a | # for an already downloaded dist |
|---|
| 152 | n/a | path1 = self.mkdtemp() |
|---|
| 153 | n/a | dist3.download(path=path1) |
|---|
| 154 | n/a | # and for a new one |
|---|
| 155 | n/a | path2_base = self.mkdtemp() |
|---|
| 156 | n/a | dist4 = Dist(url=url) |
|---|
| 157 | n/a | path2 = dist4.download(path=path2_base) |
|---|
| 158 | n/a | self.assertIn(path2_base, path2) |
|---|
| 159 | n/a | |
|---|
| 160 | n/a | def test_hashname(self): |
|---|
| 161 | n/a | # Invalid hashnames raises an exception on assignation |
|---|
| 162 | n/a | Dist(hashname="md5", hashval="value") |
|---|
| 163 | n/a | |
|---|
| 164 | n/a | self.assertRaises(UnsupportedHashName, Dist, |
|---|
| 165 | n/a | hashname="invalid_hashname", |
|---|
| 166 | n/a | hashval="value") |
|---|
| 167 | n/a | |
|---|
| 168 | n/a | @unittest.skipIf(threading is None, 'needs threading') |
|---|
| 169 | n/a | @requires_zlib |
|---|
| 170 | n/a | @use_pypi_server('downloads_with_md5') |
|---|
| 171 | n/a | def test_unpack(self, server): |
|---|
| 172 | n/a | url = server.full_address + self.srcpath |
|---|
| 173 | n/a | dist1 = Dist(url=url) |
|---|
| 174 | n/a | |
|---|
| 175 | n/a | # unpack the distribution in a specfied folder |
|---|
| 176 | n/a | dist1_here = self.mkdtemp() |
|---|
| 177 | n/a | dist1_there = dist1.unpack(path=dist1_here) |
|---|
| 178 | n/a | |
|---|
| 179 | n/a | # assert we unpack to the path provided |
|---|
| 180 | n/a | self.assertEqual(dist1_here, dist1_there) |
|---|
| 181 | n/a | dist1_result = os.listdir(dist1_there) |
|---|
| 182 | n/a | self.assertIn('paf', dist1_result) |
|---|
| 183 | n/a | os.remove(os.path.join(dist1_there, 'paf')) |
|---|
| 184 | n/a | |
|---|
| 185 | n/a | # Test unpack works without a path argument |
|---|
| 186 | n/a | dist2 = Dist(url=url) |
|---|
| 187 | n/a | # doing an unpack |
|---|
| 188 | n/a | dist2_there = dist2.unpack() |
|---|
| 189 | n/a | self.addCleanup(shutil.rmtree, dist2_there) |
|---|
| 190 | n/a | dist2_result = os.listdir(dist2_there) |
|---|
| 191 | n/a | self.assertIn('paf', dist2_result) |
|---|
| 192 | n/a | os.remove(os.path.join(dist2_there, 'paf')) |
|---|
| 193 | n/a | |
|---|
| 194 | n/a | |
|---|
| 195 | n/a | class TestReleasesList(unittest.TestCase): |
|---|
| 196 | n/a | |
|---|
| 197 | n/a | def test_filter(self): |
|---|
| 198 | n/a | # Test we filter the distributions the right way, using version |
|---|
| 199 | n/a | # predicate match method |
|---|
| 200 | n/a | releases = ReleasesList('FooBar', ( |
|---|
| 201 | n/a | ReleaseInfo("FooBar", "1.1"), |
|---|
| 202 | n/a | ReleaseInfo("FooBar", "1.1.1"), |
|---|
| 203 | n/a | ReleaseInfo("FooBar", "1.2"), |
|---|
| 204 | n/a | ReleaseInfo("FooBar", "1.2.1"), |
|---|
| 205 | n/a | )) |
|---|
| 206 | n/a | filtered = releases.filter(VersionPredicate("FooBar (<1.2)")) |
|---|
| 207 | n/a | self.assertNotIn(releases[2], filtered) |
|---|
| 208 | n/a | self.assertNotIn(releases[3], filtered) |
|---|
| 209 | n/a | self.assertIn(releases[0], filtered) |
|---|
| 210 | n/a | self.assertIn(releases[1], filtered) |
|---|
| 211 | n/a | |
|---|
| 212 | n/a | def test_append(self): |
|---|
| 213 | n/a | # When adding a new item to the list, the behavior is to test if |
|---|
| 214 | n/a | # a release with the same name and version number already exists, |
|---|
| 215 | n/a | # and if so, to add a new distribution for it. If the distribution type |
|---|
| 216 | n/a | # is already defined too, add url informations to the existing DistInfo |
|---|
| 217 | n/a | # object. |
|---|
| 218 | n/a | |
|---|
| 219 | n/a | releases = ReleasesList("FooBar", [ |
|---|
| 220 | n/a | ReleaseInfo("FooBar", "1.1", url="external_url", |
|---|
| 221 | n/a | dist_type="sdist"), |
|---|
| 222 | n/a | ]) |
|---|
| 223 | n/a | self.assertEqual(1, len(releases)) |
|---|
| 224 | n/a | releases.add_release(release=ReleaseInfo("FooBar", "1.1", |
|---|
| 225 | n/a | url="internal_url", |
|---|
| 226 | n/a | is_external=False, |
|---|
| 227 | n/a | dist_type="sdist")) |
|---|
| 228 | n/a | self.assertEqual(1, len(releases)) |
|---|
| 229 | n/a | self.assertEqual(2, len(releases[0]['sdist'].urls)) |
|---|
| 230 | n/a | |
|---|
| 231 | n/a | releases.add_release(release=ReleaseInfo("FooBar", "1.1.1", |
|---|
| 232 | n/a | dist_type="sdist")) |
|---|
| 233 | n/a | self.assertEqual(2, len(releases)) |
|---|
| 234 | n/a | |
|---|
| 235 | n/a | # when adding a distribution whith a different type, a new distribution |
|---|
| 236 | n/a | # has to be added. |
|---|
| 237 | n/a | releases.add_release(release=ReleaseInfo("FooBar", "1.1.1", |
|---|
| 238 | n/a | dist_type="bdist")) |
|---|
| 239 | n/a | self.assertEqual(2, len(releases)) |
|---|
| 240 | n/a | self.assertEqual(2, len(releases[1].dists)) |
|---|
| 241 | n/a | |
|---|
| 242 | n/a | def test_prefer_final(self): |
|---|
| 243 | n/a | # Can order the distributions using prefer_final |
|---|
| 244 | n/a | fb10 = ReleaseInfo("FooBar", "1.0") # final distribution |
|---|
| 245 | n/a | fb11a = ReleaseInfo("FooBar", "1.1a1") # alpha |
|---|
| 246 | n/a | fb12a = ReleaseInfo("FooBar", "1.2a1") # alpha |
|---|
| 247 | n/a | fb12b = ReleaseInfo("FooBar", "1.2b1") # beta |
|---|
| 248 | n/a | dists = ReleasesList("FooBar", [fb10, fb11a, fb12a, fb12b]) |
|---|
| 249 | n/a | |
|---|
| 250 | n/a | dists.sort_releases(prefer_final=True) |
|---|
| 251 | n/a | self.assertEqual(fb10, dists[0]) |
|---|
| 252 | n/a | |
|---|
| 253 | n/a | dists.sort_releases(prefer_final=False) |
|---|
| 254 | n/a | self.assertEqual(fb12b, dists[0]) |
|---|
| 255 | n/a | |
|---|
| 256 | n/a | @unittest.skip('method not implemented yet') |
|---|
| 257 | n/a | def test_prefer_source(self): |
|---|
| 258 | n/a | # Ordering supports prefer_source |
|---|
| 259 | n/a | fb_source = Dist("FooBar", "1.0", type="source") |
|---|
| 260 | n/a | fb_binary = Dist("FooBar", "1.0", type="binary") |
|---|
| 261 | n/a | fb2_binary = Dist("FooBar", "2.0", type="binary") |
|---|
| 262 | n/a | dists = ReleasesList([fb_binary, fb_source]) |
|---|
| 263 | n/a | |
|---|
| 264 | n/a | dists.sort_distributions(prefer_source=True) |
|---|
| 265 | n/a | self.assertEqual(fb_source, dists[0]) |
|---|
| 266 | n/a | |
|---|
| 267 | n/a | dists.sort_distributions(prefer_source=False) |
|---|
| 268 | n/a | self.assertEqual(fb_binary, dists[0]) |
|---|
| 269 | n/a | |
|---|
| 270 | n/a | dists.append(fb2_binary) |
|---|
| 271 | n/a | dists.sort_distributions(prefer_source=True) |
|---|
| 272 | n/a | self.assertEqual(fb2_binary, dists[0]) |
|---|
| 273 | n/a | |
|---|
| 274 | n/a | def test_get_last(self): |
|---|
| 275 | n/a | dists = ReleasesList('Foo') |
|---|
| 276 | n/a | self.assertEqual(dists.get_last('Foo 1.0'), None) |
|---|
| 277 | n/a | |
|---|
| 278 | n/a | |
|---|
| 279 | n/a | def test_suite(): |
|---|
| 280 | n/a | suite = unittest.TestSuite() |
|---|
| 281 | n/a | suite.addTest(unittest.makeSuite(TestDistInfo)) |
|---|
| 282 | n/a | suite.addTest(unittest.makeSuite(TestReleaseInfo)) |
|---|
| 283 | n/a | suite.addTest(unittest.makeSuite(TestReleasesList)) |
|---|
| 284 | n/a | return suite |
|---|
| 285 | n/a | |
|---|
| 286 | n/a | if __name__ == '__main__': |
|---|
| 287 | n/a | unittest.main(defaultTest='test_suite') |
|---|