10000 [3.12] gh-121735: Fix module-adjacent references in zip files (gh-123… · python/cpython@c60d978 · GitHub
[go: up one dir, main page]

Skip to content

Commit c60d978

Browse files
authored
[3.12] gh-121735: Fix module-adjacent references in zip files (gh-123037) (#124011)
1 parent 10cf0b8 commit c60d978

File tree

4 files changed

+45
-12
lines changed

4 files changed

+45
-12
lines changed

Lib/importlib/resources/readers.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ def files(self):
3131

3232
class ZipReader(abc.TraversableResources):
3333
def __init__(self, loader, module):
34-
_, _, name = module.rpartition('.')
35-
self.prefix = loader.prefix.replace('\\', '/') + name + '/'
34+
self.prefix = loader.prefix.replace('\\', '/')
35+
if loader.is_package(module):
36+
_, _, name = module.rpartition('.')
37+
self.prefix += name + '/'
3638
self.archive = loader.archive
3739

3840
def open_resource(self, resource):

Lib/test/test_importlib/resources/test_files.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,42 @@ def test_implicit_files(self):
108108
_path.build(spec, self.site_dir)
109109
assert importlib.import_module('somepkg').val == 'resources are the best'
110110

111+
def test_implicit_files_zip_submodule(self):
112+
"""
113+
Special test for gh-121735 for Python 3.12.
114+
"""
115+
import os
116+
import zipfile
117+
118+
def create_zip_from_directory(source_dir, zip_filename):
119+
with zipfile.ZipFile(zip_filename, 'w') as zipf:
120+
for root, _, files in os.walk(source_dir):
121+
for file in files:
122+
file_path = os.path.join(root, file)
123+
# Ensure files are at the root
124+
arcname = os.path.relpath(file_path, source_dir)
125+
zipf.write(file_path, arcname)
126+
127+
set_val = textwrap.dedent(
128+
"""
129+
import importlib.resources as res
130+
val = res.files().joinpath('res.txt').read_text(encoding='utf-8')
131+
"""
132+
)
133+
spec = {
134+
'somepkg': {
135+
'__init__.py': set_val,
136+
'submod.py': set_val,
137+
'res.txt': 'resources are the best',
138+
},
139+
}
140+
build_dir = self.fixtures.enter_context(os_helper.temp_dir())
141+
_path.build(spec, build_dir)
142+
zip_file = os.path.join(self.site_dir, 'thepkg.zip')
143+
create_zip_from_directory(build_dir, zip_file)
144+
self.fixtures.enter_context(import_helper.DirsOnSysPath(zip_file))
145+
assert importlib.import_module('somepkg.submod').val == 'resources are the best'
146+
111147

112148
if __name__ == '__main__':
113149
unittest.main()

Lib/zipimport.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -254,17 +254,9 @@ def load_module(self, fullname):
254254

255255

256256
def get_resource_reader(self, fullname):
257-
"""Return the ResourceReader for a package in a zip file.
258-
259-
If 'fullname' is a package within the zip file, return the
260-
'ResourceReader' object for the package. Otherwise return None.
261-
"""
262-
try:
263-
if not self.is_package(fullname):
264-
return None
265-
except ZipImportError:
266-
return None
257+
"""Return the ResourceReader for a module in a zip file."""
267258
from importlib.readers import ZipReader
259+
268260
return ZipReader(self, fullname)
269261

270262

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When working with zip archives, importlib.resources now properly honors
2+
module-adjacent references (e.g. ``files(pkg.mod)`` and not just
3+
``files(pkg)``).

0 commit comments

Comments
 (0)
0