diff --git a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java index 670dffca39c..877d6975255 100644 --- a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java +++ b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java @@ -134,10 +134,11 @@ public InterpreterResult interpret(String cmd, InterpreterContext contextInterpr InterpreterResult result; if (pythonErrorIn(output)) { - result = new InterpreterResult(Code.ERROR, output.replaceAll(">>>", "").trim()); + result = new InterpreterResult(Code.ERROR, output); } else { - result = new InterpreterResult(Code.SUCCESS, output.replaceAll(">>>", "") - .replaceAll("\\.\\.\\.", "").trim()); + // TODO(zjffdu), we should not do string replacement operation in the result, as it is + // possible that the output contains the kind of pattern itself, e.g. print("...") + result = new InterpreterResult(Code.SUCCESS, output.replaceAll("\\.\\.\\.", "")); } return result; } @@ -265,4 +266,5 @@ private int findRandomOpenPortOnAllLocalInterfaces() { public int getMaxResult() { return maxResult; } + } diff --git a/python/src/main/java/org/apache/zeppelin/python/PythonProcess.java b/python/src/main/java/org/apache/zeppelin/python/PythonProcess.java index 348ced68a45..0ab14613101 100644 --- a/python/src/main/java/org/apache/zeppelin/python/PythonProcess.java +++ b/python/src/main/java/org/apache/zeppelin/python/PythonProcess.java @@ -21,12 +21,11 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.InputStream; -import java.io.OutputStream; import java.io.IOException; -import java.io.OutputStreamWriter; import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.OutputStream; import java.lang.reflect.Field; /** @@ -34,11 +33,11 @@ * Python process (REPL) used by python interpreter */ public class PythonProcess { - Logger logger = LoggerFactory.getLogger(PythonProcess.class); - + private static final Logger logger = LoggerFactory.getLogger(PythonProcess.class); + private static final String STATEMENT_END = "*!?flush reader!?*"; InputStream stdout; OutputStream stdin; - BufferedWriter writer; + PrintWriter writer; BufferedReader reader; Process process; @@ -56,7 +55,7 @@ public void open() throws IOException { process = builder.start(); stdout = process.getInputStream(); stdin = process.getOutputStream(); - writer = new BufferedWriter(new OutputStreamWriter(stdin)); + writer = new PrintWriter(stdin, true); reader = new BufferedReader(new InputStreamReader(stdout)); try { pid = findPid(); @@ -85,22 +84,21 @@ public void interrupt() throws IOException { } public String sendAndGetResult(String cmd) throws IOException { - writer.write(cmd + "\n\n"); - writer.write("print (\"*!?flush reader!?*\")\n\n"); - writer.flush(); - - String output = ""; - String line; - while (!(line = reader.readLine()).contains("*!?flush reader!?*")) { + writer.println(cmd); + writer.println(); + writer.println("\"" + STATEMENT_END + "\""); + StringBuilder output = new StringBuilder(); + String line = null; + while (!(line = reader.readLine()).contains(STATEMENT_END)) { logger.debug("Read line from python shell : " + line); if (line.equals("...")) { logger.warn("Syntax error ! "); - output += "Syntax error ! "; + output.append("Syntax error ! "); break; } - output += "\r" + line + "\n"; + output.append(line + "\n"); } - return output; + return output.toString(); } private long findPid() throws NoSuchFieldException, IllegalAccessException { diff --git a/python/src/main/resources/bootstrap.py b/python/src/main/resources/bootstrap.py index 09e51e31cca..889b456b50a 100644 --- a/python/src/main/resources/bootstrap.py +++ b/python/src/main/resources/bootstrap.py @@ -25,13 +25,13 @@ except ImportError: import io as io -sys.displayhook = lambda x: None - def intHandler(signum, frame): # Set the signal handler print ("Paragraph interrupted") raise KeyboardInterrupt() signal.signal(signal.SIGINT, intHandler) +# set prompt as empty string so that java side don't need to remove the prompt. +sys.ps1="" def help(): print("""%html diff --git a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java index a4c80ae8966..8866e6ce1c1 100644 --- a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java +++ b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java @@ -115,7 +115,7 @@ public void testPy4jIsNotInstalled() { */ @Test public void testPy4jInstalled() throws IOException, InterruptedException { - when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn(">>>"); + when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn(""); pythonInterpreter.open(); Integer py4jPort = pythonInterpreter.getPy4jPort(); @@ -137,7 +137,7 @@ public void testPy4jInstalled() throws IOException, InterruptedException { @Test public void testClose() throws IOException, InterruptedException { //given: py4j is installed - when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn(">>>"); + when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn(""); pythonInterpreter.open(); Integer py4jPort = pythonInterpreter.getPy4jPort(); @@ -210,11 +210,11 @@ private String answerFromPythonMock(InvocationOnMock invocationOnMock) { String output = ""; for (int i = 0; i < lines.length; i++) { - output += ">>>" + lines[i]; + output += lines[i]; } return output; } else { - return ">>>"; + return ""; } }