blob: 33f1869d3a1a5f1e28927dc1ac0d2e492c5b403a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.python;
import net.jodah.concurrentunit.ConcurrentTestCase;
import org.apache.zeppelin.display.ui.CheckBox;
import org.apache.zeppelin.display.ui.Password;
import org.apache.zeppelin.display.ui.Select;
import org.apache.zeppelin.display.ui.TextBox;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterGroup;
import org.apache.zeppelin.interpreter.InterpreterOutput;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResultMessage;
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
public abstract class BasePythonInterpreterTest extends ConcurrentTestCase {
protected InterpreterGroup intpGroup;
protected Interpreter interpreter;
protected boolean isPython2;
@Before
public abstract void setUp() throws InterpreterException;
@After
public abstract void tearDown() throws InterpreterException;
@Test
public void testPythonBasics() throws InterpreterException, InterruptedException, IOException {
InterpreterContext context = getInterpreterContext();
InterpreterResult result =
interpreter.interpret("import sys\nprint(sys.version[0])", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
Thread.sleep(100);
List<InterpreterResultMessage> interpreterResultMessages =
context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
// single output without print
context = getInterpreterContext();
result = interpreter.interpret("'hello world'", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("'hello world'", interpreterResultMessages.get(0).getData().trim());
// unicode
context = getInterpreterContext();
result = interpreter.interpret("print(u'你好')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("你好\n", interpreterResultMessages.get(0).getData());
// only the last statement is printed
context = getInterpreterContext();
result = interpreter.interpret("'hello world'\n'hello world2'", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("'hello world2'", interpreterResultMessages.get(0).getData().trim());
// single output
context = getInterpreterContext();
result = interpreter.interpret("print('hello world')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("hello world\n", interpreterResultMessages.get(0).getData());
// multiple output
context = getInterpreterContext();
result = interpreter.interpret("print('hello world')\nprint('hello world2')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("hello world\nhello world2\n", interpreterResultMessages.get(0).getData());
// assignment
context = getInterpreterContext();
result = interpreter.interpret("abc=1", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(0, interpreterResultMessages.size());
// if block
context = getInterpreterContext();
result =
interpreter.interpret("if abc > 0:\n\tprint('True')\nelse:\n\tprint('False')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("True\n", interpreterResultMessages.get(0).getData());
// for loop
context = getInterpreterContext();
result = interpreter.interpret("for i in range(3):\n\tprint(i)", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("0\n1\n2\n", interpreterResultMessages.get(0).getData());
// syntax error
context = getInterpreterContext();
result = interpreter.interpret("print(unknown)", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.ERROR, result.code());
if (interpreter instanceof IPythonInterpreter) {
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertTrue(interpreterResultMessages.get(0).getData().contains(
"name 'unknown' is not defined"));
} else if (interpreter instanceof PythonInterpreter) {
assertTrue(result.message().get(0).getData().contains("name 'unknown' is not defined"));
}
// raise runtime exception
context = getInterpreterContext();
result = interpreter.interpret("1/0", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.ERROR, result.code());
if (interpreter instanceof IPythonInterpreter) {
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertTrue(interpreterResultMessages.get(0).getData().contains("ZeroDivisionError"));
} else if (interpreter instanceof PythonInterpreter) {
assertTrue(result.message().get(0).getData().contains("ZeroDivisionError"));
}
// ZEPPELIN-1133
context = getInterpreterContext();
result = interpreter.interpret(
"from __future__ import print_function\n" +
"def greet(name):\n" +
" print('Hello', name)\n" +
"greet('Jack')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("Hello Jack\n", interpreterResultMessages.get(0).getData());
// ZEPPELIN-1114
context = getInterpreterContext();
result = interpreter.interpret("print('there is no Error: ok')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("there is no Error: ok\n", interpreterResultMessages.get(0).getData());
// ZEPPELIN-3687
context = getInterpreterContext();
result = interpreter.interpret("# print('Hello')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(0, interpreterResultMessages.size());
context = getInterpreterContext();
result = interpreter.interpret(
"# print('Hello')\n# print('How are u?')\n# time.sleep(1)", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(0, interpreterResultMessages.size());
// multiple text output
context = getInterpreterContext();
result = interpreter.interpret(
"for i in range(1,4):\n" + "\tprint(i)", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals("1\n2\n3\n", interpreterResultMessages.get(0).getData());
}
@Test
public void testCodeCompletion() throws InterpreterException, IOException, InterruptedException {
// define `a` first
InterpreterContext context = getInterpreterContext();
String st = "a='hello'";
InterpreterResult result = interpreter.interpret(st, context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
// now we can get the completion for `a.`
context = getInterpreterContext();
st = "a.";
List<InterpreterCompletion> completions = interpreter.completion(st, st.length(), context);
// it is different for python2 and python3 and may even different for different minor version
// so only verify it is larger than 20
assertTrue(completions.size() > 20);
context = getInterpreterContext();
st = "a.co";
completions = interpreter.completion(st, st.length(), context);
assertEquals(1, completions.size());
assertEquals("count", completions.get(0).getValue());
// cursor is in the middle of code
context = getInterpreterContext();
st = "a.co\b='hello";
completions = interpreter.completion(st, 4, context);
assertEquals(1, completions.size());
assertEquals("count", completions.get(0).getValue());
}
@Test
public void testZeppelinContext() throws InterpreterException, InterruptedException, IOException {
// TextBox
InterpreterContext context = getInterpreterContext();
InterpreterResult result =
interpreter.interpret("z.input(name='text_1', defaultValue='value_1')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
List<InterpreterResultMessage> interpreterResultMessages =
context.out.toInterpreterResultMessage();
assertTrue(interpreterResultMessages.get(0).getData().contains("'value_1'"));
assertEquals(1, context.getGui().getForms().size());
assertTrue(context.getGui().getForms().get("text_1") instanceof TextBox);
TextBox textbox = (TextBox) context.getGui().getForms().get("text_1");
assertEquals("text_1", textbox.getName());
assertEquals("value_1", textbox.getDefaultValue());
// Password
context = getInterpreterContext();
result =
interpreter.interpret("z.password(name='pwd_1')", context);
Thread.sleep(100);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertTrue(context.getGui().getForms().get("pwd_1") instanceof Password);
Password password = (Password) context.getGui().getForms().get("pwd_1");
assertEquals("pwd_1", password.getName());
// Select
context = getInterpreterContext();
result = interpreter.interpret("z.select(name='select_1'," +
" options=[('value_1', 'name_1'), ('value_2', 'name_2')])", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, context.getGui().getForms().size());
assertTrue(context.getGui().getForms().get("select_1") instanceof Select);
Select select = (Select) context.getGui().getForms().get("select_1");
assertEquals("select_1", select.getName());
assertEquals(2, select.getOptions().length);
assertEquals("name_1", select.getOptions()[0].getDisplayName());
assertEquals("value_1", select.getOptions()[0].getValue());
// CheckBox
context = getInterpreterContext();
result = interpreter.interpret("z.checkbox(name='checkbox_1'," +
"options=[('value_1', 'name_1'), ('value_2', 'name_2')])", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
assertEquals(1, context.getGui().getForms().size());
assertTrue(context.getGui().getForms().get("checkbox_1") instanceof CheckBox);
CheckBox checkbox = (CheckBox) context.getGui().getForms().get("checkbox_1");
assertEquals("checkbox_1", checkbox.getName());
assertEquals(2, checkbox.getOptions().length);
assertEquals("name_1", checkbox.getOptions()[0].getDisplayName());
assertEquals("value_1", checkbox.getOptions()[0].getValue());
// Pandas DataFrame
context = getInterpreterContext();
result = interpreter.interpret("import pandas as pd\n" +
"df = pd.DataFrame({'id':[1,2,3], 'name':['a\ta','b\\nb','c\\r\\nc']})\nz.show(df)",
context);
assertEquals(context.out.toInterpreterResultMessage().toString(),
InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals(InterpreterResult.Type.TABLE, interpreterResultMessages.get(0).getType());
assertEquals("id\tname\n1\ta a\n2\tb b\n3\tc c\n", interpreterResultMessages.get(0).getData());
context = getInterpreterContext();
result = interpreter.interpret("import pandas as pd\n" +
"df = pd.DataFrame({'id':[1,2,3,4], 'name':['a','b','c', 'd']})\nz.show(df)", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(2, interpreterResultMessages.size());
assertEquals(InterpreterResult.Type.TABLE, interpreterResultMessages.get(0).getType());
assertEquals("id\tname\n1\ta\n2\tb\n3\tc\n", interpreterResultMessages.get(0).getData());
assertEquals(InterpreterResult.Type.HTML, interpreterResultMessages.get(1).getType());
assertEquals("<font color=red>Results are limited by 3.</font>\n",
interpreterResultMessages.get(1).getData());
// z.show(df, show_index=True)
context = getInterpreterContext();
result = interpreter.interpret("import pandas as pd\n" +
"df = pd.DataFrame({'id':[1,2,3], 'name':['a','b','c']})\n" +
"z.show(df, show_index=True)",
context);
assertEquals(context.out.toInterpreterResultMessage().toString(),
InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals(InterpreterResult.Type.TABLE, interpreterResultMessages.get(0).getType());
assertEquals("\tid\tname\n" +
"%html <strong>0</strong>\t1\ta\n" +
"%html <strong>1</strong>\t2\tb\n" +
"%html <strong>2</strong>\t3\tc\n", interpreterResultMessages.get(0).getData());
// z.show(df, show_index=True), index is timestamp
context = getInterpreterContext();
result = interpreter.interpret("import pandas as pd\n" +
"idx = pd.date_range('20230530', periods=3, freq='D')\n" +
"df = pd.DataFrame({'name':['a','b','c']}, index= idx)\n" +
"z.show(df, show_index=True)",
context);
assertEquals(context.out.toInterpreterResultMessage().toString(),
InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals(InterpreterResult.Type.TABLE, interpreterResultMessages.get(0).getType());
assertEquals("\tname\n" +
"%html <strong>2023-05-30T00:00:00.000000000</strong>\ta\n" +
"%html <strong>2023-05-31T00:00:00.000000000</strong>\tb\n" +
"%html <strong>2023-06-01T00:00:00.000000000</strong>\tc\n",
interpreterResultMessages.get(0).getData());
// z.show(matplotlib)
context = getInterpreterContext();
result = interpreter.interpret("import matplotlib.pyplot as plt\n" +
"data=[1,1,2,3,4]\nplt.figure()\nplt.plot(data)\nz.show(plt)", context);
assertEquals(InterpreterResult.Code.SUCCESS, result.code());
interpreterResultMessages = context.out.toInterpreterResultMessage();
assertEquals(1, interpreterResultMessages.size());
assertEquals(InterpreterResult.Type.HTML, interpreterResultMessages.get(0).getType());
// clear output
context = getInterpreterContext();
result = interpreter.interpret("import time\nprint(\"Hello\")\n" +
"time.sleep(0.5)\nz.getInterpreterContext().out().clear()\nprint(\"world\")\n", context);
assertEquals("%text world\n", context.out.getCurrentOutput().toString());
}
@Ignore("Flaky test, need to investigate why it fails")
public void testRedefinitionZeppelinContext() throws InterpreterException {
String redefinitionCode = "z = 1\n";
String restoreCode = "z = __zeppelin__\n";
String validCode = "z.input(\"test\")\n";
InterpreterContext context = getInterpreterContext();
InterpreterResult result = interpreter.interpret(validCode, context);
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
context = getInterpreterContext();
result = interpreter.interpret(redefinitionCode, context);
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
context = getInterpreterContext();
result = interpreter.interpret(validCode, context);
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.ERROR, result.code());
context = getInterpreterContext();
result = interpreter.interpret(restoreCode, context);
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
context = getInterpreterContext();
result = interpreter.interpret("type(__zeppelin__)", context);
System.out.println("result: " + context.out.toString() + ", " + result.toString());
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
context = getInterpreterContext();
result = interpreter.interpret("type(z)", context);
System.out.println("result2: " + context.out.toString() + ", " + result.toString());
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
context = getInterpreterContext();
result = interpreter.interpret(validCode, context);
assertEquals(context.out.toString() + ", " + result.toString(),
InterpreterResult.Code.SUCCESS, result.code());
}
protected InterpreterContext getInterpreterContext() {
return InterpreterContext.builder()
.setNoteId("noteId")
.setParagraphId("paragraphId")
.setInterpreterOut(new InterpreterOutput())
.setIntpEventClient(mock(RemoteInterpreterEventClient.class))
.build();
}
}