Skip to content

Commit

Permalink
[3.12] gh-121735: Fix module-adjacent references in zip files (gh-123037
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco authored Sep 24, 2024
1 parent 10cf0b8 commit c60d978
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 12 deletions.
6 changes: 4 additions & 2 deletions Lib/importlib/resources/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ def files(self):

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):
Expand Down
36 changes: 36 additions & 0 deletions Lib/test/test_importlib/resources/test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,42 @@ def test_implicit_files(self):
_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()
12 changes: 2 additions & 10 deletions Lib/zipimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,9 @@ def load_module(self, fullname):


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)


Expand Down
Original file line number Diff line number Diff line change
@@ -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)``).

0 comments on commit c60d978

Please sign in to comment.