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:
JYTHON_HOME
$ cp jython.jar jythonlib.jar
$ zip -r jythonlib.jar Lib
Add other modules to the jar:
MY_APP_DIRECTORY
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
Answer from Frank Wierzbicki on Stack OverflowThe 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:
JYTHON_HOME
$ cp jython.jar jythonlib.jar
$ zip -r jythonlib.jar Lib
Add other modules to the jar:
MY_APP_DIRECTORY
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
I experienced a similar issue in that I want to be able to create simple command line calls for my jython apps, not require that the user go through the jython installation process, and be able to have the jython scripts append library dependencies at runtime to sys.path so as to include core java code.
# append Java library elements to path
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "lib", "poi-3.8-20120326.jar"))
When running the 'jython' launcher explicitly on the command line, on Unix systems, it just runs a big shell script to properly form a java command line call. This jython launcher seems to have a dependency on reaching back to a core install of jython, and by some way of magic allows the proper handling of .jar files being added to the sys.path at runtime from within my .py scripts. You can see what the call is and block execution by the following:
jython --print run_form.py
java -Xmx512m -Xss1024k -Dfile.encoding=UTF-8 -classpath /Applications/jython2.5.2/jython.jar: -Dpython.home=/Applications/jython2.5.2 -Dpython.executable=/Applications/jython2.5.2/bin/jython org.python.util.jython run_form.py
But it's still just firing up a JVM and running a class file. So my goal was to be able to make this java call to a standalone jython.jar present in my distribution's lib directory so users would not need to do any additional installation steps to start using my .py scripted utilities.
java -Xmx512m -Xss1024k -classpath ../../lib/jython.jar org.python.util.jython run_form.py
Trouble is that the behavior is enough different that I would get responses like this:
File "run_form.py", line 14, in <module>
import xls_mgr
File "/Users/test/Eclipse/workspace/test_code/py/test/xls_mgr.py", line 17, in <module>
import org.apache.poi.hssf.extractor as xls_extractor
ImportError: No module named apache
Now you might say that I should just add the jar files to the -classpath, which in fact I tried, but I would get the same result.
The suggestion of bundling all of your .class files in a jython.jar did not sound appealing to me at all. It would be a mess and would bind the Java/Python hybrid application too tightly to the jython distribution. So that idea was not going to fly. Finally, after lots of searching, I ran across bug #1776 at jython.org, which has been listed as critical for a year and a half, but I don't see that the latest updates to jython incorporate a fix. Still, if you're having problems with having jython include your separate jar files, you should read this.
http://bugs.jython.org/issue1776
In there, you will find the temporary workaround for this. In my case, I took the Apache POI jar file and unjar'ed it into its own separate lib directory and then modified the sys.path entry to point to the directory instead of the jar:
sys.path.append('/Users/test/Eclipse/workspace/test_code/lib/poi_lib')
Now, when I run jython by way of java, referencing my local jython.jar, the utility runs just peachy. Now I can create simple scripts or batch files to make a seamless command line experience for my .py utilities, which the user can run without any additional installation steps.
java - Python: How can I execute a jar file through a python script - Stack Overflow
What is the python equivalent to a Java .jar file? - Stack Overflow
pip - Creating a Python Executable Package Similar to Java Jar file - Stack Overflow
[Curiosity] Python's equivalent of Java's .jar-file
Videos
I would use subprocess this way:
import subprocess
subprocess.call(['java', '-jar', 'Blender.jar'])
But, if you have a properly configured /proc/sys/fs/binfmt_misc/jar you should be able to run the jar directly, as you wrote.
So, which is exactly the error you are getting? Please post somewhere all the output you are getting from the failed execution.
This always works for me:
from subprocess import *
def jarWrapper(*args):
process = Popen(['java', '-jar']+list(args), stdout=PIPE, stderr=PIPE)
ret = []
while process.poll() is None:
line = process.stdout.readline()
if line != '' and line.endswith('\n'):
ret.append(line[:-1])
stdout, stderr = process.communicate()
ret += stdout.split('\n')
if stderr != '':
ret += stderr.split('\n')
ret.remove('')
return ret
args = ['myJarFile.jar', 'arg1', 'arg2', 'argN'] # Any number of args to be passed to the jar file
result = jarWrapper(*args)
print result
Python doesn't have any exact equivalent to a .jar file.
There are many differences, and without knowing exactly what you want to do, it's hard to explain how to do it. But the Python Packaging User Guide does a pretty good job of explaining just about everything relevant.
Here are some of the major differences.
A .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 yoursys.path, and it can be imported and used. - A directory full of modules can be treated the same way; it becomes a package (or, if it doesn't contain an
__init__.py, it merges with other directories of the same name elsewhere onsys.pathinto a single package). - A
.ziparchive containing any number of modules and packages can be stored anywhere, and its path added to yoursys.path(e.g., at runtime or viaPYTHONPATH) and all of its contents become importable.
Most commonly, you want things to be installed into a system, user, or virtualenv site-packages directory. The recommended way to do that is to create a pip-compatible package distribution; people then install it (and possibly automatically download it from PyPI or a private repo) via pip.
pip does a lot more than that, however. It also allows you to manage dependencies between packages. So ideally, instead of listing a bunch of prereqs that someone has to go download and install manually, you just make them dependencies, and someone just has to pip install your-library. And it keeps track of the state of your site-packages, so you can uninstall or upgrade a package without having to track down the specific files.
Meanwhile, in Java, most .jar files are cross-platform; build once, run anywhere. A few packages have JNI native code and can't be used this way, but it's not the norm.
In Python, many packages have C extensions that have to be compiled for each platform, and even pure-Python packages often need to do some install-time configuration. And meanwhile, "compiling" pure Python doesn't do anything that can't be done just as well at runtime. So in Python, you generally distribute source packages, not compiled packages.
However, .wheel is a binary package format. You can pip wheel to build binary packages for different targets from the source package; then, if someone tries to pip install your package, if there's a wheel for his system, that will be downloaded and installed.
Easy Install from setup_tools defines the .egg format for deploying Python libraries or applications. While similar to JAR, it is nowhere spread as universally as JARs in Java world. Many people just deploy the .py files.
A newer format, intended to supersede eggs, is wheel.
I realized what the problem was and I wanted to document it in case anyone else has the same problems.
I was using the jython.jar file that came in the standard installation of Jython, and NOT the standalone jython.jar (the instructions at Using the Jar Method mentions this, but the instructions at Building Jars do not). I am still unsure why copying the Lib/ folder of the standard installation into the jython.jar that came with that installation didn't work on my system. However, once I used the standalone jar, things started to work more smoothly.
Additionally, I was able to get my library to work with the packaged file by doing three things in addition to the steps I laid out in my question:
Exploding the standalone jython.jar and copying the folder with all of my library files into Lib, then create a new jar. This seemed to be the easiest way to include my library and allows me to package everything into a single jar.
I discovered after reading Frank Wierzbicki's answer in Why does Jython refuse to find my Java package? that because I am now using the standalone jar, I could no longer use imports of the style
from java.awt import *, instead I needed to fully specify each thing I was importing, for examplefrom java.awt.Font import PLAIN, BOLD, ITALIC. So I went through the library's imports and fixed the few that were of the wrong style.Now that I am adding my Library directly to the Jar's Lib folder, instead of writing
Class-Path: ./myLibrary.jarinothermanifest.mf, I putMain-Class: org.python.util.JarRunneras per Frank Wierzbicki's answer in the post I mentioned in my question: Distributing my Python scripts as JAR files with Jython?
This allowed me to create a double-clickable executable jar containing my library and jython file that I wanted to run.
There are two solutions. They both work, but one better than the other.
I believe you can rename your python script as __run__.py, place that file inside the .jar file, and pass the .jar file through a python interpreter. See https://wiki.python.org/jython/UserGuide#invoking-the-jython-interpreter for more.
Multiple methods to run Jython from the java code while running through JVM are described here, at the Jython documentation.
EDIT:
You can execute a command line code that runs the python file you want. Link to an example of running command line code from java here.
This is what I am using right now
os.system("java -jar FULL_PATH\RR.jar")
A command prompt console window pops up for an instance and all i can read is 4 lines reading success followed by some other text.
Any help will be welcome
Sharing how I achieve this. Thanks to EnigmaCurry for providing the framework.
Jar Method from Jython wiki works quite well. The one drawback that it has is that all of the Java dependancies need to be exploded into the main jar root. This gets messy very quickly.
So the approach uses One-Jar. It is a special class loader which can load a jar from contained in the jar file.
So you can have your script/class, jython and other libraries all getting packaged as a single jar.
You can download the skeleton for achieving this from here.
Once you get it put your scripts in src, put the other jars (including jython jar) in the lib folder, put one-jar source in its respective folder and just run the ant tool with build.xml provided.
You will get your jar then.
Have you tried jump? It's a build tool for distributing Java and Jython applications. I have used it a few times before and it might be able to do what you need. It can
Distributing Jython applications into a single, independent JAR file.
Distributing Jython libraries into a single JAR file. [New in v0.9.5]
Distributing native Mac OS X application bundles, Windows .exe executables, WAR files for
Python WSGI applications. [New in v0.9.5]
Distributing Java Only applications. [New in v0.9.6]
Creating build.xml file for ant. [New in v0.9.7]
Supporting Java source code and third-party JAR files.
Supporting Java Native Interface files for distributing JAR files. [New in v0.9.5]
Starting the created distribution from either Jython or Java code.
Including specified resource files in the final distribution. [New in v0.9.6]
Packaging only required Python packages into the final distribution automatically, which means you don't have to worry about using Python third-party libraries as long as they can be found in your sys.path.
Importing specified Python packages explicitly. [New in v0.9.5]
All Python modules included in the final distribution are compiled to $py.class files, which means your source code is not public.
Integrated easy use Jython factory. [New in v0.9.7]
Hi, I've got a .jar file that outputs a lot of text continuously. I've been using the following code to open the .jar in python.
import subprocess subprocess.call(['java', '-jar', 'prox.jar'])
I can see that all is working because I can see the output text in the IDLE, but I'm stuck on how to execute code based on the continuous output. So like...
if "test" in live_output_of_Jar: ... if "othertext" in... you get the idea.
Thanks!