Skip to content

Commit 40578bf

Browse files
#59 Make BaseKernel#eval() throw runtime EvaluationException
1 parent 78dbc4e commit 40578bf

File tree

7 files changed

+102
-16
lines changed

7 files changed

+102
-16
lines changed

jjava/pom.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@
4141
<artifactId>testcontainers</artifactId>
4242
<scope>test</scope>
4343
</dependency>
44+
<dependency>
45+
<groupId>org.mockito</groupId>
46+
<artifactId>mockito-core</artifactId>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.mockito</groupId>
51+
<artifactId>mockito-junit-jupiter</artifactId>
52+
<scope>test</scope>
53+
</dependency>
4454
<dependency>
4555
<groupId>org.slf4j</groupId>
4656
<artifactId>slf4j-simple</artifactId>
@@ -189,6 +199,15 @@
189199
</filesets>
190200
</configuration>
191201
</plugin>
202+
<plugin>
203+
<groupId>org.apache.maven.plugins</groupId>
204+
<artifactId>maven-surefire-plugin</artifactId>
205+
<configuration>
206+
<argLine>
207+
--add-opens jdk.jshell/jdk.jshell=ALL-UNNAMED
208+
</argLine>
209+
</configuration>
210+
</plugin>
192211
</plugins>
193212
</build>
194213

jjava/src/main/java/org/dflib/jjava/JJavaExtension.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ public class JJavaExtension implements Extension {
2525

2626
@Override
2727
public void install(BaseKernel kernel) {
28-
try {
29-
kernel.eval(STARTUP_SCRIPT);
30-
} catch (Exception e) {
31-
throw new RuntimeException(e);
32-
}
28+
kernel.eval(STARTUP_SCRIPT);
3329
}
3430
}

jjava/src/main/java/org/dflib/jjava/JavaKernel.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.dflib.jjava.execution.MagicsSourceTransformer;
4040
import org.dflib.jjava.jupyter.Extension;
4141
import org.dflib.jjava.jupyter.kernel.BaseKernel;
42+
import org.dflib.jjava.jupyter.kernel.EvaluationException;
4243
import org.dflib.jjava.jupyter.kernel.LanguageInfo;
4344
import org.dflib.jjava.jupyter.kernel.ReplacementOptions;
4445
import org.dflib.jjava.jupyter.kernel.display.DisplayData;
@@ -210,7 +211,9 @@ public boolean autoLoadExtensions() {
210211
}
211212

212213
@Override
213-
public List<String> formatError(Exception e) {
214+
public List<String> formatError(Throwable e) {
215+
if (e instanceof EvaluationException)
216+
return formatError(e.getCause());
214217
if (e instanceof CompilationException) {
215218
return formatCompilationException((CompilationException) e);
216219
} else if (e instanceof IncompleteSourceException) {
@@ -338,15 +341,20 @@ public Object evalRaw(String expr) throws Exception {
338341
}
339342

340343
@Override
341-
public DisplayData eval(String expr) throws Exception {
342-
Object result = this.evalRaw(expr);
343-
344-
if (result != null)
345-
return result instanceof DisplayData
346-
? (DisplayData) result
347-
: this.getRenderer().render(result);
344+
public DisplayData eval(String expr) {
345+
Object result;
346+
try {
347+
result = this.evalRaw(expr);
348+
} catch (Exception e) {
349+
throw new EvaluationException(e);
350+
}
348351

349-
return null;
352+
if (result == null) {
353+
return null;
354+
}
355+
return result instanceof DisplayData
356+
? (DisplayData) result
357+
: this.getRenderer().render(result);
350358
}
351359

352360
@Override
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.dflib.jjava;
2+
3+
import org.dflib.jjava.jupyter.kernel.EvaluationException;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.*;
7+
import static org.mockito.Mockito.mock;
8+
import static org.mockito.Mockito.when;
9+
10+
public class JavaKernelTest {
11+
12+
@Test
13+
public void eval_throwsRuntimeException() throws Exception {
14+
JavaKernel kernel = new JavaKernel("0");
15+
String expr = "invalid expression";
16+
17+
JavaKernel mockKernel = mock(JavaKernel.class);
18+
when(mockKernel.evalRaw(expr)).thenThrow(new Exception("Evaluation error"));
19+
20+
assertThrows(EvaluationException.class, () -> kernel.eval(expr));
21+
}
22+
}

jupyter-jvm-basekernel/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernel.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,30 @@ public HistoryManager getHistoryManager() {
161161
return null;
162162
}
163163

164-
public abstract DisplayData eval(String expr) throws Exception;
164+
/**
165+
* Evaluates a code expression in the kernel's language environment and returns the result
166+
* as display data. This is the core evaluation method called when executing code cells
167+
* in a Jupyter notebook.
168+
*
169+
* <p>The implementation should:
170+
* <ul>
171+
* <li>Parse and evaluate the provided expression string</li>
172+
* <li>Convert the evaluation result into appropriate display data formats</li>
173+
* <li>Handle any language-specific evaluation context/scope</li>
174+
* </ul>
175+
*
176+
* <p>The returned {@link DisplayData} can contain multiple representations of the result
177+
* (e.g. text/plain, text/html, image/png) to allow rich display in the notebook.
178+
* Return null if the expression produces no displayable result.
179+
*
180+
* @param expr The code expression to evaluate as received from the Jupyter frontend
181+
*
182+
* @return A {@link DisplayData} object containing the evaluation result in one or more
183+
* MIME formats, or null if there is no displayable result
184+
*
185+
* @throws EvaluationException If an error occurs during expression evaluation
186+
*/
187+
public abstract DisplayData eval(String expr);
165188

166189
/**
167190
* Inspect the code to get things such as documentation for a function. This is
@@ -283,7 +306,7 @@ public void interrupt() {
283306
* not include strings with newlines but rather separate strings each to go on a
284307
* new line.
285308
*/
286-
public List<String> formatError(Exception e) {
309+
public List<String> formatError(Throwable e) {
287310
List<String> lines = new LinkedList<>();
288311
lines.add(this.errorStyler.secondary("---------------------------------------------------------------------------"));
289312

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.dflib.jjava.jupyter.kernel;
2+
3+
import java.util.Objects;
4+
5+
public class EvaluationException extends RuntimeException {
6+
7+
public EvaluationException(Throwable cause) {
8+
super(Objects.requireNonNull(cause));
9+
}
10+
}

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<hamcrest.version>1.3</hamcrest.version>
5454
<jimfs.version>1.3.0</jimfs.version>
5555
<testcontainers.version>1.20.2</testcontainers.version>
56+
<mockito.version>5.3.1</mockito.version>
5657
<slf4j.version>1.7.36</slf4j.version>
5758
</properties>
5859

@@ -126,6 +127,13 @@
126127
<artifactId>testcontainers</artifactId>
127128
<version>${testcontainers.version}</version>
128129
</dependency>
130+
<dependency>
131+
<groupId>org.mockito</groupId>
132+
<artifactId>mockito-bom</artifactId>
133+
<version>${mockito.version}</version>
134+
<type>pom</type>
135+
<scope>import</scope>
136+
</dependency>
129137
<dependency>
130138
<groupId>org.slf4j</groupId>
131139
<artifactId>slf4j-simple</artifactId>

0 commit comments

Comments
 (0)