Skip to content

Commit b37f94a

Browse files
committed
"%load" magic should not be adding extensions to file names #115
1 parent bc34004 commit b37f94a

4 files changed

Lines changed: 127 additions & 133 deletions

File tree

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 1.0-a8
22

33
* #114 %load magic does not recognize notebooks
4+
* #115 "%load" magic should not be adding extensions to file names
45

56
## 1.0-a7
67

jjava-distro/src/main/java/org/dflib/jjava/distro/JJava.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.dflib.jjava.kernel.JavaKernel;
66
import org.dflib.jjava.kernel.magics.ClasspathMagic;
77
import org.dflib.jjava.kernel.magics.JarsMagic;
8-
import org.dflib.jjava.kernel.magics.LoadCodeMagic;
8+
import org.dflib.jjava.kernel.magics.LoadMagic;
99
import org.dflib.jjava.kernel.magics.TimeMagic;
1010
import org.dflib.jjava.maven.MavenDependencyResolver;
1111
import org.dflib.jjava.maven.magics.AddMavenDependencyMagic;
@@ -65,7 +65,7 @@ public static void main(String[] args) throws Exception {
6565
.compilerOpts(Env.compilerOpts())
6666
.timeout(timeout.time, timeout.timeUnit)
6767

68-
.lineMagic("load", new LoadCodeMagic("", ".jsh", ".jshell", ".java", ".jjava"))
68+
.lineMagic("load", new LoadMagic())
6969
.lineMagic("classpath", new ClasspathMagic())
7070
.lineMagic("time", timeMagic)
7171

jjava-kernel/src/main/java/org/dflib/jjava/kernel/magics/LoadCodeMagic.java

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package org.dflib.jjava.kernel.magics;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import com.google.gson.stream.JsonReader;
6+
import org.dflib.jjava.jupyter.kernel.magic.LineMagic;
7+
import org.dflib.jjava.jupyter.kernel.magic.MagicsArgs;
8+
import org.dflib.jjava.kernel.JavaKernel;
9+
10+
import java.io.FileNotFoundException;
11+
import java.io.Reader;
12+
import java.nio.charset.StandardCharsets;
13+
import java.nio.file.Files;
14+
import java.nio.file.Path;
15+
import java.nio.file.Paths;
16+
import java.util.List;
17+
import java.util.Map;
18+
19+
public class LoadMagic implements LineMagic<Void, JavaKernel> {
20+
21+
private static final String NOTEBOOK_EXTENSION = ".ipynb";
22+
private static final Gson GSON = new GsonBuilder().create();
23+
private static final MagicsArgs LOAD_ARGS = MagicsArgs.builder()
24+
.required("source")
25+
.onlyKnownFlags()
26+
.onlyKnownKeywords()
27+
.build();
28+
29+
@Override
30+
public Void eval(JavaKernel kernel, List<String> args) throws Exception {
31+
32+
Map<String, List<String>> vals = LOAD_ARGS.parse(args);
33+
Path sourcePath = Paths.get(vals.get("source").get(0)).toAbsolutePath();
34+
35+
String file = sourcePath.getFileName().toString();
36+
Path scriptPath = sourcePath.resolveSibling(file);
37+
if (!Files.isRegularFile(scriptPath)) {
38+
throw new FileNotFoundException("Could not find any source at '" + sourcePath);
39+
}
40+
41+
// TODO: return the eval result to the caller?
42+
Object result = (isNotebook(scriptPath))
43+
? evalNotebook(kernel, scriptPath)
44+
: kernel.evalBuilder(Files.readString(scriptPath)).resolveMagics().eval();
45+
46+
return null;
47+
}
48+
49+
private boolean isNotebook(Path scriptPath) {
50+
// ".toString()" is important. "Path.endsWith(..)" means something entirely different
51+
return scriptPath.getFileName().toString().endsWith(NOTEBOOK_EXTENSION);
52+
}
53+
54+
// This slightly verbose implementation is designed to take advantage of gson as a streaming parser
55+
// in which we can only take what we need on the fly and pass each cell to the handler without needing
56+
// to keep the entire (possibly large) notebook in memory.
57+
private Object evalNotebook(JavaKernel kernel, Path notebookPath) throws Exception {
58+
try (Reader in = Files.newBufferedReader(notebookPath, StandardCharsets.UTF_8)) {
59+
try (JsonReader reader = GSON.newJsonReader(in)) {
60+
return evalNotebook(kernel, reader);
61+
}
62+
}
63+
}
64+
65+
private Object evalNotebook(JavaKernel kernel, JsonReader reader) throws Exception {
66+
67+
Object lastResult = null;
68+
69+
reader.beginObject();
70+
while (reader.hasNext()) {
71+
String name = reader.nextName();
72+
if (!name.equals("cells")) {
73+
reader.skipValue();
74+
continue;
75+
}
76+
77+
// Parsing cells
78+
reader.beginArray();
79+
while (reader.hasNext()) {
80+
Boolean isCode = null;
81+
String source = null;
82+
83+
reader.beginObject();
84+
while (reader.hasNext()) {
85+
// If the cell type was parsed and wasn't code, then don't
86+
// bother doing any more work. Skip the rest.
87+
if (isCode != null && !isCode) {
88+
reader.skipValue();
89+
continue;
90+
}
91+
92+
switch (reader.nextName()) {
93+
case "cell_type":
94+
// We are only concerned with code cells.
95+
String cellType = reader.nextString();
96+
isCode = cellType.equals("code");
97+
break;
98+
case "source":
99+
// "source" is an array of lines.
100+
StringBuilder srcBuilder = new StringBuilder();
101+
reader.beginArray();
102+
while (reader.hasNext())
103+
srcBuilder.append(reader.nextString());
104+
reader.endArray();
105+
source = srcBuilder.toString();
106+
break;
107+
default:
108+
reader.skipValue();
109+
break;
110+
}
111+
}
112+
reader.endObject();
113+
114+
if (isCode != null && isCode) {
115+
lastResult = kernel.evalBuilder(source).resolveMagics().eval();
116+
}
117+
}
118+
reader.endArray();
119+
}
120+
reader.endObject();
121+
122+
return lastResult;
123+
}
124+
}

0 commit comments

Comments
 (0)