1import sys 2import os 3import marshal 4import importlib 5import importlib.util 6import struct 7import time 8import unittest 9 10from test import support 11 12from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED 13 14import zipimport 15import linecache 16import doctest 17import inspect 18import io 19from traceback import extract_tb, extract_stack, print_tb 20try: 21 import zlib 22except ImportError: 23 zlib = None 24 25test_src = """\ 26def get_name(): 27 return __name__ 28def get_file(): 29 return __file__ 30""" 31test_co = compile(test_src, "<???>", "exec") 32raise_src = 'def do_raise(): raise TypeError\n' 33 34def make_pyc(co, mtime, size): 35 data = marshal.dumps(co) 36 if type(mtime) is type(0.0): 37 # Mac mtimes need a bit of special casing 38 if mtime < 0x7fffffff: 39 mtime = int(mtime) 40 else: 41 mtime = int(-0x100000000 + int(mtime)) 42 pyc = (importlib.util.MAGIC_NUMBER + 43 struct.pack("<iii", 0, int(mtime), size & 0xFFFFFFFF) + data) 44 return pyc 45 46def module_path_to_dotted_name(path): 47 return path.replace(os.sep, '.') 48 49NOW = time.time() 50test_pyc = make_pyc(test_co, NOW, len(test_src)) 51 52 53TESTMOD = "ziptestmodule" 54TESTPACK = "ziptestpackage" 55TESTPACK2 = "ziptestpackage2" 56TEMP_DIR = os.path.abspath("junk95142") 57TEMP_ZIP = os.path.abspath("junk95142.zip") 58 59pyc_file = importlib.util.cache_from_source(TESTMOD + '.py') 60pyc_ext = '.pyc' 61 62 63class ImportHooksBaseTestCase(unittest.TestCase): 64 65 def setUp(self): 66 self.path = sys.path[:] 67 self.meta_path = sys.meta_path[:] 68 self.path_hooks = sys.path_hooks[:] 69 sys.path_importer_cache.clear() 70 self.modules_before = support.modules_setup() 71 72 def tearDown(self): 73 sys.path[:] = self.path 74 sys.meta_path[:] = self.meta_path 75 sys.path_hooks[:] = self.path_hooks 76 sys.path_importer_cache.clear() 77 support.modules_cleanup(*self.modules_before) 78 79 80class UncompressedZipImportTestCase(ImportHooksBaseTestCase): 81 82 compression = ZIP_STORED 83 84 def setUp(self): 85 # We're reusing the zip archive path, so we must clear the 86 # cached directory info and linecache. 87 linecache.clearcache() 88 zipimport._zip_directory_cache.clear() 89 ImportHooksBaseTestCase.setUp(self) 90 91 def makeTree(self, files, dirName=TEMP_DIR): 92 # Create a filesystem based set of modules/packages 93 # defined by files under the directory dirName. 94 self.addCleanup(support.rmtree, dirName) 95 96 for name, (mtime, data) in files.items(): 97 path = os.path.join(dirName, name) 98 if path[-1] == os.sep: 99 if not os.path.isdir(path): 100 os.makedirs(path) 101 else: 102 dname = os.path.dirname(path) 103 if not os.path.isdir(dname): 104 os.makedirs(dname) 105 with open(path, 'wb') as fp: 106 fp.write(data) 107 108 def makeZip(self, files, zipName=TEMP_ZIP, **kw): 109 # Create a zip archive based set of modules/packages 110 # defined by files in the zip file zipName. If the 111 # key 'stuff' exists in kw it is prepended to the archive. 112 self.addCleanup(support.unlink, zipName) 113 114 with ZipFile(zipName, "w") as z: 115 for name, (mtime, data) in files.items(): 116 zinfo = ZipInfo(name, time.localtime(mtime)) 117 zinfo.compress_type = self.compression 118 z.writestr(zinfo, data) 119 120 stuff = kw.get("stuff", None) 121 if stuff is not None: 122 # Prepend 'stuff' to the start of the zipfile 123 with open(zipName, "rb") as f: 124 data = f.read() 125 with open(zipName, "wb") as f: 126 f.write(stuff) 127 f.write(data) 128 129 def doTest(self, expected_ext, files, *modules, **kw): 130 self.makeZip(files, **kw) 131 132 sys.path.insert(0, TEMP_ZIP) 133 134 mod = importlib.import_module(".".join(modules)) 135 136 call = kw.get('call') 137 if call is not None: 138 call(mod) 139 140 if expected_ext: 141 file = mod.get_file() 142 self.assertEqual(file, os.path.join(TEMP_ZIP, 143 *modules) + expected_ext) 144 145 def testAFakeZlib(self): 146 # 147 # This could cause a stack overflow before: importing zlib.py 148 # from a compressed archive would cause zlib to be imported 149 # which would find zlib.py in the archive, which would... etc. 150 # 151 # This test *must* be executed first: it must be the first one 152 # to trigger zipimport to import zlib (zipimport caches the 153 # zlib.decompress function object, after which the problem being 154 # tested here wouldn't be a problem anymore... 155 # (Hence the 'A' in the test method name: to make it the first 156 # item in a list sorted by name, like unittest.makeSuite() does.) 157 # 158 # This test fails on platforms on which the zlib module is 159 # statically linked, but the problem it tests for can't 160 # occur in that case (builtin modules are always found first), 161 # so we'll simply skip it then. Bug #765456. 162 # 163 if "zlib" in sys.builtin_module_names: 164 self.skipTest('zlib is a builtin module') 165 if "zlib" in sys.modules: 166 del sys.modules["zlib"] 167 files = {"zlib.py": (NOW, test_src)} 168 try: 169 self.doTest(".py", files, "zlib") 170 except ImportError: 171 if self.compression != ZIP_DEFLATED: 172 self.fail("expected test to not raise ImportError") 173 else: 174 if self.compression != ZIP_STORED: 175 self.fail("expected test to raise ImportError") 176 177 def testPy(self): 178 files = {TESTMOD + ".py": (NOW, test_src)} 179 self.doTest(".py", files, TESTMOD) 180 181 def testPyc(self): 182 files = {TESTMOD + pyc_ext: (NOW, test_pyc)} 183 self.doTest(pyc_ext, files, TESTMOD) 184 185 def testBoth(self): 186 files = {TESTMOD + ".py": (NOW, test_src), 187 TESTMOD + pyc_ext: (NOW, test_pyc)} 188 self.doTest(pyc_ext, files, TESTMOD) 189 190 def testUncheckedHashBasedPyc(self): 191 source = b"state = 'old'" 192 source_hash = importlib.util.source_hash(source) 193 bytecode = importlib._bootstrap_external._code_to_hash_pyc( 194 compile(source, "???", "exec"), 195 source_hash, 196 False, # unchecked 197 ) 198 files = {TESTMOD + ".py": (NOW, "state = 'new'"), 199 TESTMOD + ".pyc": (NOW - 20, bytecode)} 200 def check(mod): 201 self.assertEqual(mod.state, 'old') 202 self.doTest(None, files, TESTMOD, call=check) 203 204 def testEmptyPy(self): 205 files = {TESTMOD + ".py": (NOW, "")} 206 self.doTest(None, files, TESTMOD) 207 208 def testBadMagic(self): 209 # make pyc magic word invalid, forcing loading from .py 210 badmagic_pyc = bytearray(test_pyc) 211 badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit 212 files = {TESTMOD + ".py": (NOW, test_src), 213 TESTMOD + pyc_ext: (NOW, badmagic_pyc)} 214 self.doTest(".py", files, TESTMOD) 215 216 def testBadMagic2(self): 217 # make pyc magic word invalid, causing an ImportError 218 badmagic_pyc = bytearray(test_pyc) 219 badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit 220 files = {TESTMOD + pyc_ext: (NOW, badmagic_pyc)} 221 try: 222 self.doTest(".py", files, TESTMOD) 223 except ImportError: 224 pass 225 else: 226 self.fail("expected ImportError; import from bad pyc") 227 228 def testBadMTime(self): 229 badtime_pyc = bytearray(test_pyc) 230 # flip the second bit -- not the first as that one isn't stored in the 231 # .py's mtime in the zip archive. 232 badtime_pyc[11] ^= 0x02 233 files = {TESTMOD + ".py": (NOW, test_src), 234 TESTMOD + pyc_ext: (NOW, badtime_pyc)} 235 self.doTest(".py", files, TESTMOD) 236 237 def testPackage(self): 238 packdir = TESTPACK + os.sep 239 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), 240 packdir + TESTMOD + pyc_ext: (NOW, test_pyc)} 241 self.doTest(pyc_ext, files, TESTPACK, TESTMOD) 242 243 def testSubPackage(self): 244 # Test that subpackages function when loaded from zip 245 # archives. 246 packdir = TESTPACK + os.sep 247 packdir2 = packdir + TESTPACK2 + os.sep 248 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), 249 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), 250 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 251 self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD) 252 253 def testSubNamespacePackage(self): 254 # Test that implicit namespace subpackages function 255 # when loaded from zip archives. 256 packdir = TESTPACK + os.sep 257 packdir2 = packdir + TESTPACK2 + os.sep 258 # The first two files are just directory entries (so have no data). 259 files = {packdir: (NOW, ""), 260 packdir2: (NOW, ""), 261 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 262 self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD) 263 264 def testMixedNamespacePackage(self): 265 # Test implicit namespace packages spread between a 266 # real filesystem and a zip archive. 267 packdir = TESTPACK + os.sep 268 packdir2 = packdir + TESTPACK2 + os.sep 269 packdir3 = packdir2 + TESTPACK + '3' + os.sep 270 files1 = {packdir: (NOW, ""), 271 packdir + TESTMOD + pyc_ext: (NOW, test_pyc), 272 packdir2: (NOW, ""), 273 packdir3: (NOW, ""), 274 packdir3 + TESTMOD + pyc_ext: (NOW, test_pyc), 275 packdir2 + TESTMOD + '3' + pyc_ext: (NOW, test_pyc), 276 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 277 files2 = {packdir: (NOW, ""), 278 packdir + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), 279 packdir2: (NOW, ""), 280 packdir2 + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), 281 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 282 283 zip1 = os.path.abspath("path1.zip") 284 self.makeZip(files1, zip1) 285 286 zip2 = TEMP_DIR 287 self.makeTree(files2, zip2) 288 289 # zip2 should override zip1. 290 sys.path.insert(0, zip1) 291 sys.path.insert(0, zip2) 292 293 mod = importlib.import_module(TESTPACK) 294 295 # if TESTPACK is functioning as a namespace pkg then 296 # there should be two entries in the __path__. 297 # First should be path2 and second path1. 298 self.assertEqual(2, len(mod.__path__)) 299 p1, p2 = mod.__path__ 300 self.assertEqual(os.path.basename(TEMP_DIR), p1.split(os.sep)[-2]) 301 self.assertEqual("path1.zip", p2.split(os.sep)[-2]) 302 303 # packdir3 should import as a namespace package. 304 # Its __path__ is an iterable of 1 element from zip1. 305 mod = importlib.import_module(packdir3.replace(os.sep, '.')[:-1]) 306 self.assertEqual(1, len(mod.__path__)) 307 mpath = list(mod.__path__)[0].split('path1.zip' + os.sep)[1] 308 self.assertEqual(packdir3[:-1], mpath) 309 310 # TESTPACK/TESTMOD only exists in path1. 311 mod = importlib.import_module('.'.join((TESTPACK, TESTMOD))) 312 self.assertEqual("path1.zip", mod.__file__.split(os.sep)[-3]) 313 314 # And TESTPACK/(TESTMOD + '2') only exists in path2. 315 mod = importlib.import_module('.'.join((TESTPACK, TESTMOD + '2'))) 316 self.assertEqual(os.path.basename(TEMP_DIR), 317 mod.__file__.split(os.sep)[-3]) 318 319 # One level deeper... 320 subpkg = '.'.join((TESTPACK, TESTPACK2)) 321 mod = importlib.import_module(subpkg) 322 self.assertEqual(2, len(mod.__path__)) 323 p1, p2 = mod.__path__ 324 self.assertEqual(os.path.basename(TEMP_DIR), p1.split(os.sep)[-3]) 325 self.assertEqual("path1.zip", p2.split(os.sep)[-3]) 326 327 # subpkg.TESTMOD exists in both zips should load from zip2. 328 mod = importlib.import_module('.'.join((subpkg, TESTMOD))) 329 self.assertEqual(os.path.basename(TEMP_DIR), 330 mod.__file__.split(os.sep)[-4]) 331 332 # subpkg.TESTMOD + '2' only exists in zip2. 333 mod = importlib.import_module('.'.join((subpkg, TESTMOD + '2'))) 334 self.assertEqual(os.path.basename(TEMP_DIR), 335 mod.__file__.split(os.sep)[-4]) 336 337 # Finally subpkg.TESTMOD + '3' only exists in zip1. 338 mod = importlib.import_module('.'.join((subpkg, TESTMOD + '3'))) 339 self.assertEqual('path1.zip', mod.__file__.split(os.sep)[-4]) 340 341 def testNamespacePackage(self): 342 # Test implicit namespace packages spread between multiple zip 343 # archives. 344 packdir = TESTPACK + os.sep 345 packdir2 = packdir + TESTPACK2 + os.sep 346 packdir3 = packdir2 + TESTPACK + '3' + os.sep 347 files1 = {packdir: (NOW, ""), 348 packdir + TESTMOD + pyc_ext: (NOW, test_pyc), 349 packdir2: (NOW, ""), 350 packdir3: (NOW, ""), 351 packdir3 + TESTMOD + pyc_ext: (NOW, test_pyc), 352 packdir2 + TESTMOD + '3' + pyc_ext: (NOW, test_pyc), 353 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 354 zip1 = os.path.abspath("path1.zip") 355 self.makeZip(files1, zip1) 356 357 files2 = {packdir: (NOW, ""), 358 packdir + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), 359 packdir2: (NOW, ""), 360 packdir2 + TESTMOD + '2' + pyc_ext: (NOW, test_pyc), 361 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 362 zip2 = os.path.abspath("path2.zip") 363 self.makeZip(files2, zip2) 364 365 # zip2 should override zip1. 366 sys.path.insert(0, zip1) 367 sys.path.insert(0, zip2) 368 369 mod = importlib.import_module(TESTPACK) 370 371 # if TESTPACK is functioning as a namespace pkg then 372 # there should be two entries in the __path__. 373 # First should be path2 and second path1. 374 self.assertEqual(2, len(mod.__path__)) 375 p1, p2 = mod.__path__ 376 self.assertEqual("path2.zip", p1.split(os.sep)[-2]) 377 self.assertEqual("path1.zip", p2.split(os.sep)[-2]) 378 379 # packdir3 should import as a namespace package. 380 # Tts __path__ is an iterable of 1 element from zip1. 381 mod = importlib.import_module(packdir3.replace(os.sep, '.')[:-1]) 382 self.assertEqual(1, len(mod.__path__)) 383 mpath = list(mod.__path__)[0].split('path1.zip' + os.sep)[1] 384 self.assertEqual(packdir3[:-1], mpath) 385 386 # TESTPACK/TESTMOD only exists in path1. 387 mod = importlib.import_module('.'.join((TESTPACK, TESTMOD))) 388 self.assertEqual("path1.zip", mod.__file__.split(os.sep)[-3]) 389 390 # And TESTPACK/(TESTMOD + '2') only exists in path2. 391 mod = importlib.import_module('.'.join((TESTPACK, TESTMOD + '2'))) 392 self.assertEqual("path2.zip", mod.__file__.split(os.sep)[-3]) 393 394 # One level deeper... 395 subpkg = '.'.join((TESTPACK, TESTPACK2)) 396 mod = importlib.import_module(subpkg) 397 self.assertEqual(2, len(mod.__path__)) 398 p1, p2 = mod.__path__ 399 self.assertEqual("path2.zip", p1.split(os.sep)[-3]) 400 self.assertEqual("path1.zip", p2.split(os.sep)[-3]) 401 402 # subpkg.TESTMOD exists in both zips should load from zip2. 403 mod = importlib.import_module('.'.join((subpkg, TESTMOD))) 404 self.assertEqual('path2.zip', mod.__file__.split(os.sep)[-4]) 405 406 # subpkg.TESTMOD + '2' only exists in zip2. 407 mod = importlib.import_module('.'.join((subpkg, TESTMOD + '2'))) 408 self.assertEqual('path2.zip', mod.__file__.split(os.sep)[-4]) 409 410 # Finally subpkg.TESTMOD + '3' only exists in zip1. 411 mod = importlib.import_module('.'.join((subpkg, TESTMOD + '3'))) 412 self.assertEqual('path1.zip', mod.__file__.split(os.sep)[-4]) 413 414 def testZipImporterMethods(self): 415 packdir = TESTPACK + os.sep 416 packdir2 = packdir + TESTPACK2 + os.sep 417 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), 418 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), 419 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc), 420 "spam" + pyc_ext: (NOW, test_pyc)} 421 422 z = ZipFile(TEMP_ZIP, "w") 423 try: 424 for name, (mtime, data) in files.items(): 425 zinfo = ZipInfo(name, time.localtime(mtime)) 426 zinfo.compress_type = self.compression 427 zinfo.comment = b"spam" 428 z.writestr(zinfo, data) 429 z.close() 430 431 zi = zipimport.zipimporter(TEMP_ZIP) 432 self.assertEqual(zi.archive, TEMP_ZIP) 433 self.assertEqual(zi.is_package(TESTPACK), True) 434 435 find_mod = zi.find_module('spam') 436 self.assertIsNotNone(find_mod) 437 self.assertIsInstance(find_mod, zipimport.zipimporter) 438 self.assertFalse(find_mod.is_package('spam')) 439 load_mod = find_mod.load_module('spam') 440 self.assertEqual(find_mod.get_filename('spam'), load_mod.__file__) 441 442 mod = zi.load_module(TESTPACK) 443 self.assertEqual(zi.get_filename(TESTPACK), mod.__file__) 444 445 existing_pack_path = importlib.import_module(TESTPACK).__path__[0] 446 expected_path_path = os.path.join(TEMP_ZIP, TESTPACK) 447 self.assertEqual(existing_pack_path, expected_path_path) 448 449 self.assertEqual(zi.is_package(packdir + '__init__'), False) 450 self.assertEqual(zi.is_package(packdir + TESTPACK2), True) 451 self.assertEqual(zi.is_package(packdir2 + TESTMOD), False) 452 453 mod_path = packdir2 + TESTMOD 454 mod_name = module_path_to_dotted_name(mod_path) 455 mod = importlib.import_module(mod_name) 456 self.assertTrue(mod_name in sys.modules) 457 self.assertEqual(zi.get_source(TESTPACK), None) 458 self.assertEqual(zi.get_source(mod_path), None) 459 self.assertEqual(zi.get_filename(mod_path), mod.__file__) 460 # To pass in the module name instead of the path, we must use the 461 # right importer 462 loader = mod.__loader__ 463 self.assertEqual(loader.get_source(mod_name), None) 464 self.assertEqual(loader.get_filename(mod_name), mod.__file__) 465 466 # test prefix and archivepath members 467 zi2 = zipimport.zipimporter(TEMP_ZIP + os.sep + TESTPACK) 468 self.assertEqual(zi2.archive, TEMP_ZIP) 469 self.assertEqual(zi2.prefix, TESTPACK + os.sep) 470 finally: 471 z.close() 472 os.remove(TEMP_ZIP) 473 474 def testZipImporterMethodsInSubDirectory(self): 475 packdir = TESTPACK + os.sep 476 packdir2 = packdir + TESTPACK2 + os.sep 477 files = {packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), 478 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)} 479 480 z = ZipFile(TEMP_ZIP, "w") 481 try: 482 for name, (mtime, data) in files.items(): 483 zinfo = ZipInfo(name, time.localtime(mtime)) 484 zinfo.compress_type = self.compression 485 zinfo.comment = b"eggs" 486 z.writestr(zinfo, data) 487 z.close() 488 489 zi = zipimport.zipimporter(TEMP_ZIP + os.sep + packdir) 490 self.assertEqual(zi.archive, TEMP_ZIP) 491 self.assertEqual(zi.prefix, packdir) 492 self.assertEqual(zi.is_package(TESTPACK2), True) 493 mod = zi.load_module(TESTPACK2) 494 self.assertEqual(zi.get_filename(TESTPACK2), mod.__file__) 495 496 self.assertEqual( 497 zi.is_package(TESTPACK2 + os.sep + '__init__'), False) 498 self.assertEqual( 499 zi.is_package(TESTPACK2 + os.sep + TESTMOD), False) 500 501 pkg_path = TEMP_ZIP + os.sep + packdir + TESTPACK2 502 zi2 = zipimport.zipimporter(pkg_path) 503 find_mod_dotted = zi2.find_module(TESTMOD) 504 self.assertIsNotNone(find_mod_dotted) 505 self.assertIsInstance(find_mod_dotted, zipimport.zipimporter) 506 self.assertFalse(zi2.is_package(TESTMOD)) 507 load_mod = find_mod_dotted.load_module(TESTMOD) 508 self.assertEqual( 509 find_mod_dotted.get_filename(TESTMOD), load_mod.__file__) 510 511 mod_path = TESTPACK2 + os.sep + TESTMOD 512 mod_name = module_path_to_dotted_name(mod_path) 513 mod = importlib.import_module(mod_name) 514 self.assertTrue(mod_name in sys.modules) 515 self.assertEqual(zi.get_source(TESTPACK2), None) 516 self.assertEqual(zi.get_source(mod_path), None) 517 self.assertEqual(zi.get_filename(mod_path), mod.__file__) 518 # To pass in the module name instead of the path, we must use the 519 # right importer. 520 loader = mod.__loader__ 521 self.assertEqual(loader.get_source(mod_name), None) 522 self.assertEqual(loader.get_filename(mod_name), mod.__file__) 523 finally: 524 z.close() 525 os.remove(TEMP_ZIP) 526 527 def testGetData(self): 528 z = ZipFile(TEMP_ZIP, "w") 529 z.compression = self.compression 530 try: 531 name = "testdata.dat" 532 data = bytes(x for x in range(256)) 533 z.writestr(name, data) 534 z.close() 535 zi = zipimport.zipimporter(TEMP_ZIP) 536 self.assertEqual(data, zi.get_data(name)) 537 self.assertIn('zipimporter object', repr(zi)) 538 finally: 539 z.close() 540 os.remove(TEMP_ZIP) 541 542 def test_issue31291(self): 543 # There shouldn't be an assertion failure in get_data(). 544 class FunnyStr(str): 545 def replace(self, old, new): 546 return 42 547 z = ZipFile(TEMP_ZIP, "w") 548 try: 549 name = "test31291.dat" 550 data = b'foo' 551 z.writestr(name, data) 552 z.close() 553 zi = zipimport.zipimporter(TEMP_ZIP) 554 self.assertEqual(data, zi.get_data(FunnyStr(name))) 555 finally: 556 z.close() 557 os.remove(TEMP_ZIP) 558 559 def testImporterAttr(self): 560 src = """if 1: # indent hack 561 def get_file(): 562 return __file__ 563 if __loader__.get_data("some.data") != b"some data": 564 raise AssertionError("bad data")\n""" 565 pyc = make_pyc(compile(src, "<???>", "exec"), NOW, len(src)) 566 files = {TESTMOD + pyc_ext: (NOW, pyc), 567 "some.data": (NOW, "some data")} 568 self.doTest(pyc_ext, files, TESTMOD) 569 570 def testDefaultOptimizationLevel(self): 571 # zipimport should use the default optimization level (#28131) 572 src = """if 1: # indent hack 573 def test(val): 574 assert(val) 575 return val\n""" 576 files = {TESTMOD + '.py': (NOW, src)} 577 self.makeZip(files) 578 sys.path.insert(0, TEMP_ZIP) 579 mod = importlib.import_module(TESTMOD) 580 self.assertEqual(mod.test(1), 1) 581 self.assertRaises(AssertionError, mod.test, False) 582 583 def testImport_WithStuff(self): 584 # try importing from a zipfile which contains additional 585 # stuff at the beginning of the file 586 files = {TESTMOD + ".py": (NOW, test_src)} 587 self.doTest(".py", files, TESTMOD, 588 stuff=b"Some Stuff"*31) 589 590 def assertModuleSource(self, module): 591 self.assertEqual(inspect.getsource(module), test_src) 592 593 def testGetSource(self): 594 files = {TESTMOD + ".py": (NOW, test_src)} 595 self.doTest(".py", files, TESTMOD, call=self.assertModuleSource) 596 597 def testGetCompiledSource(self): 598 pyc = make_pyc(compile(test_src, "<???>", "exec"), NOW, len(test_src)) 599 files = {TESTMOD + ".py": (NOW, test_src), 600 TESTMOD + pyc_ext: (NOW, pyc)} 601 self.doTest(pyc_ext, files, TESTMOD, call=self.assertModuleSource) 602 603 def runDoctest(self, callback): 604 files = {TESTMOD + ".py": (NOW, test_src), 605 "xyz.txt": (NOW, ">>> log.append(True)\n")} 606 self.doTest(".py", files, TESTMOD, call=callback) 607 608 def doDoctestFile(self, module): 609 log = [] 610 old_master, doctest.master = doctest.master, None 611 try: 612 doctest.testfile( 613 'xyz.txt', package=module, module_relative=True, 614 globs=locals() 615 ) 616 finally: 617 doctest.master = old_master 618 self.assertEqual(log,[True]) 619 620 def testDoctestFile(self): 621 self.runDoctest(self.doDoctestFile) 622 623 def doDoctestSuite(self, module): 624 log = [] 625 doctest.DocFileTest( 626 'xyz.txt', package=module, module_relative=True, 627 globs=locals() 628 ).run() 629 self.assertEqual(log,[True]) 630 631 def testDoctestSuite(self): 632 self.runDoctest(self.doDoctestSuite) 633 634 def doTraceback(self, module): 635 try: 636 module.do_raise() 637 except: 638 tb = sys.exc_info()[2].tb_next 639 640 f,lno,n,line = extract_tb(tb, 1)[0] 641 self.assertEqual(line, raise_src.strip()) 642 643 f,lno,n,line = extract_stack(tb.tb_frame, 1)[0] 644 self.assertEqual(line, raise_src.strip()) 645 646 s = io.StringIO() 647 print_tb(tb, 1, s) 648 self.assertTrue(s.getvalue().endswith(raise_src)) 649 else: 650 raise AssertionError("This ought to be impossible") 651 652 def testTraceback(self): 653 files = {TESTMOD + ".py": (NOW, raise_src)} 654 self.doTest(None, files, TESTMOD, call=self.doTraceback) 655 656 @unittest.skipIf(support.TESTFN_UNENCODABLE is None, 657 "need an unencodable filename") 658 def testUnencodable(self): 659 filename = support.TESTFN_UNENCODABLE + ".zip" 660 z = ZipFile(filename, "w") 661 zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) 662 zinfo.compress_type = self.compression 663 z.writestr(zinfo, test_src) 664 z.close() 665 try: 666 zipimport.zipimporter(filename).load_module(TESTMOD) 667 finally: 668 os.remove(filename) 669 670 def testBytesPath(self): 671 filename = support.TESTFN + ".zip" 672 self.addCleanup(support.unlink, filename) 673 with ZipFile(filename, "w") as z: 674 zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) 675 zinfo.compress_type = self.compression 676 z.writestr(zinfo, test_src) 677 678 zipimport.zipimporter(filename) 679 zipimport.zipimporter(os.fsencode(filename)) 680 with self.assertWarns(DeprecationWarning): 681 zipimport.zipimporter(bytearray(os.fsencode(filename))) 682 with self.assertWarns(DeprecationWarning): 683 zipimport.zipimporter(memoryview(os.fsencode(filename))) 684 685 @support.cpython_only 686 def testUninitializedZipimporter(self): 687 # The interpreter shouldn't crash in case of calling methods of an 688 # uninitialized zipimport.zipimporter object. 689 zi = zipimport.zipimporter.__new__(zipimport.zipimporter) 690 self.assertRaises(ValueError, zi.find_module, 'foo') 691 self.assertRaises(ValueError, zi.find_loader, 'foo') 692 self.assertRaises(ValueError, zi.load_module, 'foo') 693 self.assertRaises(ValueError, zi.get_filename, 'foo') 694 self.assertRaises(ValueError, zi.is_package, 'foo') 695 self.assertRaises(ValueError, zi.get_data, 'foo') 696 self.assertRaises(ValueError, zi.get_code, 'foo') 697 self.assertRaises(ValueError, zi.get_source, 'foo') 698 699 700@support.requires_zlib 701class CompressedZipImportTestCase(UncompressedZipImportTestCase): 702 compression = ZIP_DEFLATED 703 704 @support.cpython_only 705 def test_issue31602(self): 706 # There shouldn't be an assertion failure in zipimporter.get_source() 707 # in case of a bad zlib.decompress(). 708 def bad_decompress(*args): 709 return None 710 with ZipFile(TEMP_ZIP, 'w') as zip_file: 711 self.addCleanup(support.unlink, TEMP_ZIP) 712 zip_file.writestr('bar.py', b'print("hello world")', ZIP_DEFLATED) 713 zi = zipimport.zipimporter(TEMP_ZIP) 714 with support.swap_attr(zlib, 'decompress', bad_decompress): 715 self.assertRaises(TypeError, zi.get_source, 'bar') 716 717 718class BadFileZipImportTestCase(unittest.TestCase): 719 def assertZipFailure(self, filename): 720 self.assertRaises(zipimport.ZipImportError, 721 zipimport.zipimporter, filename) 722 723 def testNoFile(self): 724 self.assertZipFailure('AdfjdkFJKDFJjdklfjs') 725 726 def testEmptyFilename(self): 727 self.assertZipFailure('') 728 729 def testBadArgs(self): 730 self.assertRaises(TypeError, zipimport.zipimporter, None) 731 self.assertRaises(TypeError, zipimport.zipimporter, TESTMOD, kwd=None) 732 self.assertRaises(TypeError, zipimport.zipimporter, 733 list(os.fsencode(TESTMOD))) 734 735 def testFilenameTooLong(self): 736 self.assertZipFailure('A' * 33000) 737 738 def testEmptyFile(self): 739 support.unlink(TESTMOD) 740 support.create_empty_file(TESTMOD) 741 self.assertZipFailure(TESTMOD) 742 743 def testFileUnreadable(self): 744 support.unlink(TESTMOD) 745 fd = os.open(TESTMOD, os.O_CREAT, 000) 746 try: 747 os.close(fd) 748 749 with self.assertRaises(zipimport.ZipImportError) as cm: 750 zipimport.zipimporter(TESTMOD) 751 finally: 752 # If we leave "the read-only bit" set on Windows, nothing can 753 # delete TESTMOD, and later tests suffer bogus failures. 754 os.chmod(TESTMOD, 0o666) 755 support.unlink(TESTMOD) 756 757 def testNotZipFile(self): 758 support.unlink(TESTMOD) 759 fp = open(TESTMOD, 'w+') 760 fp.write('a' * 22) 761 fp.close() 762 self.assertZipFailure(TESTMOD) 763 764 # XXX: disabled until this works on Big-endian machines 765 def _testBogusZipFile(self): 766 support.unlink(TESTMOD) 767 fp = open(TESTMOD, 'w+') 768 fp.write(struct.pack('=I', 0x06054B50)) 769 fp.write('a' * 18) 770 fp.close() 771 z = zipimport.zipimporter(TESTMOD) 772 773 try: 774 self.assertRaises(TypeError, z.find_module, None) 775 self.assertRaises(TypeError, z.load_module, None) 776 self.assertRaises(TypeError, z.is_package, None) 777 self.assertRaises(TypeError, z.get_code, None) 778 self.assertRaises(TypeError, z.get_data, None) 779 self.assertRaises(TypeError, z.get_source, None) 780 781 error = zipimport.ZipImportError 782 self.assertEqual(z.find_module('abc'), None) 783 784 self.assertRaises(error, z.load_module, 'abc') 785 self.assertRaises(error, z.get_code, 'abc') 786 self.assertRaises(OSError, z.get_data, 'abc') 787 self.assertRaises(error, z.get_source, 'abc') 788 self.assertRaises(error, z.is_package, 'abc') 789 finally: 790 zipimport._zip_directory_cache.clear() 791 792 793def test_main(): 794 try: 795 support.run_unittest( 796 UncompressedZipImportTestCase, 797 CompressedZipImportTestCase, 798 BadFileZipImportTestCase, 799 ) 800 finally: 801 support.unlink(TESTMOD) 802 803if __name__ == "__main__": 804 test_main() 805