Jython: Packing several .py on .jar, problem importing .py modules within the .jar
Gubatron
gubatron at gmail.com
Wed Dec 3 13:01:54 EST 2008
cont...
Take in consideration
/** Hashtable of URLClassLoaders for each of the jars loaded */
private Hashtable<String, URLClassLoader> classLoaders;
Here's an example:
org.python.core.PySystemState pySys = new
org.python.core.PySystemState();
//classLoaders is a set that refers to a bunch
of URLClassLoader objects
pySys.setClassLoader(((URLClassLoader)
classLoaders.get(jarFile)));
//We also have to pass the jar to JYTHON_PATH
(sys.path)
//so that it can properly import inner python
modules.
pySys.path.insert(0,new PyString(jarFile));
//We pass the PythonInterpreter the modified
PySystemState
PythonInterpreter i = new PythonInterpreter
(null, pySys);
i.exec(pythonScriptName);
Here's my method to create a classLoader that has a jarFile in its
classpath:
/**
* Adds a given Jar to the Classpath.
* Jython uses both classloaders, and it's JYTHONPATH (sys.path)
* The classloaders help it find Java classes, in this case inside
the jar
* that contains the plugin.
*
* @param jarFile
*
* Where jarFile is the path (String) to the jarFile.
*
* I won't delete it though, in case it might be needed to load
resources from
* the jar. However, I believe the adition to the sys.path of jython
will be enough.
*/
public void addJar2Classpath(String jarFile) throws Exception {
if (jarFile == null)
throw new Exception("PluginLoader.addJar2Classpath() - the jar file
path can't be null");
File f = new File(jarFile);
if (!f.exists()) {
LOG.error("Jar doesn't exist ("+jarFile+")");
throw new Exception("PluginLoader.addJar2Classpath() - The jar file
doesn't exist ("+ jarFile +")");
}
URL jarURL = null;
try {
jarURL = new URL("jar:file:"+jarFile+"!/");
//jarURL = f.toURI().toURL();
LOG.info("The jar as an url " + jarURL);
} catch (Exception e) {
LOG.error("Bad URL for jar ("+jarFile+"):\n"+e.toString()
+" ("+jarURL+")\n");
return;
}
if (loadedJar(jarURL)) {
LOG.info("Jar was already loaded ("+jarURL+")");
return;
}
synchronized (classLoaders) {
getLoadedJars().add((URL) jarURL);
}
//Create a new class loader for this jar.
classLoaders.put(jarFile, URLClassLoader.newInstance(new URL[]
{jarURL}));
LOG.info("Jar loaded ("+jarURL+")");
} //addJar2Classpath
So if we had a Jar like this:
M Filemode Length Date Time File
- ---------- -------- ----------- --------
-------------------------------------
drwxrwxrwx 0 3-Dec-2008 12:46:22 meta-inf/
-rw-rw-rw- 71 3-Dec-2008 12:46:22 meta-inf/manifest.mf
drwxrwxrwx 0 3-Dec-2008 12:46:22 twoScriptsTest/com/
-rw-rw-rw- 491 3-Dec-2008 12:46:22 twoScriptsTest/com/
HelloFromJar.class
drwxrwxrwx 0 3-Dec-2008 12:46:18 twoScriptsTest/guba/
-rw-rw-rw- 0 3-Dec-2008 06:24:22 twoScriptsTest/guba/
__init__.py
-rw-rw-rw- 959 3-Dec-2008 12:46:18 twoScriptsTest/guba/
test.py
-rw-rw-rw- 124 2-Dec-2008 17:50:56 twoScriptsTest/guba/
pleaseWork.py
-rw-rw-rw- 0 3-Dec-2008 12:29:56 twoScriptsTest/
__init__.py
- ---------- -------- ----------- --------
-------------------------------------
When we executed:
i.exec("from guba import test")
if test.py had this code, it'd work perfectly:
#Import and use the Java Object inside the jar
from com import HelloFromJar
h = HelloFromJar()
h.sayHello()
#Import the other python module inside the jar
from pleaseWork import echo
echo("FrostWire")
NOTE: It's very important that you have the __init__.py on the folders
otherwise Jython won't find the modules.
On Dec 3, 12:54 pm, Gubatron <gubat... at gmail.com> wrote:
> I've managed to solve this problem.
>
> I can now run a python script that lives inside a Jar. The python
> script is now able to import other scripts within the same jar, and
> it's also able to import java classes that live within the jar.
>
> The problem was solved by giving the Jython Interpreter the proper
> initialization. This entails:
>
> - Giving it a class loader that has put the Jar on it's class path
> - Adding the path of the jar to the interpreter's sys.path
>
> Here's an example:
>
> org.python.core.PySystemState pySys = new
> org.python.core.PySystemState();
> pySys.setClassLoader(((URLClassLoader) classLoaders.get(jarFile)));
>
> //We also have to pass the jar to JYTHON_PATH (sys.path)
> //so that it can properly import inner python modules.
> pySys.path.insert(0,new PyString(jarFile));
>
> //We pass the PythonInterpreter the modified PySystemState
> PythonInterpreter i = new PythonInterpreter(null, pySys);
> i.exec(pythonScriptName);
>
> On Dec 3, 6:31 am, Gubatron <gubat... at gmail.com> wrote:
>
> > Hello all,
>
> > I've a problem with Jython and importing .py inside a jar.
>
> > I'm putting .class and .py files inside .jar files.
>
> > myjar.jar
> > MyJar\SomeClass.class
> > MyJar\main.py
> > MyJar\otherModule.py
>
> > So I add the myjar.jar to Jython's sys.path
>
> > org.python.core.PySystemState pySys = new
> > org.python.core.PySystemState();
> > pySys.path.insert(0,new PyString("/path/to/myjar.jar"));
>
> > and execute main.py
>
> > //We pass the PythonInterpreter the modified PySystemState
> > PythonInterpreter i = new PythonInterpreter(null, pySys);
>
> > //Find the entry in the jar for the python file and execute it.
> > //It should be able to find any resource inside the jar.
> > JarFile jFile = new JarFile("/path/to/myjar.jar");
> > ZipEntry zipEntry = jFile.getEntry("MyJar/main.py");
>
> > InputStream pythonInputStream =
> > jFile.getInputStream(zipEntry);
> > i.execfile(pythonInputStream);
>
> > main.py will execute fine, it'll be able to do
>
> > from MyJar import SomeClass
>
> > with no problem
>
> > However, If I try to import the other .py in the same jar, it won't
> > find it:
>
> > from otherModule import *
>
> > or
>
> > from MyJar.otherModule import *
>
> > I always get this:
>
> > ImportError: no module named otherModule
>
> > at org.python.core.Py.ImportError(Unknown Source)
> > at org.python.core.imp.import_first(Unknown Source)
> > at org.python.core.imp.import_name(Unknown Source)
> > at org.python.core.imp.importName(Unknown Source)
> > at org.python.core.ImportFunction.load(Unknown Source)
> > at org.python.core.ImportFunction.__call__(Unknown Source)
> > at org.python.core.PyObject.__call__(Unknown Source)
> > at org.python.core.__builtin__.__import__(Unknown Source)
> > at org.python.core.imp.importFromAs(Unknown Source)
> > at org.python.core.imp.importFrom(Unknown Source)
> > at org.python.pycode._pyx1.f$0(<iostream>:26)
> > at org.python.pycode._pyx1.call_function(<iostream>)
> > at org.python.core.PyTableCode.call(Unknown Source)
> > at org.python.core.PyCode.call(Unknown Source)
> > at org.python.core.Py.runCode(Unknown Source)
> > at org.python.util.PythonInterpreter.execfile(Unknown Source)
>
> > I've tried adding more paths to sys.path, with no luck:
>
> > pySys.path.insert(0,new PyString("/path/to/myjar.jar/MyJar"));
> > pySys.path.insert(0,new PyString("file:jar:/path/to/myjar.jar!"));
>
> > and nothing works, any ideas would help. I know this has to work,
> > because I previously had a problem where I couldn't do
>
> > import os
>
> > and then I added the "Lib/" folder inside jython.jar and now I'm able
> > to import all those standard jython modules, so, somehow, jython is
> > able to import .py within a .jar, help would be very much appreciated.
>
> > Angel Leon
>
>
More information about the Python-list
mailing list