This is an automated email from the ASF dual-hosted git repository. liuxun 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 f58f8d8 [ZEPPELIN-4171] Configuration paragraph is empty to execute f58f8d8 is described below commit f58f8d88866f7d2c7d041e1a410b82f2bf25e24f Author: Xun Liu <liu...@apache.org> AuthorDate: Mon May 27 11:34:07 2019 +0800 [ZEPPELIN-4171] Configuration paragraph is empty to execute ### What is this PR for? In some cases, For example: `%sh.terminal` interpreter The paragraph is empty and can be executed Add the config configuration section in the `interpreter-setting.json` file of the interpreter. ``` "config": { "checkEmpty": true } ``` ### What type of PR is it? [Improvement] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4171 ### How should this be tested? * [CI Pass](https://travis-ci.org/liuxunorg/zeppelin/builds/537325588) ### Screenshots (if appropriate)  ### Questions: * Does the licenses files need update? * Is there breaking changes for older versions? * Does this needs documentation? Author: Xun Liu <liu...@apache.org> Closes #3371 from liuxunorg/ZEPPELIN-4171 and squashes the following commits: 753a8a3c7 [Xun Liu] Modify according to review comments. ef1889574 [Xun Liu] Improve document description. 5abd7fc86 [Xun Liu] [ZEPPELIN-4171] Check paragraph is empty before execution --- docs/development/writing_zeppelin_interpreter.md | 14 +++++++- .../apache/zeppelin/service/NotebookService.java | 2 +- .../org/apache/zeppelin/notebook/Paragraph.java | 38 ++++++++++++++++++---- .../org/apache/zeppelin/notebook/NotebookTest.java | 23 ++++++++----- .../src/test/resources/conf/interpreter.json | 3 +- .../config_test/interpreter-setting.json | 3 +- 6 files changed, 63 insertions(+), 20 deletions(-) diff --git a/docs/development/writing_zeppelin_interpreter.md b/docs/development/writing_zeppelin_interpreter.md index c613204..27843ac 100644 --- a/docs/development/writing_zeppelin_interpreter.md +++ b/docs/development/writing_zeppelin_interpreter.md @@ -121,7 +121,8 @@ Here is an example of `interpreter-setting.json` on your own interpreter. }, "config": { "runOnSelectionChange": true/false, - "title": true/false + "title": true/false, + "checkEmpty": true/false } }, { @@ -207,6 +208,17 @@ You can make the dynamic form in the notebook not trigger execution after select } ``` + +### Check if the paragraph is empty before running (Optional) +The notebook's paragraph default will not run if it is empty. +You can set `config.checkEmpty=false`, to run even when the paragraph of the notebook is empty. + +```json +"config": { + "checkEmpty": false # default: true +} +``` + ## Install your interpreter binary Once you have built your interpreter, you can place it under the interpreter directory with all its dependencies. diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java index bb42ce2..ccd6639 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java @@ -453,7 +453,7 @@ public class NotebookService { throw new NoteNotFoundException(noteId); } Paragraph newPara = note.insertNewParagraph(index, context.getAutheInfo()); - newPara.setConfig(config); + newPara.mergeConfig(config); notebook.saveNote(note, context.getAutheInfo()); callback.onSuccess(newPara, context); return newPara; diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index 81b5250..1cc0ba7 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -105,10 +105,12 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen private transient Map<String, String> localProperties = new HashMap<>(); private transient Map<String, ParagraphRuntimeInfo> runtimeInfos = new HashMap<>(); - private static String PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE = "runOnSelectionChange"; + public static String PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE = "runOnSelectionChange"; private static boolean PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE_DEFAULT = true; - private static String PARAGRAPH_CONFIG_TITLE = "title"; + public static String PARAGRAPH_CONFIG_TITLE = "title"; private static boolean PARAGRAPH_CONFIG_TITLE_DEFAULT = false; + public static String PARAGRAPH_CONFIG_CHECK_EMTPY = "checkEmpty"; + private static boolean PARAGRAPH_CONFIG_CHECK_EMTPY_DEFAULT = true; @VisibleForTesting Paragraph() { @@ -343,12 +345,30 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen return null; } - public boolean isBlankParagraph() { + public boolean shouldSkipRunParagraph() { + // check interpreter-setting.json `config.checkEmpty` is equal false + Object configCheckEmpty = this.config.get(PARAGRAPH_CONFIG_CHECK_EMTPY); + if (null != configCheckEmpty) { + boolean checkEmtpy = PARAGRAPH_CONFIG_CHECK_EMTPY_DEFAULT; + try { + checkEmtpy = (boolean) configCheckEmpty; + } catch (ClassCastException e) { + LOGGER.error(e.getMessage(), e); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + if (!checkEmtpy) { + LOGGER.info("This interpreter config `interpreter-setting.json` set config.{} = false", + PARAGRAPH_CONFIG_CHECK_EMTPY); + return false; + } + } + return Strings.isNullOrEmpty(scriptText); } public boolean execute(boolean blocking) { - if (isBlankParagraph()) { + if (shouldSkipRunParagraph()) { LOGGER.info("Skip to run blank paragraph. {}", getId()); setStatus(Job.Status.FINISHED); return true; @@ -478,7 +498,7 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen String name = ((ManagedInterpreterGroup) intpGroup).getInterpreterSetting().getName(); Map<String, Object> config = intpSettingManager.getConfigSetting(name); - applyConfigSetting(config); + mergeConfig(config); } } } @@ -601,10 +621,13 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen return config; } + // NOTE: function setConfig(...) will overwrite all configuration + // Merge configuration, you need to use function mergeConfig(...) public void setConfig(Map<String, Object> config) { this.config = config; } + // [ZEPPELIN-3919] Paragraph config default value can be customized // apply the `interpreter-setting.json` config // When creating a paragraph, it will update some of the configuration // parameters of the paragraph from the web side. @@ -615,13 +638,13 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen // 2. The user manually modified the interpreter types of this paragraph. // Need to delete the existing configuration of this paragraph, // update with the specified interpreter configuration - public void applyConfigSetting(Map<String, Object> newConfig) { + public void mergeConfig(Map<String, Object> newConfig) { if (null == newConfig || 0 == newConfig.size()) { newConfig = getDefaultConfigSetting(); } List<String> keysToRemove = Arrays.asList(PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE, - PARAGRAPH_CONFIG_TITLE); + PARAGRAPH_CONFIG_TITLE, PARAGRAPH_CONFIG_CHECK_EMTPY); for (String removeKey : keysToRemove) { if ((false == newConfig.containsKey(removeKey)) && (true == config.containsKey(removeKey))) { @@ -637,6 +660,7 @@ public class Paragraph extends JobWithProgressPoller<InterpreterResult> implemen Map<String, Object> config = new HashMap<>(); config.put(PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE, PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE_DEFAULT); config.put(PARAGRAPH_CONFIG_TITLE, PARAGRAPH_CONFIG_TITLE_DEFAULT); + config.put(PARAGRAPH_CONFIG_CHECK_EMTPY, PARAGRAPH_CONFIG_CHECK_EMTPY_DEFAULT); return config; } diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java index 1629ab2..49023e7 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java @@ -1094,16 +1094,19 @@ public class NotebookTest extends AbstractInterpreterTest implements ParagraphJo // create paragraphs Paragraph p1 = note.addNewParagraph(anonymous); Map<String, Object> config = p1.getConfig(); - assertTrue(config.containsKey("runOnSelectionChange")); - assertTrue(config.containsKey("title")); - assertEquals(config.get("runOnSelectionChange"), false); - assertEquals(config.get("title"), true); + assertTrue(config.containsKey(Paragraph.PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE)); + assertTrue(config.containsKey(Paragraph.PARAGRAPH_CONFIG_TITLE)); + assertTrue(config.containsKey(Paragraph.PARAGRAPH_CONFIG_CHECK_EMTPY)); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE), false); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_TITLE), true); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_CHECK_EMTPY), false); // The config_test interpreter sets the default parameters // in interpreter/config_test/interpreter-setting.json // "config": { // "runOnSelectionChange": false, - // "title": true + // "title": true, + // "checkEmpty": true // }, p1.setText("%config_test sleep 1000"); note.runAll(AuthenticationInfo.ANONYMOUS, false); @@ -1113,8 +1116,9 @@ public class NotebookTest extends AbstractInterpreterTest implements ParagraphJo // Check if the config_test interpreter default parameter takes effect LOGGER.info("p1.getConfig() = " + p1.getConfig()); - assertEquals(config.get("runOnSelectionChange"), false); - assertEquals(config.get("title"), true); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE), false); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_TITLE), true); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_CHECK_EMTPY), false); // The mock1 interpreter does not set default parameters p1.setText("%mock1 sleep 1000"); @@ -1125,8 +1129,9 @@ public class NotebookTest extends AbstractInterpreterTest implements ParagraphJo // Check if the mock1 interpreter parameter is updated LOGGER.info("changed intp p1.getConfig() = " + p1.getConfig()); - assertEquals(config.get("runOnSelectionChange"), true); - assertEquals(config.get("title"), false); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE), true); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_TITLE), false); + assertEquals(config.get(Paragraph.PARAGRAPH_CONFIG_CHECK_EMTPY), true); } @Test diff --git a/zeppelin-zengine/src/test/resources/conf/interpreter.json b/zeppelin-zengine/src/test/resources/conf/interpreter.json index dc3e8ce..62ae850 100644 --- a/zeppelin-zengine/src/test/resources/conf/interpreter.json +++ b/zeppelin-zengine/src/test/resources/conf/interpreter.json @@ -132,7 +132,8 @@ "fontSize": 9, "colWidth": 12, "runOnSelectionChange": false, - "title": true + "title": true, + "checkEmpty": false }, "option": { "remote": true, diff --git a/zeppelin-zengine/src/test/resources/interpreter/config_test/interpreter-setting.json b/zeppelin-zengine/src/test/resources/interpreter/config_test/interpreter-setting.json index 6fd39fc..08d4ac7 100644 --- a/zeppelin-zengine/src/test/resources/interpreter/config_test/interpreter-setting.json +++ b/zeppelin-zengine/src/test/resources/interpreter/config_test/interpreter-setting.json @@ -8,7 +8,8 @@ }, "config": { "runOnSelectionChange": false, - "title": true + "title": true, + "checkEmpty": false }, "option": { "remote": true,