Distributing my Python scripts as JAR files with Jython?

The best current techniques for distributing your Python files in a jar are detailed in this article on Jython’s wiki: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

For your case, I think you would want to take the jython.jar file that you get when you install Jython and zip the Jython Lib directory into it, then zip your .py files in, and then add a __run__.py file with your startup logic (this file is treated specially by Jython and will be the file executed when you call the jar with “java -jar”).

This process is definitely more complicated then in ought to be, and so we (the Jython developers) need to come up with a nice tool that will automate these tasks, but for now these are the best methods. Below I’m copying the recipe at the bottom of the above article (modified slightly to fit your problem description) to give you a sense of the solution.

Create the basic jar:

$ cd $JYTHON_HOME
$ cp jython.jar jythonlib.jar
$ zip -r jythonlib.jar Lib

Add other modules to the jar:

$ cd $MY_APP_DIRECTORY
$ cp $JYTHON_HOME/jythonlib.jar myapp.jar
$ zip myapp.jar Lib/showobjs.py
# Add path to additional jar file.
$ jar ufm myapp.jar othermanifest.mf

Add the __run__.py module:

# Copy or rename your start-up script, removing the "__name__  == '__main__'" check.
$ cp mymainscript.py __run__.py
# Add your start-up script (__run__.py) to the jar.
$ zip myapp.jar __run__.py
# Add path to main jar to the CLASSPATH environment variable.
$ export CLASSPATH=/path/to/my/app/myapp.jar:$CLASSPATH

On MS Windows, that last line, setting the CLASSPATH environment variable, would look something like this:

set CLASSPATH=C:\path\to\my\app\myapp.jar;%CLASSPATH%

Or, again on MS Windows, use the Control Panel and the System properties to set the CLASSPATH environment variable.

Run the application:

$ java -jar myapp.jar mymainscript.py arg1 arg2

Or, if you have added your start-up script to the jar, use one of the following:

$ java org.python.util.jython -jar myapp.jar arg1 arg2
$ java -cp myapp.jar org.python.util.jython -jar myapp.jar arg1 arg2
$ java -jar myapp.jar -jar myapp.jar arg1 arg2

The double -jar is kind of annoying, so if you want to avoid that and get the more pleasing:

$ java -jar myapp.jar arg1

You’ll have to do a bit more work until we get something like this into a future Jython [Update: JarRunner is part of Jython 2.5.1]. Here is some Java code that looks for the __run__.py automatically, and runs it. Note that this is my first try at this class. Let me know if it needs improvement!

package org.python.util;

import org.python.core.imp;
import org.python.core.PySystemState;

public class JarRunner {

    public static void run(String[] args) {
        final String runner = "__run__";
        String[] argv = new String[args.length + 1];
        argv[0] = runner;
        System.arraycopy(args, 0, argv, 1, args.length);
        PySystemState.initialize(PySystemState.getBaseProperties(), null, argv);
        imp.load(runner);
    }

    public static void main(String[] args) {
        run(args);
    }
}

I put this code into the org.python.util package, since that’s where it would go if we decide to include it in a future Jython. To compile it, you’ll need to put jython.jar (or your myapp.jar) into the classpath like:

$ javac -classpath myapp.jar org/python/util/JarRunner.java

Then you’ll need to add JarRunner.class to your jar (the class file will need to be in org/python/util/JarRunner.class) calling jar on the “org” directory will get the whole path into your jar.

$ jar uf org

Add this to a file that you will use to update the manifest, a good name is manifest.txt:

Main-Class: org.python.util.JarRunner

Then update the jar’s manifest:

$ jar ufm myapp.jar manifest.txt

Now you should be able to run your app like this:

$ java -jar myapp.jar

Leave a Comment