ninia / jep

Embed Python in Java
Other
1.3k stars 147 forks source link

SharedInterpreter can't execute "print" in python script? #433

Closed onegoldfish closed 21 hours ago

onegoldfish commented 1 year ago
public class A {
    public static void main(String[] args) {
        try (Interpreter interp = new SharedInterpreter()) {
            interp.exec("from java.lang import System");
            interp.exec("s = 'Hello World'");
            interp.exec("System.out.println(s)");
            interp.exec("print(s)");
            interp.exec("print(s[1:-1])");
        }
    }
}

In this program, I can only see the output of interp.exec("System.out.println(s)"); on the console. When I change SharedInterpreter into SubInterpreter, I can see three lines of output: interp.exec("System.out.println(s)");, interp.exec("print(s)");, and interp.exec("print(s[1:-1])"); What's the matter, please

bsteffensmeier commented 1 year ago

I ran your sample program with both SubInterpreter and SharedInterpreter and in both cases I am able to see all 3 lines of output. The problems may be specific to your configuration, if you could provide the information requested in the issue template that would help me try to recreate your problem(python version, jep version, OS version). It would also be good to know if you are running in an IDE or directly from a command line as many IDE's have special tricks to redirect IO.

I suspect the problem may be related to python buffering output, you could try setting the PYTHONUNBUFFERED env var to see if that is related.

Another possibility to work around this problem is to jsut redirect python output to System.out using JepConfig.redirectStdOut

onegoldfish commented 1 year ago

Thank you for your suggestion. I set the environment variables PYTHONUNBUFFERED =1 and I can output normally in the console. I'm using windows 10 and IDEA. I don't know why before setting the variables PYTHONUNBUFFEREDSubInterpreteris normal but SharedInterpreteris not.

bsteffensmeier commented 1 year ago

I don't know why before setting the variables PYTHONUNBUFFEREDSubInterpreteris normal but SharedInterpreteris not.

I suspect the buffer for output is being managed at the interpreter level. When you close a SubInterpreter I expect it to flush the buffer. When you close a SharedInterpreter there is some state remaining so that can be shared with other SharedInterpreters, the details are deep within cpython and not immediately controlled by jep but I suspect the output buffer is part of that shared state and not flushed. If you do not want to set that env var then you should be able to achieve the same result by calling sys.stdout.flush().

davidmayo commented 1 year ago

I solve a similar problem by including code that causes Python's print() to default to always flush as the first Python calls.

interp.exec("import functools"); interp.exec("print = functools.partial(print, flush=True)");

Technique from this article.