Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Lib/test/test_importlib/test_namespace_pkgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ def test_project3_succeeds(self):
class ZipWithMissingDirectory(NamespacePackageTest):
paths = ['missing_directory.zip']

@unittest.expectedFailure
def test_missing_directory(self):
# This will fail because missing_directory.zip contains:
# Length Date Time Name
Expand Down
135 changes: 115 additions & 20 deletions Lib/test/test_zipimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,81 @@ def testSubNamespacePackage(self):
packdir2 + TESTMOD + pyc_ext: test_pyc}
self.doTest(pyc_ext, files, TESTPACK, TESTPACK2, TESTMOD)

def testPackageExplicitDirectories(self):
# Test explicit namespace packages with explicit directory entries.
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
z.mkdir('a')
z.writestr('a/__init__.py', test_src)
z.mkdir('a/b')
z.writestr('a/b/__init__.py', test_src)
z.mkdir('a/b/c')
z.writestr('a/b/c/__init__.py', test_src)
z.writestr('a/b/c/d.py', test_src)
self._testPackage(initfile='__init__.py')

def testPackageImplicitDirectories(self):
# Test explicit namespace packages without explicit directory entries.
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
z.writestr('a/__init__.py', test_src)
z.writestr('a/b/__init__.py', test_src)
z.writestr('a/b/c/__init__.py', test_src)
z.writestr('a/b/c/d.py', test_src)
self._testPackage(initfile='__init__.py')

def testNamespacePackageExplicitDirectories(self):
# Test implicit namespace packages with explicit directory entries.
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
z.mkdir('a')
z.mkdir('a/b')
z.mkdir('a/b/c')
z.writestr('a/b/c/d.py', test_src)
self._testPackage(initfile=None)

def testNamespacePackageImplicitDirectories(self):
# Test implicit namespace packages without explicit directory entries.
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
z.writestr('a/b/c/d.py', test_src)
self._testPackage(initfile=None)

def _testPackage(self, initfile):
zi = zipimport.zipimporter(os.path.join(TEMP_ZIP, 'a'))
if initfile is None:
# XXX Should it work?
self.assertRaises(zipimport.ZipImportError, zi.is_package, 'b')
self.assertRaises(zipimport.ZipImportError, zi.get_source, 'b')
self.assertRaises(zipimport.ZipImportError, zi.get_code, 'b')
else:
self.assertTrue(zi.is_package('b'))
self.assertEqual(zi.get_source('b'), test_src)
self.assertEqual(zi.get_code('b').co_filename,
os.path.join(TEMP_ZIP, 'a', 'b', initfile))

sys.path.insert(0, TEMP_ZIP)
self.assertNotIn('a', sys.modules)

mod = importlib.import_module(f'a.b')
self.assertIn('a', sys.modules)
self.assertIs(sys.modules['a.b'], mod)
if initfile is None:
self.assertIsNone(mod.__file__)
else:
self.assertEqual(mod.__file__,
os.path.join(TEMP_ZIP, 'a', 'b', initfile))
self.assertEqual(len(mod.__path__), 1, mod.__path__)
self.assertEqual(mod.__path__[0], os.path.join(TEMP_ZIP, 'a', 'b'))

mod2 = importlib.import_module(f'a.b.c.d')
self.assertIn('a.b.c', sys.modules)
self.assertIn('a.b.c.d', sys.modules)
self.assertIs(sys.modules['a.b.c.d'], mod2)
self.assertIs(mod.c.d, mod2)
self.assertEqual(mod2.__file__,
os.path.join(TEMP_ZIP, 'a', 'b', 'c', 'd.py'))

def testMixedNamespacePackage(self):
# Test implicit namespace packages spread between a
# real filesystem and a zip archive.
Expand Down Expand Up @@ -535,21 +610,22 @@ def testInvalidateCaches(self):
packdir2 + "__init__" + pyc_ext: test_pyc,
packdir2 + TESTMOD + pyc_ext: test_pyc,
"spam" + pyc_ext: test_pyc}
extra_files = [packdir, packdir2]
self.makeZip(files, file_comment=b"spam")

zi = zipimport.zipimporter(TEMP_ZIP)
self.assertEqual(zi._get_files().keys(), files.keys())
self.assertEqual(sorted(zi._get_files()), sorted([*files, *extra_files]))
# Check that the file information remains accurate after reloading
zi.invalidate_caches()
self.assertEqual(zi._get_files().keys(), files.keys())
self.assertEqual(sorted(zi._get_files()), sorted([*files, *extra_files]))
# Add a new file to the ZIP archive
newfile = {"spam2" + pyc_ext: test_pyc}
files.update(newfile)
with ZipFile(TEMP_ZIP, "a", compression=self.compression) as z:
self.writeZip(z, newfile, file_comment=b"spam")
# Check that we can detect the new file after invalidating the cache
zi.invalidate_caches()
self.assertEqual(zi._get_files().keys(), files.keys())
self.assertEqual(sorted(zi._get_files()), sorted([*files, *extra_files]))
spec = zi.find_spec('spam2')
self.assertIsNotNone(spec)
self.assertIsInstance(spec.loader, zipimport.zipimporter)
Expand All @@ -567,13 +643,14 @@ def testInvalidateCachesWithMultipleZipimports(self):
packdir2 + "__init__" + pyc_ext: test_pyc,
packdir2 + TESTMOD + pyc_ext: test_pyc,
"spam" + pyc_ext: test_pyc}
extra_files = [packdir, packdir2]
self.makeZip(files, file_comment=b"spam")

zi = zipimport.zipimporter(TEMP_ZIP)
self.assertEqual(zi._get_files().keys(), files.keys())
self.assertEqual(sorted(zi._get_files()), sorted([*files, *extra_files]))
# Zipimporter for the same path.
zi2 = zipimport.zipimporter(TEMP_ZIP)
self.assertEqual(zi2._get_files().keys(), files.keys())
self.assertEqual(sorted(zi2._get_files()), sorted([*files, *extra_files]))
# Add a new file to the ZIP archive to make the cache wrong.
newfile = {"spam2" + pyc_ext: test_pyc}
files.update(newfile)
Expand All @@ -582,7 +659,7 @@ def testInvalidateCachesWithMultipleZipimports(self):
# Invalidate the cache of the first zipimporter.
zi.invalidate_caches()
# Check that the second zipimporter detects the new file and isn't using a stale cache.
self.assertEqual(zi2._get_files().keys(), files.keys())
self.assertEqual(sorted(zi2._get_files()), sorted([*files, *extra_files]))
spec = zi2.find_spec('spam2')
self.assertIsNotNone(spec)
self.assertIsInstance(spec.loader, zipimport.zipimporter)
Expand Down Expand Up @@ -638,17 +715,33 @@ def testZipImporterMethodsInSubDirectory(self):
self.assertIsNone(loader.get_source(mod_name))
self.assertEqual(loader.get_filename(mod_name), mod.__file__)

def testGetData(self):
def testGetDataExplicitDirectories(self):
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, "w") as z:
z.compression = self.compression
name = "testdata.dat"
data = bytes(x for x in range(256))
z.writestr(name, data)

zi = zipimport.zipimporter(TEMP_ZIP)
self.assertEqual(data, zi.get_data(name))
self.assertIn('zipimporter object', repr(zi))
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
z.mkdir('a')
z.mkdir('a/b')
z.mkdir('a/b/c')
data = bytes(range(256))
z.writestr('a/b/c/testdata.dat', data)
self._testGetData()

def testGetDataImplicitDirectories(self):
self.addCleanup(os_helper.unlink, TEMP_ZIP)
with ZipFile(TEMP_ZIP, 'w', compression=self.compression) as z:
data = bytes(range(256))
z.writestr('a/b/c/testdata.dat', data)
self._testGetData()

def _testGetData(self):
zi = zipimport.zipimporter(os.path.join(TEMP_ZIP, 'ignored'))
pathname = os.path.join('a', 'b', 'c', 'testdata.dat')
data = bytes(range(256))
self.assertEqual(zi.get_data(pathname), data)
self.assertEqual(zi.get_data(os.path.join(TEMP_ZIP, pathname)), data)
self.assertEqual(zi.get_data(os.path.join('a', 'b', '')), b'')
self.assertEqual(zi.get_data(os.path.join(TEMP_ZIP, 'a', 'b', '')), b'')
self.assertRaises(OSError, zi.get_data, os.path.join('a', 'b'))
self.assertRaises(OSError, zi.get_data, os.path.join(TEMP_ZIP, 'a', 'b'))

def testImporterAttr(self):
src = """if 1: # indent hack
Expand Down Expand Up @@ -742,15 +835,15 @@ def doTraceback(self, module):

s = io.StringIO()
print_tb(tb, 1, s)
self.assertTrue(s.getvalue().endswith(
self.assertEndsWith(s.getvalue(),
' def do_raise(): raise TypeError\n'
'' if support.has_no_debug_ranges() else
' ^^^^^^^^^^^^^^^\n'
))
)
else:
raise AssertionError("This ought to be impossible")

@unittest.expectedFailure # TODO: RUSTPYTHON; empty caret lines from equal col/end_col
@unittest.expectedFailure # TODO: RUSTPYTHON; empty caret lines from equal col/end_col
def testTraceback(self):
files = {TESTMOD + ".py": raise_src}
self.doTest(None, files, TESTMOD, call=self.doTraceback)
Expand Down Expand Up @@ -788,15 +881,17 @@ def testLargestPossibleComment(self):
files = {TESTMOD + ".py": test_src}
self.doTest(".py", files, TESTMOD, comment=b"c" * ((1 << 16) - 1))

@support.requires_resource('cpu')
def testZip64(self):
files = self.getZip64Files()
self.doTest(".py", files, "f6")

@support.requires_resource('cpu')
def testZip64CruftAndComment(self):
files = self.getZip64Files()
self.doTest(".py", files, "f65536", comment=b"c" * ((1 << 16) - 1))

@unittest.skip('TODO: RUSTPYTHON; (intermittent success/failures); ValueError: name="RustPython/crates/pylib/Lib/test/zipimport_data/sparse-zip64-c0-0x000000000.part" does not fit expected pattern.')
@unittest.skip("TODO: RUSTPYTHON; (intermittent success/failures); ValueError: name=\"RustPython/crates/pylib/Lib/test/zipimport_data/sparse-zip64-c0-0x000000000.part\" does not fit expected pattern.")
def testZip64LargeFile(self):
support.requires(
"largefile",
Expand Down
31 changes: 25 additions & 6 deletions Lib/zipimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import marshal # for loads
import sys # for modules
import time # for mktime
import _warnings # For warn()

__all__ = ['ZipImportError', 'zipimporter']

Expand Down Expand Up @@ -155,6 +154,8 @@ def get_data(self, pathname):
toc_entry = self._get_files()[key]
except KeyError:
raise OSError(0, '', key)
if toc_entry is None:
return b''
return _get_data(self.archive, toc_entry)


Expand Down Expand Up @@ -219,9 +220,11 @@ def load_module(self, fullname):

Deprecated since Python 3.10. Use exec_module() instead.
"""
msg = ("zipimport.zipimporter.load_module() is deprecated and slated for "
"removal in Python 3.12; use exec_module() instead")
_warnings.warn(msg, DeprecationWarning)
import warnings
warnings._deprecated("zipimport.zipimporter.load_module",
f"{warnings._DEPRECATED_MSG}; "
"use zipimport.zipimporter.exec_module() instead",
remove=(3, 15))
code, ispackage, modpath = _get_module_code(self, fullname)
mod = sys.modules.get(fullname)
if mod is None or not isinstance(mod, _module_type):
Expand Down Expand Up @@ -513,7 +516,7 @@ def _read_directory(archive):

# N.b. Here be dragons: the ordering of these is different than
# the header fields, and it's really easy to get it wrong since
# naturally-occuring zips that use all 3 are >4GB
# naturally-occurring zips that use all 3 are >4GB
if file_size == MAX_UINT32:
file_size = values.pop(0)
if data_size == MAX_UINT32:
Expand Down Expand Up @@ -546,6 +549,22 @@ def _read_directory(archive):
finally:
fp.seek(start_offset)
_bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive)

# Add implicit directories.
count = 0
for name in list(files):
while True:
i = name.rstrip(path_sep).rfind(path_sep)
if i < 0:
break
name = name[:i + 1]
if name in files:
break
files[name] = None
count += 1
if count:
_bootstrap._verbose_message('zipimport: added {} implicit directories in {!r}',
count, archive)
return files

# During bootstrap, we may need to load the encodings
Expand Down Expand Up @@ -679,7 +698,7 @@ def _unmarshal_code(self, pathname, fullpath, fullname, data):
source_bytes = _get_pyc_source(self, fullpath)
if source_bytes is not None:
source_hash = _imp.source_hash(
_bootstrap_external._RAW_MAGIC_NUMBER,
_imp.pyc_magic_number_token,
source_bytes,
)

Expand Down
Loading