This is an automated email from the ASF dual-hosted git repository.
tbonelee 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 03de344818 [ZEPPELIN-6153] Add display_name to the kernelspec when
exporting to ipynb
03de344818 is described below
commit 03de344818b8153a8ab017da91475d53e91c5dbf
Author: minjcho <[email protected]>
AuthorDate: Sun Aug 9 15:42:59 2026 +0900
[ZEPPELIN-6153] Add display_name to the kernelspec when exporting to ipynb
### What is this PR for?
Exporting a Zeppelin note to ipynb produces a `kernelspec` with only
`language` and `name`:
```java
JsonObject kernelspecJson = new JsonObject();
kernelspecJson.addProperty("language", "scala");
kernelspecJson.addProperty("name", "spark2-scala");
```
The nbformat schema requires `kernelspec.display_name`, so renderers that
validate the schema — GitHub in particular — refuse to display the exported
notebook. The import side already models the field (`nbformat/Kernelspec.java`
has `display_name`); only the export path in `JupyterUtil.getNbformat()` omits
it.
This PR writes `"display_name": "Zeppelin"` into the exported kernelspec,
the default suggested in the JIRA issue. The value is kept as a constant
(`JupyterUtil.KERNEL_DISPLAY_NAME`) and `Kernelspec` gains getters following
the pattern of the sibling nbformat classes (`Metadata`, `Nbformat`), so the
new round-trip test can assert on the deserialized object. The test exports
`spark_example_notebook.zpln`, reads the result back, and checks the kernelspec
carries both `name` and `display_name`.
### What type of PR is it?
Bug Fix
### Todos
* [x] Write `display_name` into the exported kernelspec
* [x] Expose `Kernelspec` fields through getters
* [x] Pin the behaviour with a round-trip test
### What is the Jira issue?
* https://issues.apache.org/jira/browse/ZEPPELIN-6153
### How should this be tested?
```bash
./mvnw test -pl zeppelin-jupyter -Dtest=JupyterUtilTest
-DfailIfNoTests=false
```
`Tests run: 5, Failures: 0, Errors: 0, Skipped: 0`
To verify end-to-end: export any note to ipynb and push it to a GitHub
repository — the notebook now renders instead of showing "Invalid Notebook".
### Screenshots (if appropriate)
N/A
### Questions:
* Does the license files need to update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No
Closes #5397 from minjcho/ZEPPELIN-6153.
Signed-off-by: ChanHo Lee <[email protected]>
---
.../java/org/apache/zeppelin/jupyter/JupyterUtil.java | 5 +++++
.../apache/zeppelin/jupyter/nbformat/Kernelspec.java | 8 ++++++++
.../zeppelin/jupyter/nbformat/JupyterUtilTest.java | 17 +++++++++++++++++
3 files changed, 30 insertions(+)
diff --git
a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java
b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java
index 81fda1a39d..3135d57212 100644
---
a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java
+++
b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java
@@ -64,6 +64,8 @@ public class JupyterUtil {
private static final Gson PRETTY_GSON = new
GsonBuilder().setPrettyPrinting().create();
+ public static final String KERNEL_DISPLAY_NAME = "Zeppelin";
+
private final RuntimeTypeAdapterFactory<Cell> cellTypeFactory;
private final RuntimeTypeAdapterFactory<Output> outputTypeFactory;
@@ -239,6 +241,9 @@ public class JupyterUtil {
JsonObject kernelspecJson = new JsonObject();
kernelspecJson.addProperty("language", "scala");
kernelspecJson.addProperty("name", "spark2-scala");
+ // display_name is required by the nbformat schema. Renderers such as
GitHub
+ // fail to display the notebook when it is missing.
+ kernelspecJson.addProperty("display_name", KERNEL_DISPLAY_NAME);
JsonObject languageInfoJson = new JsonObject();
languageInfoJson.addProperty("codemirror_mode", "text/x-scala");
diff --git
a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java
b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java
index 6232416851..ddfd7e99af 100644
---
a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java
+++
b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java
@@ -28,4 +28,12 @@ public class Kernelspec {
@SerializedName("display_name")
private String displayName;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
}
diff --git
a/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java
b/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java
index 7ae8e2449f..ba30607f6e 100644
---
a/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java
+++
b/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java
@@ -114,4 +114,21 @@ class JupyterUtilTest {
assertEquals(3 , nbformat.getCells().stream().filter(c -> c instanceof
MarkdownCell).count());
assertEquals(4 , nbformat.getCells().stream().filter(c -> c instanceof
CodeCell).count());
}
+
+ @Test
+ void testGetNbformatKernelspec() {
+ InputStream resource =
getClass().getResourceAsStream("/spark_example_notebook.zpln");
+ String text = new BufferedReader(
+ new InputStreamReader(resource, StandardCharsets.UTF_8))
+ .lines()
+ .collect(Collectors.joining("\n"));
+ JupyterUtil util = new JupyterUtil();
+ Nbformat nbformat = util.getNbformat(new
StringReader(util.getNbformat(text)));
+
+ Kernelspec kernelspec = nbformat.getMetadata().getKernelspec();
+ assertNotNull(kernelspec);
+ assertEquals("spark2-scala", kernelspec.getName());
+ // display_name is required by the nbformat schema, see ZEPPELIN-6153
+ assertEquals(JupyterUtil.KERNEL_DISPLAY_NAME, kernelspec.getDisplayName());
+ }
}