From: <pj...@us...> - 2008-04-16 18:40:02
|
Revision: 4349 http://jython.svn.sourceforge.net/jython/?rev=4349&view=rev Author: pjenvey Date: 2008-04-16 11:39:50 -0700 (Wed, 16 Apr 2008) Log Message: ----------- include the jarjar'd asm ClassReader in our jar and use it to get the real class name of $py.class files before importing them. Allows us to import misnamed/mislabeled $py.class files the import statement has been hacking around this by recompiling the .py (if it exists) when it happens. more importantly imp.load_module (and load_compiled when we support it) don't and shouldn't workaround this, instead load_module has been throwing NoClassDefFoundErrors Modified Paths: -------------- trunk/jython/Lib/test/test_chdir.py trunk/jython/build.xml trunk/jython/src/org/python/core/BytecodeLoader.java Added Paths: ----------- trunk/jython/Lib/test/test_import_jy.py Modified: trunk/jython/Lib/test/test_chdir.py =================================================================== --- trunk/jython/Lib/test/test_chdir.py 2008-04-15 04:11:00 UTC (rev 4348) +++ trunk/jython/Lib/test/test_chdir.py 2008-04-16 18:39:50 UTC (rev 4349) @@ -369,17 +369,19 @@ self.assertEqual(mod.__file__, self.mod_name + COMPILED_SUFFIX) def test_compile_dest(self): - # XXX: py_compile with a destination is a little broken (when - # you go to import the file, it raises an error because the - # class is mislabeled in regard to the filename). Just test the - # destination for now py_compile.compile(self.basename1, self.basename1[:-3] + 'chdir_test' + COMPILED_SUFFIX) self.assert_(os.path.exists(self.filename1[:-3] + 'chdir_test' + COMPILED_SUFFIX)) + mod_name = self.mod_name + 'chdir_test' + __import__(mod_name) + self.assert_(mod_name in sys.modules) + mod = sys.modules[mod_name] + self.assertEqual(mod.__file__, mod_name + COMPILED_SUFFIX) + class SubprocessTestCase(BaseChdirTestCase): TEST_DIRS = 2 Added: trunk/jython/Lib/test/test_import_jy.py =================================================================== --- trunk/jython/Lib/test/test_import_jy.py (rev 0) +++ trunk/jython/Lib/test/test_import_jy.py 2008-04-16 18:39:50 UTC (rev 4349) @@ -0,0 +1,104 @@ +"""Misc. import tests + +Made for Jython. +""" +import imp +import os +import shutil +import sys +import tempfile +import unittest +from test import test_support +from test_chdir import read, safe_mktemp, COMPILED_SUFFIX + +class MislabeledImportTestCase(unittest.TestCase): + + def setUp(self): + self.dir = tempfile.mkdtemp() + self.orig_cwd = os.getcwd() + os.chdir(self.dir) + self.orig_syspath = sys.path + sys.path.append('') + + def tearDown(self): + shutil.rmtree(self.dir) + os.chdir(self.orig_cwd) + sys.path = self.orig_syspath + + def test_renamed_bytecode(self): + source = safe_mktemp(dir=self.dir, suffix='.py') + fp = open(source, 'w') + fp.write("test = 'imported'") + fp.close() + + module = os.path.basename(source)[:-3] + compiled = module + COMPILED_SUFFIX + # Compile to bytecode + module_obj = __import__(module) + self.assertEquals(module_obj.test, 'imported') + self.assert_(os.path.exists(compiled)) + + # Rename the bytecode + compiled_moved = safe_mktemp(dir=self.dir, suffix=COMPILED_SUFFIX) + os.rename(compiled, compiled_moved) + + # Ensure we can still import the renamed bytecode + moved_module = os.path.basename(compiled_moved)[:-len(COMPILED_SUFFIX)] + module_obj = __import__(moved_module) + self.assertEquals(module_obj.__file__, os.path.basename(compiled_moved)) + self.assertEquals(module_obj.test, 'imported') + + def test_dunder_init(self): + os.mkdir('foo') + + # typical import: foo.__init__$py.class is actually compiled + # with a class name of foo + init = os.path.join('foo', '__init__.py') + fp = open(init, 'w') + fp.write("bar = 'test'") + fp.close() + module_obj = __import__('foo') + self.assertEquals(module_obj.__file__, init) + self.assertEquals(module_obj.bar, 'test') + + init_compiled = init[:-3] + COMPILED_SUFFIX + self.assert_(os.path.exists(init_compiled)) + bytecode = read(init_compiled) + + # trigger an abnormal import of foo.__init__; ask for it by the + # mismatched __init__ name + fp = open(os.path.join('foo', 'test.py'), 'w') + fp.write("import __init__; baz = __init__.bar + 'test'; " + "init_file = __init__.__file__") + fp.close() + module_obj = __import__('foo.test') + self.assertEquals(module_obj.test.baz, 'testtest') + # XXX: Jython's import has a bug where it doesn't use the + # $py.class filename when it exists along with the .py file + if sys.platform.startswith('java'): + self.assertEqual(module_obj.test.init_file, + os.path.join('foo', '__init__.py')) + else: + self.assertEqual(module_obj.test.init_file, + os.path.join('foo', '__init__' + COMPILED_SUFFIX)) + + # Ensure a recompile of __init__$py.class wasn't triggered to + # satisfy the abnormal import + self.assertEquals(bytecode, read(init_compiled), + 'bytecode was recompiled') + + # Ensure load_module can still load it as foo (doesn't + # recompile) + module_obj = imp.load_module('foo', *imp.find_module('foo')) + self.assertEquals(module_obj.bar, 'test') + + # Again ensure we didn't recompile + self.assertEquals(bytecode, read(init_compiled), + 'bytecode was recompiled') + + +def test_main(): + test_support.run_unittest(MislabeledImportTestCase) + +if __name__ == '__main__': + test_main() Modified: trunk/jython/build.xml =================================================================== --- trunk/jython/build.xml 2008-04-15 04:11:00 UTC (rev 4348) +++ trunk/jython/build.xml 2008-04-16 18:39:50 UTC (rev 4349) @@ -491,6 +491,9 @@ <jar destfile="${dist.dir}/jython.jar"> <fileset dir="${compile.dir}"/> <fileset dir="${exposed.dir}"/> + <fileset dir="${jarjar.dir}"> + <include name="org/python/objectweb/asm/ClassReader.class" /> + </fileset> <manifest> <attribute name="Main-Class" value="org.python.util.jython" /> <attribute name="Built-By" value="${user.name}" /> Modified: trunk/jython/src/org/python/core/BytecodeLoader.java =================================================================== --- trunk/jython/src/org/python/core/BytecodeLoader.java 2008-04-15 04:11:00 UTC (rev 4348) +++ trunk/jython/src/org/python/core/BytecodeLoader.java 2008-04-16 18:39:50 UTC (rev 4349) @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.List; +import org.python.objectweb.asm.ClassReader; + /** * Utility class for loading of compiled python modules and java classes defined in python modules. */ @@ -98,6 +100,18 @@ } public Class<?> loadClassFromBytes(String name, byte[] data) { + if (name.endsWith("$py")) { + try { + // Get the real class name: we might request a 'bar' + // Jython module that was compiled as 'foo.bar', or + // even 'baz.__init__' which is compiled as just 'baz' + ClassReader cr = new ClassReader(data); + name = cr.getClassName().replace('/', '.'); + } catch (RuntimeException re) { + // Probably an invalid .class, fallback to the + // specified name + } + } Class<?> c = defineClass(name, data, 0, data.length, getClass().getProtectionDomain()); resolveClass(c); Compiler.compileClass(c); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |