Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/interpreter/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ group: manual
<th>Description</th>
</tr>
<tr>
<td>python</td>
<td>zeppelin.python</td>
<td>python</td>
<td>Path of the already installed Python binary (could be python2 or python3).
If python is not in your $PATH you can set the absolute directory (example : /usr/bin/python)
</td>
</tr>
<tr>
<td>zeppelin.python.maxResult</td>
<td>1000</td>
<td>Max number of dataframe rows to display.</td>
</tr>
</table>

## Enabling Python Interpreter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
Expand Down Expand Up @@ -50,27 +49,16 @@ public class PythonInterpreter extends Interpreter {
public static final String BOOTSTRAP_INPUT_PY = "/bootstrap_input.py";
public static final String ZEPPELIN_PYTHON = "zeppelin.python";
public static final String DEFAULT_ZEPPELIN_PYTHON = "python";
public static final String MAX_RESULT = "zeppelin.python.maxResult";

private Integer port;
private GatewayServer gatewayServer;
private long pythonPid;
private Boolean py4J = false;
private InterpreterContext context;
private int maxResult;

PythonProcess process = null;

static {
Interpreter.register(
"python",
"python",
PythonInterpreter.class.getName(),
new InterpreterPropertyBuilder()
.add(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON,
"Python directory. Default : python (assume python is in your $PATH)")
.build()
);
}

public PythonInterpreter(Properties property) {
super(property);
}
Expand All @@ -80,6 +68,7 @@ public void open() {
logger.info("Starting Python interpreter .....");
logger.info("Python path is set to:" + property.getProperty(ZEPPELIN_PYTHON));

maxResult = Integer.valueOf(getProperty(MAX_RESULT));
process = getPythonProcess();

try {
Expand Down Expand Up @@ -223,7 +212,7 @@ public GUI getGui() {
return context.getGui();
}

public Integer getPy4JPort() {
public Integer getPy4jPort() {
return port;
}

Expand All @@ -247,4 +236,7 @@ private int findRandomOpenPortOnAllLocalInterfaces() {
return port;
}

public int getMaxResult() {
return maxResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public String sendAndGetResult(String cmd) throws IOException {
String output = "";
String line;
while (!(line = reader.readLine()).contains("*!?flush reader!?*")) {
logger.debug("Readed line from python shell : " + line);
logger.debug("Read line from python shell : " + line);
if (line.equals("...")) {
logger.warn("Syntax error ! ");
output += "Syntax error ! ";
Expand Down
5 changes: 2 additions & 3 deletions python/src/main/resources/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# PYTHON 2 / 3 comptability :
# PYTHON 2 / 3 compatibility :
# bootstrap.py must be runnable with Python 2 or 3

# Remove interactive mode displayhook
Expand All @@ -36,7 +36,7 @@ def intHandler(signum, frame): # Set the signal handler
def help():
print ('%html')
print ('<h2>Python Interpreter help</h2>')
print ('<h3>Python 2 & 3 comptability</h3>')
print ('<h3>Python 2 & 3 compatibility</h3>')
print ('<p>The interpreter is compatible with Python 2 & 3.<br/>')
print ('To change Python version, ')
print ('change in the interpreter configuration the python to the ')
Expand Down Expand Up @@ -100,4 +100,3 @@ def checkbox(self, name, options, defaultChecked=[]):
print (self.errorMsg)

z = PyZeppelinContext("")

21 changes: 21 additions & 0 deletions python/src/main/resources/interpreter-setting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[
{
"group": "python",
"name": "python",
"className": "org.apache.zeppelin.python.PythonInterpreter",
"properties": {
"zeppelin.python": {
"envName": null,
"propertyName": "zeppelin.python",
"defaultValue": "python",
"description": "Python directory. It is set to python by default.(assume python is in your $PATH)"
},
"zeppelin.python.maxResult": {
"envName": null,
"propertyName": "zeppelin.python.maxResult",
"defaultValue": "1000",
"description": "Max number of dataframe rows to display."
}
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.zeppelin.python;

import static org.apache.zeppelin.python.PythonInterpreter.*;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -53,13 +54,17 @@ public class PythonInterpreterTest {

Logger logger = LoggerFactory.getLogger(PythonProcess.class);

public static final String ZEPPELIN_PYTHON = "zeppelin.python";
public static final String DEFAULT_ZEPPELIN_PYTHON = "python";

PythonInterpreter pythonInterpreter = null;
PythonProcess mockPythonProcess;
String cmdHistory;

public static Properties getPythonTestProperties() {
Properties p = new Properties();
p.setProperty(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON);
p.setProperty(MAX_RESULT, "1000");
return p;
}

@Before
public void beforeTest() {
cmdHistory = "";
Expand All @@ -79,20 +84,15 @@ public String answer(InvocationOnMock invocationOnMock) throws Throwable {
logger.error("Can't initiate python process", e);
}

Properties properties = new Properties();
properties.put(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON);
pythonInterpreter = spy(new PythonInterpreter(properties));
pythonInterpreter = spy(new PythonInterpreter(getPythonTestProperties()));

when(pythonInterpreter.getPythonProcess()).thenReturn(mockPythonProcess);


try {
when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn("ImportError");
} catch (IOException e) {
e.printStackTrace();
}


}

@Test
Expand All @@ -111,7 +111,7 @@ public void testPy4jIsNotInstalled() {
py4j JavaGateway is not running
*/
pythonInterpreter.open();
assertNull(pythonInterpreter.getPy4JPort());
assertNull(pythonInterpreter.getPy4jPort());

assertTrue(cmdHistory.contains("def help()"));
assertTrue(cmdHistory.contains("class PyZeppelinContext():"));
Expand All @@ -122,8 +122,7 @@ public void testPy4jIsNotInstalled() {
}

@Test
public void testPy4JInstalled() {

public void testPy4jInstalled() {

/*
If Py4J installed, bootstrap_input.py
Expand All @@ -137,7 +136,7 @@ public void testPy4JInstalled() {
e.printStackTrace();
}
pythonInterpreter.open();
Integer py4jPort = pythonInterpreter.getPy4JPort();
Integer py4jPort = pythonInterpreter.getPy4jPort();
assertNotNull(py4jPort);

assertTrue(cmdHistory.contains("def help()"));
Expand All @@ -147,8 +146,7 @@ public void testPy4JInstalled() {
assertTrue(cmdHistory.contains("GatewayClient(port=" + py4jPort + ")"));
assertTrue(cmdHistory.contains("org.apache.zeppelin.display.Input"));


assertTrue(checkSocketAdress(py4jPort));
assertTrue(checkSocketAddress(py4jPort));

}

Expand All @@ -162,12 +160,12 @@ public void testClose() {
e.printStackTrace();
}
pythonInterpreter.open();
Integer py4jPort = pythonInterpreter.getPy4JPort();
Integer py4jPort = pythonInterpreter.getPy4jPort();

assertNotNull(py4jPort);
pythonInterpreter.close();

assertFalse(checkSocketAdress(py4jPort));
assertFalse(checkSocketAddress(py4jPort));
try {
verify(mockPythonProcess, times(1)).close();
} catch (IOException e) {
Expand All @@ -189,7 +187,7 @@ public void testInterpret() {



private boolean checkSocketAdress(Integer py4jPort) {
private boolean checkSocketAddress(Integer py4jPort) {
Socket s = new Socket();
SocketAddress sa = new InetSocketAddress("localhost", py4jPort);
Boolean working = null;
Expand Down