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