OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # -*- coding: utf-8 -*- |
| 3 # NOTE: the shebang and encoding lines are for ScriptHeaderTests do not remove |
| 4 |
| 5 import os |
| 6 import sys |
| 7 import tempfile |
| 8 import shutil |
| 9 from unittest import TestCase |
| 10 |
| 11 import setuptools._vendor.packaging.version |
| 12 import setuptools._vendor.packaging.specifiers |
| 13 packaging = setuptools._vendor.packaging |
| 14 |
| 15 import pkg_resources |
| 16 from pkg_resources import (parse_requirements, VersionConflict, parse_version, |
| 17 Distribution, EntryPoint, Requirement, safe_version, safe_name, |
| 18 WorkingSet) |
| 19 |
| 20 from setuptools.command.easy_install import (get_script_header, is_sh, |
| 21 nt_quote_arg) |
| 22 from setuptools.compat import StringIO, iteritems, PY3 |
| 23 from .py26compat import skipIf |
| 24 |
| 25 def safe_repr(obj, short=False): |
| 26 """ copied from Python2.7""" |
| 27 try: |
| 28 result = repr(obj) |
| 29 except Exception: |
| 30 result = object.__repr__(obj) |
| 31 if not short or len(result) < pkg_resources._MAX_LENGTH: |
| 32 return result |
| 33 return result[:pkg_resources._MAX_LENGTH] + ' [truncated]...' |
| 34 |
| 35 class Metadata(pkg_resources.EmptyProvider): |
| 36 """Mock object to return metadata as if from an on-disk distribution""" |
| 37 |
| 38 def __init__(self,*pairs): |
| 39 self.metadata = dict(pairs) |
| 40 |
| 41 def has_metadata(self,name): |
| 42 return name in self.metadata |
| 43 |
| 44 def get_metadata(self,name): |
| 45 return self.metadata[name] |
| 46 |
| 47 def get_metadata_lines(self,name): |
| 48 return pkg_resources.yield_lines(self.get_metadata(name)) |
| 49 |
| 50 dist_from_fn = pkg_resources.Distribution.from_filename |
| 51 |
| 52 class DistroTests(TestCase): |
| 53 |
| 54 def testCollection(self): |
| 55 # empty path should produce no distributions |
| 56 ad = pkg_resources.Environment([], platform=None, python=None) |
| 57 self.assertEqual(list(ad), []) |
| 58 self.assertEqual(ad['FooPkg'],[]) |
| 59 ad.add(dist_from_fn("FooPkg-1.3_1.egg")) |
| 60 ad.add(dist_from_fn("FooPkg-1.4-py2.4-win32.egg")) |
| 61 ad.add(dist_from_fn("FooPkg-1.2-py2.4.egg")) |
| 62 |
| 63 # Name is in there now |
| 64 self.assertTrue(ad['FooPkg']) |
| 65 # But only 1 package |
| 66 self.assertEqual(list(ad), ['foopkg']) |
| 67 |
| 68 # Distributions sort by version |
| 69 self.assertEqual( |
| 70 [dist.version for dist in ad['FooPkg']], ['1.4','1.3-1','1.2'] |
| 71 ) |
| 72 # Removing a distribution leaves sequence alone |
| 73 ad.remove(ad['FooPkg'][1]) |
| 74 self.assertEqual( |
| 75 [dist.version for dist in ad['FooPkg']], ['1.4','1.2'] |
| 76 ) |
| 77 # And inserting adds them in order |
| 78 ad.add(dist_from_fn("FooPkg-1.9.egg")) |
| 79 self.assertEqual( |
| 80 [dist.version for dist in ad['FooPkg']], ['1.9','1.4','1.2'] |
| 81 ) |
| 82 |
| 83 ws = WorkingSet([]) |
| 84 foo12 = dist_from_fn("FooPkg-1.2-py2.4.egg") |
| 85 foo14 = dist_from_fn("FooPkg-1.4-py2.4-win32.egg") |
| 86 req, = parse_requirements("FooPkg>=1.3") |
| 87 |
| 88 # Nominal case: no distros on path, should yield all applicable |
| 89 self.assertEqual(ad.best_match(req,ws).version, '1.9') |
| 90 # If a matching distro is already installed, should return only that |
| 91 ws.add(foo14) |
| 92 self.assertEqual(ad.best_match(req,ws).version, '1.4') |
| 93 |
| 94 # If the first matching distro is unsuitable, it's a version conflict |
| 95 ws = WorkingSet([]) |
| 96 ws.add(foo12) |
| 97 ws.add(foo14) |
| 98 self.assertRaises(VersionConflict, ad.best_match, req, ws) |
| 99 |
| 100 # If more than one match on the path, the first one takes precedence |
| 101 ws = WorkingSet([]) |
| 102 ws.add(foo14) |
| 103 ws.add(foo12) |
| 104 ws.add(foo14) |
| 105 self.assertEqual(ad.best_match(req,ws).version, '1.4') |
| 106 |
| 107 def checkFooPkg(self,d): |
| 108 self.assertEqual(d.project_name, "FooPkg") |
| 109 self.assertEqual(d.key, "foopkg") |
| 110 self.assertEqual(d.version, "1.3.post1") |
| 111 self.assertEqual(d.py_version, "2.4") |
| 112 self.assertEqual(d.platform, "win32") |
| 113 self.assertEqual(d.parsed_version, parse_version("1.3-1")) |
| 114 |
| 115 def testDistroBasics(self): |
| 116 d = Distribution( |
| 117 "/some/path", |
| 118 project_name="FooPkg",version="1.3-1",py_version="2.4",platform="win
32" |
| 119 ) |
| 120 self.checkFooPkg(d) |
| 121 |
| 122 d = Distribution("/some/path") |
| 123 self.assertEqual(d.py_version, sys.version[:3]) |
| 124 self.assertEqual(d.platform, None) |
| 125 |
| 126 def testDistroParse(self): |
| 127 d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg") |
| 128 self.checkFooPkg(d) |
| 129 d = dist_from_fn("FooPkg-1.3.post1-py2.4-win32.egg-info") |
| 130 self.checkFooPkg(d) |
| 131 |
| 132 def testDistroMetadata(self): |
| 133 d = Distribution( |
| 134 "/some/path", project_name="FooPkg", py_version="2.4", platform="win
32", |
| 135 metadata = Metadata( |
| 136 ('PKG-INFO',"Metadata-Version: 1.0\nVersion: 1.3-1\n") |
| 137 ) |
| 138 ) |
| 139 self.checkFooPkg(d) |
| 140 |
| 141 def distRequires(self, txt): |
| 142 return Distribution("/foo", metadata=Metadata(('depends.txt', txt))) |
| 143 |
| 144 def checkRequires(self, dist, txt, extras=()): |
| 145 self.assertEqual( |
| 146 list(dist.requires(extras)), |
| 147 list(parse_requirements(txt)) |
| 148 ) |
| 149 |
| 150 def testDistroDependsSimple(self): |
| 151 for v in "Twisted>=1.5", "Twisted>=1.5\nZConfig>=2.0": |
| 152 self.checkRequires(self.distRequires(v), v) |
| 153 |
| 154 def testResolve(self): |
| 155 ad = pkg_resources.Environment([]) |
| 156 ws = WorkingSet([]) |
| 157 # Resolving no requirements -> nothing to install |
| 158 self.assertEqual(list(ws.resolve([],ad)), []) |
| 159 # Request something not in the collection -> DistributionNotFound |
| 160 self.assertRaises( |
| 161 pkg_resources.DistributionNotFound, ws.resolve, parse_requirements("
Foo"), ad |
| 162 ) |
| 163 Foo = Distribution.from_filename( |
| 164 "/foo_dir/Foo-1.2.egg", |
| 165 metadata=Metadata(('depends.txt', "[bar]\nBaz>=2.0")) |
| 166 ) |
| 167 ad.add(Foo) |
| 168 ad.add(Distribution.from_filename("Foo-0.9.egg")) |
| 169 |
| 170 # Request thing(s) that are available -> list to activate |
| 171 for i in range(3): |
| 172 targets = list(ws.resolve(parse_requirements("Foo"), ad)) |
| 173 self.assertEqual(targets, [Foo]) |
| 174 list(map(ws.add,targets)) |
| 175 self.assertRaises(VersionConflict, ws.resolve, |
| 176 parse_requirements("Foo==0.9"), ad) |
| 177 ws = WorkingSet([]) # reset |
| 178 |
| 179 # Request an extra that causes an unresolved dependency for "Baz" |
| 180 self.assertRaises( |
| 181 pkg_resources.DistributionNotFound, ws.resolve,parse_requirements("F
oo[bar]"), ad |
| 182 ) |
| 183 Baz = Distribution.from_filename( |
| 184 "/foo_dir/Baz-2.1.egg", metadata=Metadata(('depends.txt', "Foo")) |
| 185 ) |
| 186 ad.add(Baz) |
| 187 |
| 188 # Activation list now includes resolved dependency |
| 189 self.assertEqual( |
| 190 list(ws.resolve(parse_requirements("Foo[bar]"), ad)), [Foo,Baz] |
| 191 ) |
| 192 # Requests for conflicting versions produce VersionConflict |
| 193 self.assertRaises(VersionConflict, |
| 194 ws.resolve, parse_requirements("Foo==1.2\nFoo!=1.2"), ad) |
| 195 |
| 196 def testDistroDependsOptions(self): |
| 197 d = self.distRequires(""" |
| 198 Twisted>=1.5 |
| 199 [docgen] |
| 200 ZConfig>=2.0 |
| 201 docutils>=0.3 |
| 202 [fastcgi] |
| 203 fcgiapp>=0.1""") |
| 204 self.checkRequires(d,"Twisted>=1.5") |
| 205 self.checkRequires( |
| 206 d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3".split(), ["docgen"] |
| 207 ) |
| 208 self.checkRequires( |
| 209 d,"Twisted>=1.5 fcgiapp>=0.1".split(), ["fastcgi"] |
| 210 ) |
| 211 self.checkRequires( |
| 212 d,"Twisted>=1.5 ZConfig>=2.0 docutils>=0.3 fcgiapp>=0.1".split(), |
| 213 ["docgen","fastcgi"] |
| 214 ) |
| 215 self.checkRequires( |
| 216 d,"Twisted>=1.5 fcgiapp>=0.1 ZConfig>=2.0 docutils>=0.3".split(), |
| 217 ["fastcgi", "docgen"] |
| 218 ) |
| 219 self.assertRaises(pkg_resources.UnknownExtra, d.requires, ["foo"]) |
| 220 |
| 221 |
| 222 class EntryPointTests(TestCase): |
| 223 |
| 224 def assertfields(self, ep): |
| 225 self.assertEqual(ep.name,"foo") |
| 226 self.assertEqual(ep.module_name,"setuptools.tests.test_resources") |
| 227 self.assertEqual(ep.attrs, ("EntryPointTests",)) |
| 228 self.assertEqual(ep.extras, ("x",)) |
| 229 self.assertTrue(ep.load() is EntryPointTests) |
| 230 self.assertEqual( |
| 231 str(ep), |
| 232 "foo = setuptools.tests.test_resources:EntryPointTests [x]" |
| 233 ) |
| 234 |
| 235 def setUp(self): |
| 236 self.dist = Distribution.from_filename( |
| 237 "FooPkg-1.2-py2.4.egg", metadata=Metadata(('requires.txt','[x]'))) |
| 238 |
| 239 def testBasics(self): |
| 240 ep = EntryPoint( |
| 241 "foo", "setuptools.tests.test_resources", ["EntryPointTests"], |
| 242 ["x"], self.dist |
| 243 ) |
| 244 self.assertfields(ep) |
| 245 |
| 246 def testParse(self): |
| 247 s = "foo = setuptools.tests.test_resources:EntryPointTests [x]" |
| 248 ep = EntryPoint.parse(s, self.dist) |
| 249 self.assertfields(ep) |
| 250 |
| 251 ep = EntryPoint.parse("bar baz= spammity[PING]") |
| 252 self.assertEqual(ep.name,"bar baz") |
| 253 self.assertEqual(ep.module_name,"spammity") |
| 254 self.assertEqual(ep.attrs, ()) |
| 255 self.assertEqual(ep.extras, ("ping",)) |
| 256 |
| 257 ep = EntryPoint.parse(" fizzly = wocka:foo") |
| 258 self.assertEqual(ep.name,"fizzly") |
| 259 self.assertEqual(ep.module_name,"wocka") |
| 260 self.assertEqual(ep.attrs, ("foo",)) |
| 261 self.assertEqual(ep.extras, ()) |
| 262 |
| 263 def testRejects(self): |
| 264 for ep in [ |
| 265 "foo", "x=1=2", "x=a:b:c", "q=x/na", "fez=pish:tush-z", "x=f[a]>2", |
| 266 ]: |
| 267 try: EntryPoint.parse(ep) |
| 268 except ValueError: pass |
| 269 else: raise AssertionError("Should've been bad", ep) |
| 270 |
| 271 def checkSubMap(self, m): |
| 272 self.assertEqual(len(m), len(self.submap_expect)) |
| 273 for key, ep in iteritems(self.submap_expect): |
| 274 self.assertEqual(repr(m.get(key)), repr(ep)) |
| 275 |
| 276 submap_expect = dict( |
| 277 feature1=EntryPoint('feature1', 'somemodule', ['somefunction']), |
| 278 feature2=EntryPoint('feature2', 'another.module', ['SomeClass'], ['extra
1','extra2']), |
| 279 feature3=EntryPoint('feature3', 'this.module', extras=['something']) |
| 280 ) |
| 281 submap_str = """ |
| 282 # define features for blah blah |
| 283 feature1 = somemodule:somefunction |
| 284 feature2 = another.module:SomeClass [extra1,extra2] |
| 285 feature3 = this.module [something] |
| 286 """ |
| 287 |
| 288 def testParseList(self): |
| 289 self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str)) |
| 290 self.assertRaises(ValueError, EntryPoint.parse_group, "x a", "foo=bar") |
| 291 self.assertRaises(ValueError, EntryPoint.parse_group, "x", |
| 292 ["foo=baz", "foo=bar"]) |
| 293 |
| 294 def testParseMap(self): |
| 295 m = EntryPoint.parse_map({'xyz':self.submap_str}) |
| 296 self.checkSubMap(m['xyz']) |
| 297 self.assertEqual(list(m.keys()),['xyz']) |
| 298 m = EntryPoint.parse_map("[xyz]\n"+self.submap_str) |
| 299 self.checkSubMap(m['xyz']) |
| 300 self.assertEqual(list(m.keys()),['xyz']) |
| 301 self.assertRaises(ValueError, EntryPoint.parse_map, ["[xyz]", "[xyz]"]) |
| 302 self.assertRaises(ValueError, EntryPoint.parse_map, self.submap_str) |
| 303 |
| 304 class RequirementsTests(TestCase): |
| 305 |
| 306 def testBasics(self): |
| 307 r = Requirement.parse("Twisted>=1.2") |
| 308 self.assertEqual(str(r),"Twisted>=1.2") |
| 309 self.assertEqual(repr(r),"Requirement.parse('Twisted>=1.2')") |
| 310 self.assertEqual(r, Requirement("Twisted", [('>=','1.2')], ())) |
| 311 self.assertEqual(r, Requirement("twisTed", [('>=','1.2')], ())) |
| 312 self.assertNotEqual(r, Requirement("Twisted", [('>=','2.0')], ())) |
| 313 self.assertNotEqual(r, Requirement("Zope", [('>=','1.2')], ())) |
| 314 self.assertNotEqual(r, Requirement("Zope", [('>=','3.0')], ())) |
| 315 self.assertNotEqual(r, Requirement.parse("Twisted[extras]>=1.2")) |
| 316 |
| 317 def testOrdering(self): |
| 318 r1 = Requirement("Twisted", [('==','1.2c1'),('>=','1.2')], ()) |
| 319 r2 = Requirement("Twisted", [('>=','1.2'),('==','1.2c1')], ()) |
| 320 self.assertEqual(r1,r2) |
| 321 self.assertEqual(str(r1),str(r2)) |
| 322 self.assertEqual(str(r2),"Twisted==1.2c1,>=1.2") |
| 323 |
| 324 def testBasicContains(self): |
| 325 r = Requirement("Twisted", [('>=','1.2')], ()) |
| 326 foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") |
| 327 twist11 = Distribution.from_filename("Twisted-1.1.egg") |
| 328 twist12 = Distribution.from_filename("Twisted-1.2.egg") |
| 329 self.assertTrue(parse_version('1.2') in r) |
| 330 self.assertTrue(parse_version('1.1') not in r) |
| 331 self.assertTrue('1.2' in r) |
| 332 self.assertTrue('1.1' not in r) |
| 333 self.assertTrue(foo_dist not in r) |
| 334 self.assertTrue(twist11 not in r) |
| 335 self.assertTrue(twist12 in r) |
| 336 |
| 337 def testOptionsAndHashing(self): |
| 338 r1 = Requirement.parse("Twisted[foo,bar]>=1.2") |
| 339 r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") |
| 340 self.assertEqual(r1,r2) |
| 341 self.assertEqual(r1.extras, ("foo","bar")) |
| 342 self.assertEqual(r2.extras, ("bar","foo")) # extras are normalized |
| 343 self.assertEqual(hash(r1), hash(r2)) |
| 344 self.assertEqual( |
| 345 hash(r1), hash(("twisted", packaging.specifiers.SpecifierSet(">=1.2"
), |
| 346 frozenset(["foo","bar"]))) |
| 347 ) |
| 348 |
| 349 def testVersionEquality(self): |
| 350 r1 = Requirement.parse("foo==0.3a2") |
| 351 r2 = Requirement.parse("foo!=0.3a4") |
| 352 d = Distribution.from_filename |
| 353 |
| 354 self.assertTrue(d("foo-0.3a4.egg") not in r1) |
| 355 self.assertTrue(d("foo-0.3a1.egg") not in r1) |
| 356 self.assertTrue(d("foo-0.3a4.egg") not in r2) |
| 357 |
| 358 self.assertTrue(d("foo-0.3a2.egg") in r1) |
| 359 self.assertTrue(d("foo-0.3a2.egg") in r2) |
| 360 self.assertTrue(d("foo-0.3a3.egg") in r2) |
| 361 self.assertTrue(d("foo-0.3a5.egg") in r2) |
| 362 |
| 363 def testSetuptoolsProjectName(self): |
| 364 """ |
| 365 The setuptools project should implement the setuptools package. |
| 366 """ |
| 367 |
| 368 self.assertEqual( |
| 369 Requirement.parse('setuptools').project_name, 'setuptools') |
| 370 # setuptools 0.7 and higher means setuptools. |
| 371 self.assertEqual( |
| 372 Requirement.parse('setuptools == 0.7').project_name, 'setuptools') |
| 373 self.assertEqual( |
| 374 Requirement.parse('setuptools == 0.7a1').project_name, 'setuptools') |
| 375 self.assertEqual( |
| 376 Requirement.parse('setuptools >= 0.7').project_name, 'setuptools') |
| 377 |
| 378 |
| 379 class ParseTests(TestCase): |
| 380 |
| 381 def testEmptyParse(self): |
| 382 self.assertEqual(list(parse_requirements('')), []) |
| 383 |
| 384 def testYielding(self): |
| 385 for inp,out in [ |
| 386 ([], []), ('x',['x']), ([[]],[]), (' x\n y', ['x','y']), |
| 387 (['x\n\n','y'], ['x','y']), |
| 388 ]: |
| 389 self.assertEqual(list(pkg_resources.yield_lines(inp)),out) |
| 390 |
| 391 def testSplitting(self): |
| 392 sample = """ |
| 393 x |
| 394 [Y] |
| 395 z |
| 396 |
| 397 a |
| 398 [b ] |
| 399 # foo |
| 400 c |
| 401 [ d] |
| 402 [q] |
| 403 v |
| 404 """ |
| 405 self.assertEqual(list(pkg_resources.split_sections(sample)), |
| 406 [(None,["x"]), ("Y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] |
| 407 ) |
| 408 self.assertRaises(ValueError,list,pkg_resources.split_sections("[foo")) |
| 409 |
| 410 def testSafeName(self): |
| 411 self.assertEqual(safe_name("adns-python"), "adns-python") |
| 412 self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") |
| 413 self.assertEqual(safe_name("WSGI Utils"), "WSGI-Utils") |
| 414 self.assertEqual(safe_name("Money$$$Maker"), "Money-Maker") |
| 415 self.assertNotEqual(safe_name("peak.web"), "peak-web") |
| 416 |
| 417 def testSafeVersion(self): |
| 418 self.assertEqual(safe_version("1.2-1"), "1.2.post1") |
| 419 self.assertEqual(safe_version("1.2 alpha"), "1.2.alpha") |
| 420 self.assertEqual(safe_version("2.3.4 20050521"), "2.3.4.20050521") |
| 421 self.assertEqual(safe_version("Money$$$Maker"), "Money-Maker") |
| 422 self.assertEqual(safe_version("peak.web"), "peak.web") |
| 423 |
| 424 def testSimpleRequirements(self): |
| 425 self.assertEqual( |
| 426 list(parse_requirements('Twis-Ted>=1.2-1')), |
| 427 [Requirement('Twis-Ted',[('>=','1.2-1')], ())] |
| 428 ) |
| 429 self.assertEqual( |
| 430 list(parse_requirements('Twisted >=1.2, \ # more\n<2.0')), |
| 431 [Requirement('Twisted',[('>=','1.2'),('<','2.0')], ())] |
| 432 ) |
| 433 self.assertEqual( |
| 434 Requirement.parse("FooBar==1.99a3"), |
| 435 Requirement("FooBar", [('==','1.99a3')], ()) |
| 436 ) |
| 437 self.assertRaises(ValueError,Requirement.parse,">=2.3") |
| 438 self.assertRaises(ValueError,Requirement.parse,"x\\") |
| 439 self.assertRaises(ValueError,Requirement.parse,"x==2 q") |
| 440 self.assertRaises(ValueError,Requirement.parse,"X==1\nY==2") |
| 441 self.assertRaises(ValueError,Requirement.parse,"#") |
| 442 |
| 443 def testVersionEquality(self): |
| 444 def c(s1,s2): |
| 445 p1, p2 = parse_version(s1),parse_version(s2) |
| 446 self.assertEqual(p1,p2, (s1,s2,p1,p2)) |
| 447 |
| 448 c('1.2-rc1', '1.2rc1') |
| 449 c('0.4', '0.4.0') |
| 450 c('0.4.0.0', '0.4.0') |
| 451 c('0.4.0-0', '0.4-0') |
| 452 c('0post1', '0.0post1') |
| 453 c('0pre1', '0.0c1') |
| 454 c('0.0.0preview1', '0c1') |
| 455 c('0.0c1', '0-rc1') |
| 456 c('1.2a1', '1.2.a.1') |
| 457 c('1.2.a', '1.2a') |
| 458 |
| 459 def testVersionOrdering(self): |
| 460 def c(s1,s2): |
| 461 p1, p2 = parse_version(s1),parse_version(s2) |
| 462 self.assertTrue(p1<p2, (s1,s2,p1,p2)) |
| 463 |
| 464 c('2.1','2.1.1') |
| 465 c('2a1','2b0') |
| 466 c('2a1','2.1') |
| 467 c('2.3a1', '2.3') |
| 468 c('2.1-1', '2.1-2') |
| 469 c('2.1-1', '2.1.1') |
| 470 c('2.1', '2.1post4') |
| 471 c('2.1a0-20040501', '2.1') |
| 472 c('1.1', '02.1') |
| 473 c('3.2', '3.2.post0') |
| 474 c('3.2post1', '3.2post2') |
| 475 c('0.4', '4.0') |
| 476 c('0.0.4', '0.4.0') |
| 477 c('0post1', '0.4post1') |
| 478 c('2.1.0-rc1','2.1.0') |
| 479 c('2.1dev','2.1a0') |
| 480 |
| 481 torture =""" |
| 482 0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1 |
| 483 0.79.9999+0.80.0pre2-3 0.79.9999+0.80.0pre2-2 |
| 484 0.77.2-1 0.77.1-1 0.77.0-1 |
| 485 """.split() |
| 486 |
| 487 for p,v1 in enumerate(torture): |
| 488 for v2 in torture[p+1:]: |
| 489 c(v2,v1) |
| 490 |
| 491 def testVersionBuildout(self): |
| 492 """ |
| 493 Buildout has a function in it's bootstrap.py that inspected the return |
| 494 value of parse_version. The new parse_version returns a Version class |
| 495 which needs to support this behavior, at least for now. |
| 496 """ |
| 497 def buildout(parsed_version): |
| 498 _final_parts = '*final-', '*final' |
| 499 |
| 500 def _final_version(parsed_version): |
| 501 for part in parsed_version: |
| 502 if (part[:1] == '*') and (part not in _final_parts): |
| 503 return False |
| 504 return True |
| 505 return _final_version(parsed_version) |
| 506 |
| 507 self.assertTrue(buildout(parse_version("1.0"))) |
| 508 self.assertFalse(buildout(parse_version("1.0a1"))) |
| 509 |
| 510 def testVersionIndexable(self): |
| 511 """ |
| 512 Some projects were doing things like parse_version("v")[0], so we'll |
| 513 support indexing the same as we support iterating. |
| 514 """ |
| 515 self.assertEqual(parse_version("1.0")[0], "00000001") |
| 516 |
| 517 def testVersionTupleSort(self): |
| 518 """ |
| 519 Some projects expected to be able to sort tuples against the return |
| 520 value of parse_version. So again we'll add a warning enabled shim to |
| 521 make this possible. |
| 522 """ |
| 523 self.assertTrue(parse_version("1.0") < tuple(parse_version("2.0"))) |
| 524 self.assertTrue(parse_version("1.0") <= tuple(parse_version("2.0"))) |
| 525 self.assertTrue(parse_version("1.0") == tuple(parse_version("1.0"))) |
| 526 self.assertTrue(parse_version("3.0") > tuple(parse_version("2.0"))) |
| 527 self.assertTrue(parse_version("3.0") >= tuple(parse_version("2.0"))) |
| 528 self.assertTrue(parse_version("3.0") != tuple(parse_version("2.0"))) |
| 529 self.assertFalse(parse_version("3.0") != tuple(parse_version("3.0"))) |
| 530 |
| 531 def testVersionHashable(self): |
| 532 """ |
| 533 Ensure that our versions stay hashable even though we've subclassed |
| 534 them and added some shim code to them. |
| 535 """ |
| 536 self.assertEqual( |
| 537 hash(parse_version("1.0")), |
| 538 hash(parse_version("1.0")), |
| 539 ) |
| 540 |
| 541 |
| 542 class ScriptHeaderTests(TestCase): |
| 543 non_ascii_exe = '/Users/José/bin/python' |
| 544 exe_with_spaces = r'C:\Program Files\Python33\python.exe' |
| 545 |
| 546 def test_get_script_header(self): |
| 547 if not sys.platform.startswith('java') or not is_sh(sys.executable): |
| 548 # This test is for non-Jython platforms |
| 549 expected = '#!%s\n' % nt_quote_arg(os.path.normpath(sys.executable)) |
| 550 self.assertEqual(get_script_header('#!/usr/local/bin/python'), |
| 551 expected) |
| 552 expected = '#!%s -x\n' % nt_quote_arg(os.path.normpath(sys.executab
le)) |
| 553 self.assertEqual(get_script_header('#!/usr/bin/python -x'), |
| 554 expected) |
| 555 self.assertEqual(get_script_header('#!/usr/bin/python', |
| 556 executable=self.non_ascii_exe), |
| 557 '#!%s -x\n' % self.non_ascii_exe) |
| 558 candidate = get_script_header('#!/usr/bin/python', |
| 559 executable=self.exe_with_spaces) |
| 560 self.assertEqual(candidate, '#!"%s"\n' % self.exe_with_spaces) |
| 561 |
| 562 def test_get_script_header_jython_workaround(self): |
| 563 # This test doesn't work with Python 3 in some locales |
| 564 if PY3 and os.environ.get("LC_CTYPE") in (None, "C", "POSIX"): |
| 565 return |
| 566 |
| 567 class java: |
| 568 class lang: |
| 569 class System: |
| 570 @staticmethod |
| 571 def getProperty(property): |
| 572 return "" |
| 573 sys.modules["java"] = java |
| 574 |
| 575 platform = sys.platform |
| 576 sys.platform = 'java1.5.0_13' |
| 577 stdout, stderr = sys.stdout, sys.stderr |
| 578 try: |
| 579 # A mock sys.executable that uses a shebang line (this file) |
| 580 exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py') |
| 581 self.assertEqual( |
| 582 get_script_header('#!/usr/local/bin/python', executable=exe), |
| 583 '#!/usr/bin/env %s\n' % exe) |
| 584 |
| 585 # Ensure we generate what is basically a broken shebang line |
| 586 # when there's options, with a warning emitted |
| 587 sys.stdout = sys.stderr = StringIO() |
| 588 self.assertEqual(get_script_header('#!/usr/bin/python -x', |
| 589 executable=exe), |
| 590 '#!%s -x\n' % exe) |
| 591 self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalu
e()) |
| 592 sys.stdout = sys.stderr = StringIO() |
| 593 self.assertEqual(get_script_header('#!/usr/bin/python', |
| 594 executable=self.non_ascii_exe), |
| 595 '#!%s -x\n' % self.non_ascii_exe) |
| 596 self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalu
e()) |
| 597 finally: |
| 598 del sys.modules["java"] |
| 599 sys.platform = platform |
| 600 sys.stdout, sys.stderr = stdout, stderr |
| 601 |
| 602 |
| 603 class NamespaceTests(TestCase): |
| 604 |
| 605 def setUp(self): |
| 606 self._ns_pkgs = pkg_resources._namespace_packages.copy() |
| 607 self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") |
| 608 os.makedirs(os.path.join(self._tmpdir, "site-pkgs")) |
| 609 self._prev_sys_path = sys.path[:] |
| 610 sys.path.append(os.path.join(self._tmpdir, "site-pkgs")) |
| 611 |
| 612 def tearDown(self): |
| 613 shutil.rmtree(self._tmpdir) |
| 614 pkg_resources._namespace_packages = self._ns_pkgs.copy() |
| 615 sys.path = self._prev_sys_path[:] |
| 616 |
| 617 msg = "Test fails when /tmp is a symlink. See #231" |
| 618 @skipIf(os.path.islink(tempfile.gettempdir()), msg) |
| 619 def test_two_levels_deep(self): |
| 620 """ |
| 621 Test nested namespace packages |
| 622 Create namespace packages in the following tree : |
| 623 site-packages-1/pkg1/pkg2 |
| 624 site-packages-2/pkg1/pkg2 |
| 625 Check both are in the _namespace_packages dict and that their __path__ |
| 626 is correct |
| 627 """ |
| 628 sys.path.append(os.path.join(self._tmpdir, "site-pkgs2")) |
| 629 os.makedirs(os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2")) |
| 630 os.makedirs(os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")) |
| 631 ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" |
| 632 for site in ["site-pkgs", "site-pkgs2"]: |
| 633 pkg1_init = open(os.path.join(self._tmpdir, site, |
| 634 "pkg1", "__init__.py"), "w") |
| 635 pkg1_init.write(ns_str) |
| 636 pkg1_init.close() |
| 637 pkg2_init = open(os.path.join(self._tmpdir, site, |
| 638 "pkg1", "pkg2", "__init__.py"), "w") |
| 639 pkg2_init.write(ns_str) |
| 640 pkg2_init.close() |
| 641 import pkg1 |
| 642 assert "pkg1" in pkg_resources._namespace_packages |
| 643 try: |
| 644 import pkg1.pkg2 |
| 645 except ImportError: |
| 646 self.fail("Setuptools tried to import the parent namespace package") |
| 647 # check the _namespace_packages dict |
| 648 assert "pkg1.pkg2" in pkg_resources._namespace_packages |
| 649 assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] |
| 650 # check the __path__ attribute contains both paths |
| 651 expected = [ |
| 652 os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"), |
| 653 os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2"), |
| 654 ] |
| 655 assert pkg1.pkg2.__path__ == expected |
OLD | NEW |