invoking python from java (jython?)


Results 1 to 4 of 4

Thread: invoking python from java (jython?)

  1. #1
    Join Date
    Jan 2003
    Location
    Austin, Texas
    Posts
    683

    invoking python from java (jython?)

    I am working on a Java program for use at work that is coming along nicely. It is used to analyze log files. For one particular type of log files, we already have a nice python script that will generate all sorts of statistical information about run lengths, the top 10 SQL statements used, the number of rows aggregated and deleted from each table, etc. In a sense -- it's really slick!

    Rather than reinvent the wheel I just planned on including it with the Java program that I'm working on right now, and invoking it whenever that particular log needs to be analyzed. Is there a simple way to do this? I have been looking into jython but so far all of the examples that I have found and research I have done suggests that jython is used to invoke Java code from within a python script. Is there a way to do precisely the opposite?


    Actually, I know that there is a way to invoke python from within Java and I have done it:

    Code:
    import java.io.*;
    
    public class Foo
    {
        public static void main(String[] args)
        {
            try
            {
                Runtime r = Runtime.getRuntime();
                Process p = r.exec("python foo.py");
                BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
                p.waitFor();
                String line = "";
                while (br.ready())
                    System.out.println(br.readLine());
    
            }
            catch (Exception e)
            {
    		String cause = e.getMessage();
    		if (cause.equals("python: not found"))
    			System.out.println("No python interpreter found.");
            }
        }
    }
    It works perfectly:

    $ cat foo.py
    import os

    print "SUCCESS"
    $ java Foo
    SUCCESS
    $ echo "print \"ASDF\"" >> foo.py
    $ cat foo.py
    import os

    print "SUCCESS"
    print "ASDF"
    $ java Foo
    SUCCESS
    ASDF
    [/code]


    The only problem with this method is that it requires the user to have a python interpreter installed on their system (and in the PATH). Is there some way that I can just include a jar file with the final code and then just call a Java class inside of that jar which will interpret and execute the python script for me? I think jython might be able to do this but I'm not sure.
    "The author of that poem is either Homer or, if not Homer, somebody else of the same name."

  2. #2
    Join Date
    Sep 2003
    Location
    Rochester, MN
    Posts
    3,604
    Hmm, Python with real threading? I like the sounds of that.

    Unfortunately the documentation section that looks like it would cover this sort of thing is MIA. One option might be to take a look at the source code - check out how the jar runs a Python script and you might be able to just integrate that into your application.

  3. #3
    Join Date
    Jan 2003
    Location
    Austin, Texas
    Posts
    683
    Nevermind...I figured it out. jythonc isn't very useful because it hard-codes the path to your python script into the java code. This isn't portable at all. However, I installed jython as a jar file and now I can just invoke it by including it in my class path. Here is a sample file:

    Code:
    import org.python.util.PythonInterpreter;
    
    public class Foo
    {
    	public static void main (String[] args)
    	{
    		try
    		{
    			PythonInterpreter.initialize(System.getProperties(), System.getProperties(), new String[0]);
    			PythonInterpreter interp = new PythonInterpreter();
    			interp.execfile("foo.py");
    		}
    		catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    	}
    }
    Just be sure to compile and execute with jython.jar in your classpath:

    Code:
    $ cat foo.py 
    print "I'm python"
    print "and I'm called from Java"
    $ javac -cp .:jython.jar Foo.java
    $ java -cp .:jython.jar Foo
    I'm python
    and I'm called from Java

    Ultimately I'm not sure that I going to go this route for several reasons:

    1. the jython.jar file is about 8MB -- which is really more bloated than I want, though I would be willing to deal with it (internet is fast enough these days that 8MB is virtually nothing).

    2. The program I am writing a swing application, but unfortunately the print statements in the python code force output to the to the terminal. That's fine for anyone using the program in console mode (where there is GUI and all output *is* to the CLI) but for my GUI users -- that isn't cool. I suppose I could redirect the output to a buffer or a file somewhere and then output once the python code finishes running...


    I have some java code already written that doesn't do nearly the same statistics and so forth so I think I'll just include that. For anyone that does not have python installed, they will get the "basic" output. Anyone that does have python installed and in PATH will get the much fancier output. I think I am cool with doing that, so I might just stick to the code in my first post.


    Anyway, the above works for anyone that doesn't mind lugging around an 8MB jar file with their code, and output that only goes to the CLI. Hope this helps someone.
    "The author of that poem is either Homer or, if not Homer, somebody else of the same name."

  4. #4
    Join Date
    Jan 2003
    Location
    Austin, Texas
    Posts
    683
    Oh yeah, the other thing that sucks about calling the execfile() method is that you can't pass command line arguments, at least not by just appending them as string arguments to the execfile() argument. You can however set variables in Java and then use them in the python code:

    Code:
    import org.python.util.PythonInterpreter;
    
    public class Foo
    {
    	public static void main (String[] args)
    	{
    		try
    		{
    			PythonInterpreter.initialize(System.getProperties(), System.getProperties(), new String[0]);
    			PythonInterpreter interp = new PythonInterpreter();
    			interp.set("firstName", args[0]);
    			interp.set("lastName", args[1]);
    			interp.execfile("foo.py");
    		}
    		catch (Exception e)
    		{
    			e.printStackTrace();
    		}
    	}
    }
    Inside of foo.py you can just call the variable names directly:

    Code:
    $ cat foo.py
    print "Your full name is:"
    print firstName + " " + lastName
    $ java -cp .:jython.jar Foo Bugs Bunny
    Your full name is:
    Bugs Bunny
    It's also not very efficient. It took about 6 seconds for Java to invoke that 2 line python program and run it completion. The first five seconds or so it just sat there with no output at all. Then I could visibly see it print the first line, and then the second line shortly thereafter.

    It works though!
    "The author of that poem is either Homer or, if not Homer, somebody else of the same name."

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •