Skip to content

Commit dd04dcf

Browse files
committed
Use lower-level zipimporter rather than zipfile module for importing from JAR files
1 parent eab2caf commit dd04dcf

File tree

2 files changed

+62
-42
lines changed

2 files changed

+62
-42
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -349,24 +349,58 @@ def test_java_imports():
349349
assert sun.misc.Signal is not None
350350

351351
def test_java_import_from_jar():
352-
import sys
353-
import tempfile
354-
import zipfile
355-
356-
tempname = tempfile.mktemp() + ".jar"
357-
with zipfile.ZipFile(tempname, mode="w") as z:
358-
with z.open("scriptDir/test_java_jar_import.py", mode="w") as member:
359-
member.write(b"MEMBER = 42\n")
360-
try:
361-
sys.path.append(tempname + "!scriptDir")
352+
if sys.graal_python_jython_emulation_enabled:
353+
import tempfile
354+
import zipfile
355+
356+
# import a single file with jar!prefix/
357+
tempname = tempfile.mktemp() + ".jar"
358+
with zipfile.ZipFile(tempname, mode="w") as z:
359+
with z.open("scriptDir/test_java_jar_import.py", mode="w") as member:
360+
member.write(b"MEMBER = 42\n")
361+
try:
362+
sys.path.append(tempname + "!scriptDir")
363+
try:
364+
import test_java_jar_import
365+
assert test_java_jar_import.MEMBER == 42
366+
assert test_java_jar_import.__path__ == tempname + "/scriptDir/test_java_jar_import.py"
367+
finally:
368+
sys.path.pop()
369+
finally:
370+
os.unlink(tempname)
371+
372+
# import a single file with jar!/prefix/
373+
tempname = tempfile.mktemp() + ".jar"
374+
with zipfile.ZipFile(tempname, mode="w") as z:
375+
with z.open("scriptDir/test_java_jar_import_2.py", mode="w") as member:
376+
member.write(b"MEMBER = 43\n")
362377
try:
363-
import test_java_jar_import
364-
assert test_java_jar_import.MEMBER == 42
365-
assert test_java_jar_import.__path__ == tempname + "!scriptDir/test_java_jar_import.py"
378+
sys.path.append(tempname + "!/scriptDir")
379+
try:
380+
import test_java_jar_import_2
381+
assert test_java_jar_import_2.MEMBER == 43
382+
assert test_java_jar_import_2.__path__ == tempname + "/scriptDir/test_java_jar_import_2.py"
383+
finally:
384+
sys.path.pop()
366385
finally:
367-
sys.path.pop()
368-
finally:
369-
os.unlink(tempname)
386+
os.unlink(tempname)
387+
388+
# import a package with jar!/prefix/
389+
tempname = tempfile.mktemp() + ".jar"
390+
with zipfile.ZipFile(tempname, mode="w") as z:
391+
with z.open("scriptDir/test_java_jar_pkg/__init__.py", mode="w") as member:
392+
member.write(b"MEMBER = 44\n")
393+
try:
394+
sys.path.append(tempname + "!/scriptDir")
395+
try:
396+
import test_java_jar_pkg
397+
assert test_java_jar_pkg.MEMBER == 44
398+
assert test_java_jar_pkg.__path__ == tempname + "/scriptDir/test_java_jar_pkg/__init__.py"
399+
finally:
400+
sys.path.pop()
401+
finally:
402+
os.unlink(tempname)
403+
370404

371405
def test_java_exceptions():
372406
if sys.graal_python_jython_emulation_enabled:

graalpython/lib-graalpython/java.py

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -166,46 +166,32 @@ def find_spec(self, fullname, path, target=None):
166166

167167
if sys.graal_python_jython_emulation_enabled:
168168
class JarImportLoader:
169-
def __init__(self, jarpath, zippath):
170-
self.jarpath = jarpath
171-
self.zippath = zippath
169+
def __init__(self, code):
170+
self.code = code
172171

173172
def create_module(self, spec):
174173
newmod = _frozen_importlib._new_module(spec.name)
175-
newmod.__path__ = "%s!%s" % (self.jarpath, self.zippath)
174+
newmod.__path__ = self.code.co_filename
176175
return newmod
177176

178177
def exec_module(self, module):
179-
import zipfile
180-
with zipfile.ZipFile(self.jarpath) as z:
181-
code = z.read(self.zippath)
182-
exec(code, module.__dict__)
178+
exec(self.code, module.__dict__)
183179

184180

185181
class JarImportFinder:
186182
def __init__(self):
187-
self.namelist_cache = {}
183+
self.zipimport = __import__("zipimport")
188184

189185
def find_spec(self, fullname, path, target=None):
190186
for path in sys.path:
191187
if ".jar!" in path:
192-
jarfile, _, zippath = path.partition("!")
193-
file_to_find = "%s/%s.py" % (zippath, fullname.replace(".", "/"))
194-
init_to_find = "%s/%s/__init__.py" % (zippath, fullname.replace(".", "/"))
195-
old_mtime, namelist = self.namelist_cache.get(jarfile, (None, None))
196-
try:
197-
mtime = posix.stat(jarfile).st_mtime
198-
except OSError:
199-
mtime = -1
200-
if namelist is None or mtime > old_mtime:
201-
import zipfile
202-
with zipfile.ZipFile(jarfile) as z:
203-
namelist = z.namelist()
204-
self.namelist_cache[jarfile] = (mtime, namelist)
205-
if file_to_find in namelist:
206-
return _frozen_importlib.ModuleSpec(fullname, JarImportLoader(jarfile, file_to_find), is_package=False)
207-
elif init_to_find in namelist:
208-
return _frozen_importlib.ModuleSpec(fullname, JarImportLoader(jarfile, init_to_find), is_package=True)
188+
zipimport_path = path.replace(".jar!/", ".jar/").replace(".jar!", ".jar/")
189+
zipimporter = self.zipimport.zipimporter(zipimport_path)
190+
if zipimporter.find_module(fullname):
191+
if zipimporter.is_package(fullname):
192+
return _frozen_importlib.ModuleSpec(fullname, JarImportLoader(zipimporter.get_code(fullname)), is_package=True)
193+
else:
194+
return _frozen_importlib.ModuleSpec(fullname, JarImportLoader(zipimporter.get_code(fullname)), is_package=False)
209195

210196

211197
sys.meta_path.append(JarImportFinder())

0 commit comments

Comments
 (0)