blob: 7ddbc509f9bb332040078b06e946434f8a382705 [file] [log] [blame]
Just van Rossum52e14d62002-12-30 22:08:05 +00001import sys
2import os
3import marshal
Brett Cannon56aae8f2016-01-15 11:22:19 -08004import importlib
Brett Cannon9529fbf2013-06-15 17:11:25 -04005import importlib.util
Just van Rossum52e14d62002-12-30 22:08:05 +00006import struct
7import time
Neal Norwitzb155b622006-01-23 07:52:13 +00008import unittest
Just van Rossum52e14d62002-12-30 22:08:05 +00009
Benjamin Petersonee8712c2008-05-20 21:35:26 +000010from test import support
Just van Rossum52e14d62002-12-30 22:08:05 +000011
Ezio Melotti78ea2022009-09-12 18:41:20 +000012from zipfile import ZipFile, ZipInfo, ZIP_STORED, ZIP_DEFLATED
13
Just van Rossum52e14d62002-12-30 22:08:05 +000014import zipimport
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000015import linecache
16import doctest
17import inspect
Guido van Rossum34d19282007-08-09 01:03:29 +000018import io
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000019from traceback import extract_tb, extract_stack, print_tb
Brett Cannon638ce072013-06-12 15:57:01 -040020
21test_src = """\
22def get_name():
23 return __name__
24def get_file():
25 return __file__
26"""
27test_co = compile(test_src, "<???>", "exec")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000028raise_src = 'def do_raise(): raise TypeError\n'
Just van Rossum52e14d62002-12-30 22:08:05 +000029
Antoine Pitrou5136ac02012-01-13 18:52:16 +010030def make_pyc(co, mtime, size):
Just van Rossum52e14d62002-12-30 22:08:05 +000031 data = marshal.dumps(co)
Jack Jansen472e7db2003-01-08 16:37:03 +000032 if type(mtime) is type(0.0):
Tim Petersf2715e02003-02-19 02:35:07 +000033 # Mac mtimes need a bit of special casing
34 if mtime < 0x7fffffff:
35 mtime = int(mtime)
36 else:
Guido van Rossume2a383d2007-01-15 16:59:06 +000037 mtime = int(-0x100000000 + int(mtime))
Brett Cannon9529fbf2013-06-15 17:11:25 -040038 pyc = (importlib.util.MAGIC_NUMBER +
39 struct.pack("<ii", int(mtime), size & 0xFFFFFFFF) + data)
Just van Rossum52e14d62002-12-30 22:08:05 +000040 return pyc
41
Tim Peters68f2d002006-01-23 22:19:24 +000042def module_path_to_dotted_name(path):
43 return path.replace(os.sep, '.')
44
Just van Rossum52e14d62002-12-30 22:08:05 +000045NOW = time.time()
Antoine Pitrou5136ac02012-01-13 18:52:16 +010046test_pyc = make_pyc(test_co, NOW, len(test_src))
Just van Rossum52e14d62002-12-30 22:08:05 +000047
48
Just van Rossum52e14d62002-12-30 22:08:05 +000049TESTMOD = "ziptestmodule"
50TESTPACK = "ziptestpackage"
Just van Rossumd35c6db2003-01-02 12:55:48 +000051TESTPACK2 = "ziptestpackage2"
Brett Cannon56aae8f2016-01-15 11:22:19 -080052TEMP_DIR = os.path.abspath("junk95142")
Skip Montanaro7a98be22007-08-16 14:35:24 +000053TEMP_ZIP = os.path.abspath("junk95142.zip")
Just van Rossum52e14d62002-12-30 22:08:05 +000054
Brett Cannon9529fbf2013-06-15 17:11:25 -040055pyc_file = importlib.util.cache_from_source(TESTMOD + '.py')
Brett Cannonf299abd2015-04-13 14:21:02 -040056pyc_ext = '.pyc'
Barry Warsaw28a691b2010-04-17 00:19:56 +000057
Ezio Melotti78ea2022009-09-12 18:41:20 +000058
Brett Cannon638ce072013-06-12 15:57:01 -040059class 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
Just van Rossum52e14d62002-12-30 22:08:05 +000076class 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
Brett Cannon56aae8f2016-01-15 11:22:19 -080082 # cached directory info and linecache.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000083 linecache.clearcache()
Just van Rossum52e14d62002-12-30 22:08:05 +000084 zipimport._zip_directory_cache.clear()
85 ImportHooksBaseTestCase.setUp(self)
86
Brett Cannon56aae8f2016-01-15 11:22:19 -080087 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:
Benjamin Petersoneb437362014-02-16 14:12:57 -0500111 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)
Benjamin Petersoneb437362014-02-16 14:12:57 -0500115
Brett Cannon56aae8f2016-01-15 11:22:19 -0800116 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)
Benjamin Petersoneb437362014-02-16 14:12:57 -0500124
Brett Cannon56aae8f2016-01-15 11:22:19 -0800125 def doTest(self, expected_ext, files, *modules, **kw):
126 self.makeZip(files, **kw)
Just van Rossum52e14d62002-12-30 22:08:05 +0000127
Brett Cannon56aae8f2016-01-15 11:22:19 -0800128 sys.path.insert(0, TEMP_ZIP)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000129
Brett Cannon56aae8f2016-01-15 11:22:19 -0800130 mod = importlib.import_module(".".join(modules))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000131
Brett Cannon56aae8f2016-01-15 11:22:19 -0800132 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,
Ezio Melottib3aedd42010-11-20 19:04:17 +0000139 *modules) + expected_ext)
Just van Rossum52e14d62002-12-30 22:08:05 +0000140
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 #
Just van Rossum59498542003-11-18 23:00:55 +0000154 # 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:
Zachary Ware9fe6d862013-12-08 00:20:35 -0600160 self.skipTest('zlib is a builtin module')
Just van Rossum52e14d62002-12-30 22:08:05 +0000161 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
Just van Rossum9a3129c2003-01-03 11:18:56 +0000186 def testEmptyPy(self):
187 files = {TESTMOD + ".py": (NOW, "")}
188 self.doTest(None, files, TESTMOD)
189
Just van Rossum52e14d62002-12-30 22:08:05 +0000190 def testBadMagic(self):
191 # make pyc magic word invalid, forcing loading from .py
Guido van Rossum254348e2007-11-21 19:29:53 +0000192 badmagic_pyc = bytearray(test_pyc)
Guido van Rossumad8d3002007-08-03 18:40:49 +0000193 badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit
Just van Rossum52e14d62002-12-30 22:08:05 +0000194 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
Guido van Rossum254348e2007-11-21 19:29:53 +0000200 badmagic_pyc = bytearray(test_pyc)
Guido van Rossumad8d3002007-08-03 18:40:49 +0000201 badmagic_pyc[0] ^= 0x04 # flip an arbitrary bit
Just van Rossum52e14d62002-12-30 22:08:05 +0000202 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):
Guido van Rossum254348e2007-11-21 19:29:53 +0000211 badtime_pyc = bytearray(test_pyc)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000212 # 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
Just van Rossum52e14d62002-12-30 22:08:05 +0000215 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
Brett Cannon56aae8f2016-01-15 11:22:19 -0800225 def testSubPackage(self):
226 # Test that subpackages function when loaded from zip
227 # archives.
Just van Rossum52e14d62002-12-30 22:08:05 +0000228 packdir = TESTPACK + os.sep
Just van Rossumd35c6db2003-01-02 12:55:48 +0000229 packdir2 = packdir + TESTPACK2 + os.sep
Just van Rossum52e14d62002-12-30 22:08:05 +0000230 files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
231 packdir2 + "__init__" + pyc_ext: (NOW, test_pyc),
232 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)}
Just van Rossumd35c6db2003-01-02 12:55:48 +0000233 self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD)
Just van Rossum52e14d62002-12-30 22:08:05 +0000234
Brett Cannon56aae8f2016-01-15 11:22:19 -0800235 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
Neal Norwitzb155b622006-01-23 07:52:13 +0000396 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),
Robert Collins9e1bf492015-07-23 02:57:56 +1200401 packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc),
402 "spam" + pyc_ext: (NOW, test_pyc)}
Neal Norwitzb155b622006-01-23 07:52:13 +0000403
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
Serhiy Storchaka0e6b7b52013-02-16 17:43:45 +0200409 zinfo.comment = b"spam"
Neal Norwitzb155b622006-01-23 07:52:13 +0000410 z.writestr(zinfo, data)
411 z.close()
412
413 zi = zipimport.zipimporter(TEMP_ZIP)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000414 self.assertEqual(zi.archive, TEMP_ZIP)
415 self.assertEqual(zi.is_package(TESTPACK), True)
Robert Collins9e1bf492015-07-23 02:57:56 +1200416
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
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000424 mod = zi.load_module(TESTPACK)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000425 self.assertEqual(zi.get_filename(TESTPACK), mod.__file__)
Tim Petersbc29c1a2006-01-23 21:28:42 +0000426
Brett Cannon56aae8f2016-01-15 11:22:19 -0800427 existing_pack_path = importlib.import_module(TESTPACK).__path__[0]
R David Murraya9719052012-03-12 21:16:33 -0400428 expected_path_path = os.path.join(TEMP_ZIP, TESTPACK)
429 self.assertEqual(existing_pack_path, expected_path_path)
430
Ezio Melottib3aedd42010-11-20 19:04:17 +0000431 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)
Neal Norwitzb155b622006-01-23 07:52:13 +0000434
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000435 mod_path = packdir2 + TESTMOD
436 mod_name = module_path_to_dotted_name(mod_path)
Brett Cannon56aae8f2016-01-15 11:22:19 -0800437 mod = importlib.import_module(mod_name)
438 self.assertTrue(mod_name in sys.modules)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000439 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__)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000442 # To pass in the module name instead of the path, we must use the
443 # right importer
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000444 loader = mod.__loader__
Ezio Melottib3aedd42010-11-20 19:04:17 +0000445 self.assertEqual(loader.get_source(mod_name), None)
446 self.assertEqual(loader.get_filename(mod_name), mod.__file__)
Christian Heimes7f044312008-01-06 17:05:40 +0000447
448 # test prefix and archivepath members
449 zi2 = zipimport.zipimporter(TEMP_ZIP + os.sep + TESTPACK)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000450 self.assertEqual(zi2.archive, TEMP_ZIP)
451 self.assertEqual(zi2.prefix, TESTPACK + os.sep)
Neal Norwitzb155b622006-01-23 07:52:13 +0000452 finally:
453 z.close()
454 os.remove(TEMP_ZIP)
455
Alexandre Vassalotti8ae3e052008-05-16 00:41:41 +0000456 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
Serhiy Storchaka0e6b7b52013-02-16 17:43:45 +0200467 zinfo.comment = b"eggs"
Alexandre Vassalotti8ae3e052008-05-16 00:41:41 +0000468 z.writestr(zinfo, data)
469 z.close()
470
471 zi = zipimport.zipimporter(TEMP_ZIP + os.sep + packdir)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000472 self.assertEqual(zi.archive, TEMP_ZIP)
473 self.assertEqual(zi.prefix, packdir)
474 self.assertEqual(zi.is_package(TESTPACK2), True)
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000475 mod = zi.load_module(TESTPACK2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000476 self.assertEqual(zi.get_filename(TESTPACK2), mod.__file__)
Alexandre Vassalotti8ae3e052008-05-16 00:41:41 +0000477
Ezio Melottib3aedd42010-11-20 19:04:17 +0000478 self.assertEqual(
Barry Warsaw28a691b2010-04-17 00:19:56 +0000479 zi.is_package(TESTPACK2 + os.sep + '__init__'), False)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000480 self.assertEqual(
Barry Warsaw28a691b2010-04-17 00:19:56 +0000481 zi.is_package(TESTPACK2 + os.sep + TESTMOD), False)
Alexandre Vassalotti8ae3e052008-05-16 00:41:41 +0000482
Robert Collins9e1bf492015-07-23 02:57:56 +1200483 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
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000493 mod_path = TESTPACK2 + os.sep + TESTMOD
494 mod_name = module_path_to_dotted_name(mod_path)
Brett Cannon56aae8f2016-01-15 11:22:19 -0800495 mod = importlib.import_module(mod_name)
496 self.assertTrue(mod_name in sys.modules)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000497 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__)
Barry Warsaw28a691b2010-04-17 00:19:56 +0000500 # To pass in the module name instead of the path, we must use the
Brett Cannon56aae8f2016-01-15 11:22:19 -0800501 # right importer.
Nick Coghlanf088e5e2008-12-14 11:50:48 +0000502 loader = mod.__loader__
Ezio Melottib3aedd42010-11-20 19:04:17 +0000503 self.assertEqual(loader.get_source(mod_name), None)
504 self.assertEqual(loader.get_filename(mod_name), mod.__file__)
Alexandre Vassalotti8ae3e052008-05-16 00:41:41 +0000505 finally:
506 z.close()
507 os.remove(TEMP_ZIP)
508
Just van Rossum52e14d62002-12-30 22:08:05 +0000509 def testGetData(self):
510 z = ZipFile(TEMP_ZIP, "w")
511 z.compression = self.compression
512 try:
513 name = "testdata.dat"
Guido van Rossumad8d3002007-08-03 18:40:49 +0000514 data = bytes(x for x in range(256))
Just van Rossum52e14d62002-12-30 22:08:05 +0000515 z.writestr(name, data)
516 z.close()
517 zi = zipimport.zipimporter(TEMP_ZIP)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000518 self.assertEqual(data, zi.get_data(name))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000519 self.assertIn('zipimporter object', repr(zi))
Just van Rossum52e14d62002-12-30 22:08:05 +0000520 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__
Guido van Rossumad8d3002007-08-03 18:40:49 +0000528 if __loader__.get_data("some.data") != b"some data":
Collin Winter828f04a2007-08-31 00:04:24 +0000529 raise AssertionError("bad data")\n"""
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100530 pyc = make_pyc(compile(src, "<???>", "exec"), NOW, len(src))
Just van Rossum52e14d62002-12-30 22:08:05 +0000531 files = {TESTMOD + pyc_ext: (NOW, pyc),
532 "some.data": (NOW, "some data")}
533 self.doTest(pyc_ext, files, TESTMOD)
534
Berker Peksag4aa74c42016-09-14 08:09:48 +0300535 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
Thomas Heller354e3d92003-07-22 18:10:15 +0000548 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,
Guido van Rossum85825dc2007-08-27 17:03:28 +0000553 stuff=b"Some Stuff"*31)
Just van Rossum52e14d62002-12-30 22:08:05 +0000554
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000555 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):
Antoine Pitrou5136ac02012-01-13 18:52:16 +0100563 pyc = make_pyc(compile(test_src, "<???>", "exec"), NOW, len(test_src))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000564 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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000599 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
Guido van Rossum34d19282007-08-09 01:03:29 +0000611 s = io.StringIO()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000612 print_tb(tb, 1, s)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000613 self.assertTrue(s.getvalue().endswith(raise_src))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000614 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
Victor Stinner2460a432010-08-16 17:54:28 +0000621 @unittest.skipIf(support.TESTFN_UNENCODABLE is None,
622 "need an unencodable filename")
Victor Stinner36e79112010-08-17 00:44:11 +0000623 def testUnencodable(self):
Victor Stinner2460a432010-08-16 17:54:28 +0000624 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:
Steve Dower8dcc48e2016-09-09 17:27:33 -0700631 zipimport.zipimporter(filename).load_module(TESTMOD)
Victor Stinner2460a432010-08-16 17:54:28 +0000632 finally:
633 os.remove(filename)
634
Serhiy Storchaka9305d832016-06-18 13:53:36 +0300635 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))
Serhiy Storchakafebc3322016-08-06 23:29:29 +0300645 with self.assertWarns(DeprecationWarning):
646 zipimport.zipimporter(bytearray(os.fsencode(filename)))
647 with self.assertWarns(DeprecationWarning):
648 zipimport.zipimporter(memoryview(os.fsencode(filename)))
Serhiy Storchaka9305d832016-06-18 13:53:36 +0300649
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000650
Ezio Melotti975077a2011-05-19 22:03:22 +0300651@support.requires_zlib
Just van Rossum52e14d62002-12-30 22:08:05 +0000652class CompressedZipImportTestCase(UncompressedZipImportTestCase):
653 compression = ZIP_DEFLATED
654
655
Neal Norwitzb155b622006-01-23 07:52:13 +0000656class BadFileZipImportTestCase(unittest.TestCase):
657 def assertZipFailure(self, filename):
Benjamin Petersoneb437362014-02-16 14:12:57 -0500658 self.assertRaises(zipimport.ZipImportError,
659 zipimport.zipimporter, filename)
Neal Norwitzb155b622006-01-23 07:52:13 +0000660
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)
Serhiy Storchaka9305d832016-06-18 13:53:36 +0300670 self.assertRaises(TypeError, zipimport.zipimporter,
671 list(os.fsencode(TESTMOD)))
Neal Norwitzb155b622006-01-23 07:52:13 +0000672
673 def testFilenameTooLong(self):
674 self.assertZipFailure('A' * 33000)
675
676 def testEmptyFile(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000677 support.unlink(TESTMOD)
Victor Stinnerbf816222011-06-30 23:25:47 +0200678 support.create_empty_file(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000679 self.assertZipFailure(TESTMOD)
680
681 def testFileUnreadable(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000682 support.unlink(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000683 fd = os.open(TESTMOD, os.O_CREAT, 000)
Tim Peters68f2d002006-01-23 22:19:24 +0000684 try:
685 os.close(fd)
Victor Stinnerfbd6f9e2015-03-20 10:52:25 +0100686
687 with self.assertRaises(zipimport.ZipImportError) as cm:
688 zipimport.zipimporter(TESTMOD)
Tim Peters68f2d002006-01-23 22:19:24 +0000689 finally:
690 # If we leave "the read-only bit" set on Windows, nothing can
691 # delete TESTMOD, and later tests suffer bogus failures.
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000692 os.chmod(TESTMOD, 0o666)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000693 support.unlink(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000694
695 def testNotZipFile(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000696 support.unlink(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000697 fp = open(TESTMOD, 'w+')
698 fp.write('a' * 22)
699 fp.close()
700 self.assertZipFailure(TESTMOD)
701
Neal Norwitzdbc95f42006-01-23 08:48:03 +0000702 # XXX: disabled until this works on Big-endian machines
703 def _testBogusZipFile(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000704 support.unlink(TESTMOD)
Neal Norwitzb155b622006-01-23 07:52:13 +0000705 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')
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200724 self.assertRaises(OSError, z.get_data, 'abc')
Neal Norwitzb155b622006-01-23 07:52:13 +0000725 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
Neal Norwitz5c1ba532003-02-17 18:05:20 +0000731def test_main():
Neal Norwitzb155b622006-01-23 07:52:13 +0000732 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000733 support.run_unittest(
Neal Norwitzb155b622006-01-23 07:52:13 +0000734 UncompressedZipImportTestCase,
735 CompressedZipImportTestCase,
736 BadFileZipImportTestCase,
737 )
738 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000739 support.unlink(TESTMOD)
Neal Norwitz5c1ba532003-02-17 18:05:20 +0000740
741if __name__ == "__main__":
742 test_main()