0

How do I call and execute python class methods from java. My current java code works, but only if I write:

if __name__ == '__main__':
    print("hello")

But I want to execute a class method, regardless of if __name__ == '__main__':

Example python class method I would like to run:

class SECFileScraper:
    def __init__(self):
        self.counter = 5

    def tester_func(self):
        return "hello, this test works"

Essentially I would want to run SECFileScraper.tester_func() in java.

My Java code:

try {

            ProcessBuilder pb = new ProcessBuilder(Arrays.asList(
                    "python", pdfFileScraper));
            Process p = pb.start();

            BufferedReader bfr = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String line = "";
            System.out.println("Running Python starts: " + line);
            int exitCode = p.waitFor();
            System.out.println("Exit Code : " + exitCode);
            line = bfr.readLine();
            System.out.println("First Line: " + line);
            while ((line = bfr.readLine()) != null) {
                System.out.println("Python Output: " + line);


            }

        } catch (Exception e) {
            e.printStackTrace();
        }

pdfFileScraper is the file path to my python script.

I've tried jython, but my python files use pandas and sqlite3, which can't be implemented using jython.

3 Answers 3

2

So if I understand your requirement, you want to invoke a class method in pdfFileScraper.py. The basics of doing this from the shell would be something akin to:

scraper=path/to/pdfFileScraper.py
dir_of_scraper=$(dirname $scraper)
export PYTHONPATH=$dir_of_scraper
python -c 'import pdfFileScraper; pdfFileScraper.ClassInScraper()'

What we do is get the directory of pdfFileScraper, and add it to the PYTHONPATH, then we run python with a command that imports the pdfFileScraper file as a module, which exposes all the methods and classes in the class in the namespace pdfFileScraper, and then construct a class ClassInScraper().

In java, something like:

import java.io.*;
import java.util.*;

public class RunFile {
    public static void main(String args[]) throws Exception {
        File f = new File(args[0]); // .py file (e.g. bob/script.py)

        String dir = f.getParent(); // dir of .py file
        String file = f.getName(); // name of .py file (script.py)
        String module = file.substring(0, file.lastIndexOf('.'));
        String command = "import " + module + "; " + module + "." + args[1];
        List<String> items = Arrays.asList("python", "-c", command);
        ProcessBuilder pb = new ProcessBuilder(items);
        Map<String, String> env = pb.environment();
        env.put("PYTHONPATH", dir);
        pb.redirectErrorStream();
        Process p = pb.start();

        BufferedReader bfr = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line = "";
        System.out.println("Running Python starts: " + line);
        int exitCode = p.waitFor();
        System.out.println("Exit Code : " + exitCode);
        line = bfr.readLine();
        System.out.println("First Line: " + line);
        while ((line = bfr.readLine()) != null) {
            System.out.println("Python Output: " + line);
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

It doesn't output anything. All I get is this: Running Python starts: Exit Code : 0 First Line: null
ProcessBuilder can only deal with printed return output, so the line returning a string won't actually display anything that can be parsed. You would need to print "This test works" to get the desired result. If you want to directly interact with python objects then you're going to have to use a solution like mko's one - i.e. load a python interpreter in the VM and interact with it directly.
1

You can also call Python lib directly via JNI. This way, you don't start new process, you can share context between script calls, etc.

Take a look here for a sample:

https://github.com/mkopsnc/keplerhacks/tree/master/python

Comments

0

This is my java class that worked for me.

class PythonFileReader {
private String path;
private String fileName;
private String methodName;

PythonFileReader(String path, String fileName, String methodName) throws Exception {
    this.path = path;
    this.fileName = fileName;
    this.methodName = methodName;
    reader();
}

private void reader() throws Exception {

    StringBuilder input_result = new StringBuilder();
    StringBuilder output_result = new StringBuilder();
    StringBuilder error_result = new StringBuilder();
    String line;

    String module = fileName.substring(0, fileName.lastIndexOf('.'));
    String command = "import " + module + "; " + module + "." + module + "." + methodName;
    List<String> items = Arrays.asList("python", "-c", command);

    ProcessBuilder pb = new ProcessBuilder(items);
    pb.directory(new File(path));
    Process p = pb.start();
    BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
    BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
    BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));

    while ((line = in.readLine()) != null)
        input_result.append("\n").append(line);
    if (input_result.length() > 0)
        System.out.println(fileName + " : " + input_result);

    while ((line = out.readLine()) != null)
        output_result.append(" ").append(line);
    if (output_result.length() > 0)
        System.out.println("Output : " + output_result);

    while ((line = error.readLine()) != null)
        error_result.append(" ").append(line);
    if (error_result.length() > 0)
        System.out.println("Error : " + error_result);
}}

and this is the way that you can use this class

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

    String path = "python/path/file";
    String pyFileName = "python_name.py";
    String methodeName = "test('stringInput' , 20)";

    new PythonFileReader(path, pyFileName, methodeName );
}

and this is my python class

class test:

def test(name, count):
    print(name + " - " + str([x for x in range(count)]))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.