diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index dccbec52aa731e..2e499f5705a960 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -176,7 +176,15 @@ def _iter_file_finder_modules(importer, prefix=''): from zipimport import zipimporter def iter_zipimport_modules(importer, prefix=''): - dirlist = sorted(zipimport._zip_directory_cache[importer.archive]) + """Iterate through the modules available within a zipfile + + For each module found in the zipfile, a tuple containing the module's + name and boolean indicating whether the module is a package + gets yielded. + + It is assumed that importer is an instance of zipimport.zipimporter. + """ + dirlist = sorted(zipimporter(importer.archive)._get_files()) _prefix = importer.prefix plen = len(_prefix) yielded = {} diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index d095f440a99f63..2566ccca62cb10 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -522,6 +522,51 @@ def test_mixed_namespace(self): del sys.modules['foo.bar'] del sys.modules['foo.baz'] + def test_iter_zipimport_modules(self): + with zipfile.ZipFile( + tempfile.NamedTemporaryFile(suffix='.zip', delete=False), + mode='w' + ) as tmp_file_zip: + tmp_file_zip.writestr( + 'foo.py', + 'print("foot")' + ) + tmp_file_zip.writestr( + 'bar/__init__.py', + 'print("bar")' + ) + + module_zip = pkgutil.zipimporter(tmp_file_zip.filename) + + self.assertIn(('foo', False), pkgutil.iter_zipimport_modules(module_zip, prefix='')) + self.assertIn(('bar', True), pkgutil.iter_zipimport_modules(module_zip, prefix='')) + + # Cleanup + os.remove(tmp_file_zip.filename) + + def test_iter_zipimport_modules_invalidate_caches(self): + with zipfile.ZipFile( + tempfile.NamedTemporaryFile(suffix='.zip', delete=False), + mode='w' + ) as tmp_file_zip: + tmp_file_zip.writestr( + 'foo.py', + 'print("foo")' + ) + tmp_file_zip.writestr( + 'bar/__init__.py', + 'print("bar")' + ) + + module_zip = pkgutil.zipimporter(tmp_file_zip.filename) + module_zip.invalidate_caches() + + self.assertIn(('foo', False), pkgutil.iter_zipimport_modules(module_zip, prefix='')) + self.assertIn(('bar', True), pkgutil.iter_zipimport_modules(module_zip, prefix='')) + + # Cleanup + os.remove(tmp_file_zip.filename) + # XXX: test .pkg files diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-07-13-15-58-52.gh-issue-121342.NyuGnr.rst b/Misc/NEWS.d/next/Core and Builtins/2024-07-13-15-58-52.gh-issue-121342.NyuGnr.rst new file mode 100644 index 00000000000000..05c1e09e562e3b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-07-13-15-58-52.gh-issue-121342.NyuGnr.rst @@ -0,0 +1,2 @@ +Fix ``pkgutil.iter_zipimport_modules`` when called on an invalidated cache. +Patch by Andreas Stocker.