Cannot run python script from java jar

Question:

While working in IntelliJ everything worked but after I built jar it stopped. At first, it was just me forgetting to put it in jar build config, but now after making sure it is there, I still can’t run it. These are ways I try:

InputStream script = mainView.class.getResourceAsStream("vizualize3D.py");
Process process = new ProcessBuilder("python3", "-").start() ;

Process p1 = Runtime.getRuntime().exec("python3 " + script);

Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("python3 " + mainView.class.getResourceAsStream("vizualize3D.py"));

None of theme work despite having it in resources. I also tried to specify path to it in IntelliJ project and it works but only when run from IntelliJ after I start it from jar it doesn’t.

Edit1:
For people that didn’t understand py file is in jar file

Asked By: FikiCar

||

Answers:

None of the options involving you trying to execute "python3 "+script, and equivalents, will work. script is an InputStream, not a path on the file system, so simply concatenating it with a String will not give you anything meaningful. Additionally, since your script is not in its own file, and there’s no simple way for the python interpreter to extract it, simply invoking it like this won’t work.

What you can do, however, is to execute

python3 -

The - option here (at least on BSD-like systems) means “read from standard input, and interpret it as a script”. Then, on the Java side, you can read the jar-packaged resource as a stream and pipe it to the python process’s standard input.

For details on choosing the correct path for the resource, see How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?.

The following, in which the script is simply placed in the same package as the class, works for me:

PythonRunner.java:

package example.python;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class PythonRunner {

    public static void main(String[] args) throws Exception {

        String pythonInterpreter = "/usr/bin/python3" ; // default
        if (args.length > 0) {
            pythonInterpreter = args[0] ;
        }

        InputStream script = PythonRunner.class.getResourceAsStream("script.py");
        Process pythonProcess = new ProcessBuilder(pythonInterpreter, "-")
                .start();

        // This thread reads the output from the process and 
        // processes it (in this case just dumps it to standard out)
        new Thread(() ->  {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(pythonProcess.getInputStream()))) {

                for (String line ; (line = reader.readLine()) != null ;) {
                    System.out.println(line);
                }
            } catch (IOException exc) {
                exc.printStackTrace();
            }
        }).start();

        // read the script from the resource, and pipe it to the
        // python process's standard input (which will be read because
        // of the '-' option)
        OutputStream stdin = pythonProcess.getOutputStream();
        byte[] buffer = new byte[1024];
        for (int read = 0 ; read >= 0 ; read = script.read(buffer)) {
            stdin.write(buffer, 0, read);
        }
        stdin.close();
    }

}

script.py:

import sys

for i in range(10):
    print("Spam")

sys.exit(0)

MANIFEST.MF

Manifest-Version: 1.0
Main-Class: example.python.PythonRunner

Eclipse layout:

enter image description here

Jar contents and result of running:

$ jar tf runPython.jar 
META-INF/MANIFEST.MF
example/python/PythonRunner.class
example/python/script.py
$ java -jar runPython.jar 
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
$
Answered By: James_D

I’ve tried all solutions provided; inorder to run a python script present inside a jar file.

My best bet would be to NOT keep the python files inside jar.
Instead keep them at same location/level with jar and use following code to invoke python script from a java class inside the jar.

String pyScriptPath = "./py_script.py"; 

ProcessBuilder pb = new ProcessBuilder("python3" + pyScriptPath);
Process process = pb.start();

This ultimately worked for me after wasting a complete day.

Answered By: Heisenbug