This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 13d3912  [ZEPPELIN-4508]. Completion doesn't work in jupyter 
interpreter
13d3912 is described below

commit 13d391273fc6d77fe0a64471e6bc585e9c866d53
Author: Jeff Zhang <zjf...@apache.org>
AuthorDate: Wed Dec 25 11:59:36 2019 +0800

    [ZEPPELIN-4508]. Completion doesn't work in jupyter interpreter
    
    ### What is this PR for?
    
    `getCompletions` is missing for `JupyterInterpreter`, this PR fix that and 
also add IPythonKernelTest to verify all the features of `JupyterInterpreter`
    
    ### What type of PR is it?
    [Bug Fix]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * https://jira.apache.org/jira/browse/ZEPPELIN-4508
    
    ### How should this be tested?
    * CI pass
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Jeff Zhang <zjf...@apache.org>
    
    Closes #3567 from zjffdu/ZEPPELIN-4508 and squashes the following commits:
    
    9d9544061 [Jeff Zhang] [ZEPPELIN-4508]. Completion doesn't work in jupyter 
interpreter
---
 zeppelin-jupyter-interpreter/pom.xml               |   2 +-
 .../zeppelin/jupyter/JupyterInterpreter.java       |  20 +-
 .../src/main/resources/interpreter-setting.json    |   1 +
 .../apache/zeppelin/jupyter/IPythonKernelTest.java | 261 +++++++++++++++++++++
 4 files changed, 282 insertions(+), 2 deletions(-)

diff --git a/zeppelin-jupyter-interpreter/pom.xml 
b/zeppelin-jupyter-interpreter/pom.xml
index ffc8daa..a924717 100644
--- a/zeppelin-jupyter-interpreter/pom.xml
+++ b/zeppelin-jupyter-interpreter/pom.xml
@@ -31,7 +31,7 @@
   <artifactId>zeppelin-jupyter-interpreter</artifactId>
   <packaging>jar</packaging>
   <version>0.9.0-SNAPSHOT</version>
-  <name>Zeppelin: Jupyter Adapter</name>
+  <name>Zeppelin: Jupyter Interpreter</name>
 
   <properties>
     <interpreter.name>jupyter</interpreter.name>
diff --git 
a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterInterpreter.java
 
b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterInterpreter.java
index b359468..66d42e8 100644
--- 
a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterInterpreter.java
+++ 
b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterInterpreter.java
@@ -23,8 +23,10 @@ import org.apache.zeppelin.interpreter.BaseZeppelinContext;
 import org.apache.zeppelin.interpreter.InterpreterContext;
 import org.apache.zeppelin.interpreter.InterpreterException;
 import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -86,7 +88,7 @@ public class JupyterInterpreter extends AbstractInterpreter {
       throw new InterpreterException("No kernel is specified");
     }
     JupyterKernelInterpreter kernelInterpreter = 
kernelInterpreterMap.get(kernel);
-    if (kernelInterpreter != null) {
+    if (kernelInterpreter == null) {
       throw new InterpreterException("No such interpreter: " + kernel);
     }
     kernelInterpreter.cancel(context);
@@ -109,4 +111,20 @@ public class JupyterInterpreter extends 
AbstractInterpreter {
     }
     return  kernelInterpreter.getProgress(context);
   }
+
+  @Override
+  public List<InterpreterCompletion> completion(
+          String buf,
+          int cursor,
+          InterpreterContext context) throws InterpreterException {
+    String kernel = context.getLocalProperties().get("kernel");
+    if (kernel == null) {
+      throw new InterpreterException("No kernel is specified");
+    }
+    JupyterKernelInterpreter kernelInterpreter = 
kernelInterpreterMap.get(kernel);
+    if (kernelInterpreter == null) {
+      throw new InterpreterException("No such interpreter: " + kernel);
+    }
+    return kernelInterpreter.completion(buf, cursor, context);
+  }
 }
diff --git 
a/zeppelin-jupyter-interpreter/src/main/resources/interpreter-setting.json 
b/zeppelin-jupyter-interpreter/src/main/resources/interpreter-setting.json
index 19181f7..fbb1fdf 100644
--- a/zeppelin-jupyter-interpreter/src/main/resources/interpreter-setting.json
+++ b/zeppelin-jupyter-interpreter/src/main/resources/interpreter-setting.json
@@ -8,6 +8,7 @@
     "editor": {
       "language": "text",
       "editOnDblClick": false,
+      "completionKey": "TAB",
       "completionSupport": true
     }
   }
diff --git 
a/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IPythonKernelTest.java
 
b/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IPythonKernelTest.java
new file mode 100644
index 0000000..af8f881
--- /dev/null
+++ 
b/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IPythonKernelTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.jupyter;
+
+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.LazyOpenInterpreter;
+import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient;
+import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+
+/**
+ * TODO(zjffdu) These tests are copied from python module.
+ * Should reorganize them to avoid code duplication.
+ */
+public class IPythonKernelTest {
+
+  protected InterpreterGroup intpGroup;
+  protected Interpreter interpreter;
+
+  @Before
+  public void setUp() throws InterpreterException {
+    Properties properties = new Properties();
+    interpreter = new LazyOpenInterpreter(new JupyterInterpreter(properties));
+    intpGroup = new InterpreterGroup();
+    intpGroup.put("session_1", new ArrayList<Interpreter>());
+    intpGroup.get("session_1").add(interpreter);
+    interpreter.setInterpreterGroup(intpGroup);
+
+    interpreter.open();
+  }
+
+  @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());
+
+    interpreterResultMessages = context.out.toInterpreterResultMessage();
+    assertEquals(1, interpreterResultMessages.size());
+    assertTrue(interpreterResultMessages.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());
+
+    interpreterResultMessages = context.out.toInterpreterResultMessage();
+    assertEquals(1, interpreterResultMessages.size());
+    
assertTrue(interpreterResultMessages.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());
+  }
+
+  protected InterpreterContext getInterpreterContext() {
+    Map<String, String> localProperties = new HashMap<>();
+    localProperties.put("kernel", "python");
+    return InterpreterContext.builder()
+            .setNoteId("noteId")
+            .setParagraphId("paragraphId")
+            .setInterpreterOut(new InterpreterOutput(null))
+            .setIntpEventClient(mock(RemoteInterpreterEventClient.class))
+            .setLocalProperties(localProperties)
+            .build();
+  }
+}

Reply via email to