Skip to content

Commit 2618585

Browse files
Fix zipimport invalidate caches
1 parent 385b5d6 commit 2618585

File tree

2 files changed

+32
-20
lines changed

2 files changed

+32
-20
lines changed

Lib/test/test_zipimport.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -520,10 +520,10 @@ def testInvalidateCaches(self):
520520
z.writestr(zinfo, data)
521521

522522
zi = zipimport.zipimporter(TEMP_ZIP)
523-
self.assertEqual(zi._files.keys(), files.keys())
523+
self.assertEqual(zi._get_files().keys(), files.keys())
524524
# Check that the file information remains accurate after reloading
525525
zi.invalidate_caches()
526-
self.assertEqual(zi._files.keys(), files.keys())
526+
self.assertEqual(zi._get_files().keys(), files.keys())
527527
# Add a new file to the ZIP archive
528528
newfile = {"spam2" + pyc_ext: (NOW, test_pyc)}
529529
files.update(newfile)
@@ -535,14 +535,14 @@ def testInvalidateCaches(self):
535535
z.writestr(zinfo, data)
536536
# Check that we can detect the new file after invalidating the cache
537537
zi.invalidate_caches()
538-
self.assertEqual(zi._files.keys(), files.keys())
538+
self.assertEqual(zi._get_files().keys(), files.keys())
539539
spec = zi.find_spec('spam2')
540540
self.assertIsNotNone(spec)
541541
self.assertIsInstance(spec.loader, zipimport.zipimporter)
542542
# Check that the cached data is removed if the file is deleted
543543
os.remove(TEMP_ZIP)
544544
zi.invalidate_caches()
545-
self.assertFalse(zi._files)
545+
self.assertFalse(zi._get_files())
546546
self.assertIsNone(zipimport._zip_directory_cache.get(zi.archive))
547547
self.assertIsNone(zi.find_spec("name_does_not_matter"))
548548

Lib/zipimport.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def __init__(self, path):
9393
except KeyError:
9494
files = _read_directory(path)
9595
_zip_directory_cache[path] = files
96-
self._files = files
96+
self._cache_is_valid = True
9797
self.archive = path
9898
# a prefix directory following the ZIP file path.
9999
self.prefix = _bootstrap_external._path_join(*prefix[::-1])
@@ -152,7 +152,7 @@ def get_data(self, pathname):
152152
key = pathname[len(self.archive + path_sep):]
153153

154154
try:
155-
toc_entry = self._files[key]
155+
toc_entry = self._get_files()[key]
156156
except KeyError:
157157
raise OSError(0, '', key)
158158
return _get_data(self.archive, toc_entry)
@@ -189,7 +189,7 @@ def get_source(self, fullname):
189189
fullpath = f'{path}.py'
190190

191191
try:
192-
toc_entry = self._files[fullpath]
192+
toc_entry = self._get_files()[fullpath]
193193
except KeyError:
194194
# we have the module, but no source
195195
return None
@@ -268,14 +268,26 @@ def get_resource_reader(self, fullname):
268268
return ZipReader(self, fullname)
269269

270270

271-
def invalidate_caches(self):
272-
"""Reload the file data of the archive path."""
271+
def _get_files(self):
272+
"""Return the files within the archive path."""
273+
if not self._cache_is_valid:
274+
try:
275+
_zip_directory_cache[self.archive] = _read_directory(self.archive)
276+
except ZipImportError:
277+
_zip_directory_cache.pop(self.archive, None)
278+
self._cache_is_valid = True
279+
273280
try:
274-
self._files = _read_directory(self.archive)
275-
_zip_directory_cache[self.archive] = self._files
276-
except ZipImportError:
277-
_zip_directory_cache.pop(self.archive, None)
278-
self._files = {}
281+
files = _zip_directory_cache[self.archive]
282+
except KeyError:
283+
files = {}
284+
285+
return files
286+
287+
288+
def invalidate_caches(self):
289+
"""Invalidates the cache of file data of the archive path."""
290+
self._cache_is_valid = False
279291

280292

281293
def __repr__(self):
@@ -305,15 +317,15 @@ def _is_dir(self, path):
305317
# of a namespace package. We test by seeing if the name, with an
306318
# appended path separator, exists.
307319
dirpath = path + path_sep
308-
# If dirpath is present in self._files, we have a directory.
309-
return dirpath in self._files
320+
# If dirpath is present in self._get_files(), we have a directory.
321+
return dirpath in self._get_files()
310322

311323
# Return some information about a module.
312324
def _get_module_info(self, fullname):
313325
path = _get_module_path(self, fullname)
314326
for suffix, isbytecode, ispackage in _zip_searchorder:
315327
fullpath = path + suffix
316-
if fullpath in self._files:
328+
if fullpath in self._get_files():
317329
return ispackage
318330
return None
319331

@@ -656,7 +668,7 @@ def _get_mtime_and_size_of_source(self, path):
656668
# strip 'c' or 'o' from *.py[co]
657669
assert path[-1:] in ('c', 'o')
658670
path = path[:-1]
659-
toc_entry = self._files[path]
671+
toc_entry = self._get_files()[path]
660672
# fetch the time stamp of the .py file for comparison
661673
# with an embedded pyc time stamp
662674
time = toc_entry[5]
@@ -676,7 +688,7 @@ def _get_pyc_source(self, path):
676688
path = path[:-1]
677689

678690
try:
679-
toc_entry = self._files[path]
691+
toc_entry = self._get_files()[path]
680692
except KeyError:
681693
return None
682694
else:
@@ -692,7 +704,7 @@ def _get_module_code(self, fullname):
692704
fullpath = path + suffix
693705
_bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2)
694706
try:
695-
toc_entry = self._files[fullpath]
707+
toc_entry = self._get_files()[fullpath]
696708
except KeyError:
697709
pass
698710
else:

0 commit comments

Comments
 (0)