From: Jason R. Coombs Date: Tue, 24 Sep 2024 17:19:43 +0000 (-0400) Subject: [3.12] gh-121735: Fix module-adjacent references in zip files (gh-123037) (#124011) X-Git-Tag: v3.12.7~49 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c60d97805f7569399caff266ba53d53550564e26;p=thirdparty%2FPython%2Fcpython.git [3.12] gh-121735: Fix module-adjacent references in zip files (gh-123037) (#124011) --- diff --git a/Lib/importlib/resources/readers.py b/Lib/importlib/resources/readers.py index c3cdf769cbec..8e2d8e8250bd 100644 --- a/Lib/importlib/resources/readers.py +++ b/Lib/importlib/resources/readers.py @@ -31,8 +31,10 @@ class FileReader(abc.TraversableResources): class ZipReader(abc.TraversableResources): def __init__(self, loader, module): - _, _, name = module.rpartition('.') - self.prefix = loader.prefix.replace('\\', '/') + name + '/' + self.prefix = loader.prefix.replace('\\', '/') + if loader.is_package(module): + _, _, name = module.rpartition('.') + self.prefix += name + '/' self.archive = loader.archive def open_resource(self, resource): diff --git a/Lib/test/test_importlib/resources/test_files.py b/Lib/test/test_importlib/resources/test_files.py index 26c8b04e44c3..038aac0a3fe7 100644 --- a/Lib/test/test_importlib/resources/test_files.py +++ b/Lib/test/test_importlib/resources/test_files.py @@ -108,6 +108,42 @@ class ImplicitContextFilesTests(SiteDir, unittest.TestCase): _path.build(spec, self.site_dir) assert importlib.import_module('somepkg').val == 'resources are the best' + def test_implicit_files_zip_submodule(self): + """ + Special test for gh-121735 for Python 3.12. + """ + import os + import zipfile + + def create_zip_from_directory(source_dir, zip_filename): + with zipfile.ZipFile(zip_filename, 'w') as zipf: + for root, _, files in os.walk(source_dir): + for file in files: + file_path = os.path.join(root, file) + # Ensure files are at the root + arcname = os.path.relpath(file_path, source_dir) + zipf.write(file_path, arcname) + + set_val = textwrap.dedent( + """ + import importlib.resources as res + val = res.files().joinpath('res.txt').read_text(encoding='utf-8') + """ + ) + spec = { + 'somepkg': { + '__init__.py': set_val, + 'submod.py': set_val, + 'res.txt': 'resources are the best', + }, + } + build_dir = self.fixtures.enter_context(os_helper.temp_dir()) + _path.build(spec, build_dir) + zip_file = os.path.join(self.site_dir, 'thepkg.zip') + create_zip_from_directory(build_dir, zip_file) + self.fixtures.enter_context(import_helper.DirsOnSysPath(zip_file)) + assert importlib.import_module('somepkg.submod').val == 'resources are the best' + if __name__ == '__main__': unittest.main() diff --git a/Lib/zipimport.py b/Lib/zipimport.py index a7333a4c4906..7669abd6c472 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -254,17 +254,9 @@ class zipimporter(_bootstrap_external._LoaderBasics): def get_resource_reader(self, fullname): - """Return the ResourceReader for a package in a zip file. - - If 'fullname' is a package within the zip file, return the - 'ResourceReader' object for the package. Otherwise return None. - """ - try: - if not self.is_package(fullname): - return None - except ZipImportError: - return None + """Return the ResourceReader for a module in a zip file.""" from importlib.readers import ZipReader + return ZipReader(self, fullname) diff --git a/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst b/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst new file mode 100644 index 000000000000..e10b2e760bc0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-15-09-45-34.gh-issue-121735._1q0qf.rst @@ -0,0 +1,3 @@ +When working with zip archives, importlib.resources now properly honors +module-adjacent references (e.g. ``files(pkg.mod)`` and not just +``files(pkg)``).