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