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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy