Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distributing my Python scripts as JAR files with Jython?

I have been a Python programmer for almost two years, and I am used to writing small scripts to automate some repetitive tasks I had to do at the office. Now, apparently my colleagues noticed this, and they want those scripts too.

Some of them have Macs, some Windows; I made these on windows. I investigated the possibility of using py2exe or even py2app to make natives of my script, but they never satisfied me...

I came to know that all of them have JVM on their systems, so can I give them one single executable JAR file of my script using something like Jython may be?

How feasible is this... I mean, I had no idea how to write scripts for Jython, neither did I care about it when I wrote them... what kind of problems will it give?

like image 744
sharat87 Avatar asked Oct 19 '22 23:10

sharat87


People also ask

What is a python jar file?

jar file is a compiled collection of classes that can be dropped into your application, or installed anywhere on your CLASSPATH . In Python: A . py (or . pyc ) module can be dropped into your application, or installed anywhere on your sys.


1 Answers

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
like image 66
Frank Wierzbicki Avatar answered Oct 22 '22 12:10

Frank Wierzbicki