Skip to content

Commit 3a14979

Browse files
Merge remote-tracking branch 'origin/main' into fix-win-tests
2 parents 98f8599 + f04acb8 commit 3a14979

17 files changed

Lines changed: 165 additions & 212 deletions

File tree

RELEASE-NOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.0-a7
2+
3+
* #67 JJAVA_STARTUP_SCRIPT can't start up spark
4+
* #102 Eval startup snippets explicitly
5+
16
## 1.0-a6
27

38
* #68 CompilationException doesn't provide any information about the underlying problem

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ public static void main(String[] args) throws Exception {
5555
.version((String) pomProps.getOrDefault("version", ""))
5656

5757
.extensionsEnabled(Env.extensionsEnabled())
58-
.startupSnippets(Env.startupSnippets())
5958
.compilerOpts(Env.compilerOpts())
6059
.timeout(Env.timeout())
6160

@@ -79,6 +78,9 @@ public static void main(String[] args) throws Exception {
7978
// process custom locations: expand JShell classpath, install extensions from those places (if enabled)
8079
kernel.addToClasspath(Env.extraClasspath());
8180

81+
// run user defined startup snippets explicitly after the default startup
82+
Env.startupSnippets().forEach(kernel::evalRaw);
83+
8284
// connect to Jupyter
8385
kernel.becomeHandlerForConnection(connection);
8486
connection.connect();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class Opts {
77

8-
// TODO: see 7205d03766c8 and c91ade8fec0cdc. A similar split method in MagicParser got altered in a few subtle
8+
// TODO: see 7205d03766c8 and c91ade8fec0cdc. A similar split method in MagicsResolver got altered in a few subtle
99
// ways... Do those changes alloy here, and should we have a single splitter?
1010
// 7205d03766c8
1111
// - if (current.length() > 0 && inQuotes) {

jjava-distro/src/test/java/org/dflib/jjava/distro/KernelStartupIT.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import org.junit.jupiter.api.Test;
44
import org.testcontainers.containers.Container;
55

6+
import java.util.Map;
67
import static org.hamcrest.Matchers.containsString;
78
import static org.hamcrest.Matchers.not;
89
import static org.hamcrest.MatcherAssert.assertThat;
10+
import static org.hamcrest.Matchers.matchesPattern;
911
import static org.junit.jupiter.api.Assertions.assertEquals;
1012

1113
class KernelStartupIT extends ContainerizedKernelCase {
@@ -19,4 +21,17 @@ void startUp() throws Exception {
1921
assertThat(snippetResult.getStdout(), not(containsString("|")));
2022
assertThat(snippetResult.getStdout(), containsString("1001.0"));
2123
}
24+
25+
@Test
26+
void startUp_scriptRequiresClasspath() throws Exception {
27+
Map<String, String> env = Map.of(
28+
Env.JJAVA_CLASSPATH, TEST_CLASSPATH,
29+
Env.JJAVA_STARTUP_SCRIPT, "var obj = new org.dflib.jjava.Dummy()"
30+
);
31+
String snippet = "\"hash = \" + obj.hashCode()";
32+
Container.ExecResult snippetResult = executeInKernel(snippet, env);
33+
34+
assertThat(snippetResult.getStdout(), not(containsString("|")));
35+
assertThat(snippetResult.getStdout(), matchesPattern("(?s).*hash = -?\\d+.*"));
36+
}
2237
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.dflib.jjava.jupyter.kernel.display.common.Url;
1212
import org.dflib.jjava.jupyter.kernel.history.HistoryEntry;
1313
import org.dflib.jjava.jupyter.kernel.history.HistoryManager;
14-
import org.dflib.jjava.jupyter.kernel.magic.MagicParser;
14+
import org.dflib.jjava.jupyter.kernel.magic.MagicsResolver;
1515
import org.dflib.jjava.jupyter.kernel.magic.MagicsRegistry;
1616
import org.dflib.jjava.jupyter.kernel.util.PathsHandler;
1717
import org.dflib.jjava.jupyter.kernel.util.StringStyler;
@@ -85,7 +85,7 @@ public abstract class BaseKernel {
8585
protected final JupyterIO io;
8686
protected final CommManager commManager;
8787
protected final Renderer renderer;
88-
protected final MagicParser magicParser;
88+
protected final MagicsResolver magicsResolver;
8989
protected final MagicsRegistry magicsRegistry;
9090
protected final Map<String, Extension> extensions;
9191
protected final boolean extensionsEnabled;
@@ -111,7 +111,7 @@ protected BaseKernel(
111111
JupyterIO io,
112112
CommManager commManager,
113113
Renderer renderer,
114-
MagicParser magicParser,
114+
MagicsResolver magicsResolver,
115115
MagicsRegistry magicsRegistry,
116116
boolean extensionsEnabled,
117117
StringStyler errorStyler) {
@@ -127,7 +127,7 @@ protected BaseKernel(
127127
this.io = Objects.requireNonNull(io);
128128
this.commManager = Objects.requireNonNull(commManager);
129129
this.renderer = Objects.requireNonNull(renderer);
130-
this.magicParser = magicParser;
130+
this.magicsResolver = magicsResolver;
131131
this.magicsRegistry = magicsRegistry;
132132
this.extensionsEnabled = extensionsEnabled;
133133
this.extensions = new ConcurrentHashMap<>();
@@ -156,8 +156,8 @@ public MagicsRegistry getMagicsRegistry() {
156156
return magicsRegistry;
157157
}
158158

159-
public MagicParser getMagicParser() {
160-
return magicParser;
159+
public MagicsResolver getMagicsResolver() {
160+
return magicsResolver;
161161
}
162162

163163
public JupyterIO getIO() {

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernelBuilder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.dflib.jjava.jupyter.kernel.history.HistoryManager;
66
import org.dflib.jjava.jupyter.kernel.magic.CellMagic;
77
import org.dflib.jjava.jupyter.kernel.magic.LineMagic;
8-
import org.dflib.jjava.jupyter.kernel.magic.MagicParser;
8+
import org.dflib.jjava.jupyter.kernel.magic.MagicsResolver;
99
import org.dflib.jjava.jupyter.kernel.magic.MagicTranspiler;
1010
import org.dflib.jjava.jupyter.kernel.magic.MagicsRegistry;
1111
import org.dflib.jjava.jupyter.kernel.util.StringStyler;
@@ -24,7 +24,7 @@ public abstract class BaseKernelBuilder<
2424
protected String name;
2525
protected String version;
2626
protected Charset jupyterIOEncoding;
27-
protected MagicParser magicParser;
27+
protected MagicsResolver magicsResolver;
2828
protected MagicTranspiler magicTranspiler;
2929
protected HistoryManager historyManager;
3030
protected Boolean extensionsEnabled;
@@ -64,8 +64,8 @@ public B cellMagic(String name, CellMagic<?, ?> magic) {
6464
return (B) this;
6565
}
6666

67-
public B magicParser(MagicParser magicParser) {
68-
this.magicParser = magicParser;
67+
public B magicsResolver(MagicsResolver magicsResolver) {
68+
this.magicsResolver = magicsResolver;
6969
return (B) this;
7070
}
7171

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/magic/CellMagicArgs.java

Lines changed: 0 additions & 13 deletions
This file was deleted.

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/magic/LineMagicArgs.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/magic/MagicTranspiler.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import java.util.stream.Collectors;
99

1010
/**
11-
* A converter (aka "transpiler") of the generic magic syntax into kernel-specific syntax (such as Java).
11+
* A converter (aka "transpiler") of generic syntax of a single magic into kernel-specific syntax (such as Java).
1212
*/
1313
public class MagicTranspiler {
1414

@@ -21,29 +21,29 @@ public class MagicTranspiler {
2121

2222
public String transpileCell(ParsedCellMagic magic) {
2323
return String.format(CELL_CALL_TEMPLATE,
24-
argWithEscapingToJava(magic.magicCall.name),
25-
magic.magicCall.args.stream()
24+
argWithEscapingToJava(magic.name),
25+
magic.args.stream()
2626
.map(this::argWithEscapingToJava)
2727
.collect(Collectors.joining(",")),
28-
argWithEscapingToJava(magic.magicCall.body)
28+
argWithEscapingToJava(magic.cellBodyAfterMagic)
2929
);
3030
}
3131

3232
public String transpileLine(ParsedLineMagic magic) {
3333
boolean inString = false;
34-
Matcher m = UNESCAPED_QUOTE.matcher(magic.linePrefix);
34+
Matcher m = UNESCAPED_QUOTE.matcher(magic.magicLinePrefix);
3535
while (m.find()) {
3636
inString = !inString;
3737
}
3838

3939
// If in a string literal, don't apply the magic, just use the original
4040
if (inString) {
41-
return magic.raw;
41+
return magic.unparsedMagic;
4242
}
4343

4444
return String.format(LINE_CALL_TEMPLATE,
45-
argWithEscapingToJava(magic.magicCall.name),
46-
magic.magicCall.args.stream()
45+
argWithEscapingToJava(magic.name),
46+
magic.args.stream()
4747
.map(this::argWithEscapingToJava)
4848
.collect(Collectors.joining(","))
4949
);

jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/magic/MagicParser.java renamed to jjava-jupyter/src/main/java/org/dflib/jjava/jupyter/kernel/magic/MagicsResolver.java

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,79 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5-
import java.util.Optional;
65
import java.util.regex.Matcher;
76
import java.util.regex.Pattern;
87

98
/**
109
* Locates line and cell magic syntax in the cell code and replaces it with code native to the underlying kernel.
10+
* Code replacement happens via {@link MagicTranspiler}.
1111
*/
12-
public class MagicParser {
12+
public class MagicsResolver {
13+
14+
private final Pattern lineMagicPattern;
15+
private final Pattern cellMagicPattern;
16+
private final MagicTranspiler magicTranspiler;
17+
18+
public MagicsResolver(String lineMagicStart, String cellMagicStart, MagicTranspiler magicTranspiler) {
19+
this.lineMagicPattern = Pattern.compile(lineMagicStart + "(?<args>\\w.*?)$", Pattern.MULTILINE);
20+
this.cellMagicPattern = Pattern.compile("^(?<argsLine>" + cellMagicStart + "(?<args>\\w.*?))\\R(?<body>(?sU).+?)$");
21+
this.magicTranspiler = magicTranspiler;
22+
}
23+
24+
/**
25+
* Replaces cell and line magics in the source with native kernel code.
26+
*/
27+
public String resolve(String cellSource) {
28+
ParsedCellMagic parsedCell = parseCellMagic(cellSource);
29+
return parsedCell != null
30+
? magicTranspiler.transpileCell(parsedCell)
31+
: resolveLineMagics(cellSource);
32+
}
33+
34+
String resolveLineMagics(String cellSource) {
35+
36+
StringBuffer out = new StringBuffer();
37+
Matcher m = lineMagicPattern.matcher(cellSource);
38+
39+
while (m.find()) {
40+
ParsedLineMagic parsed = parseLineMagic(cellSource, m);
41+
String transformed = magicTranspiler.transpileLine(parsed);
42+
m.appendReplacement(out, Matcher.quoteReplacement(transformed));
43+
}
44+
45+
m.appendTail(out);
46+
return out.toString();
47+
}
48+
49+
ParsedCellMagic parseCellMagic(String cellSource) {
50+
Matcher m = cellMagicPattern.matcher(cellSource);
51+
52+
if (!m.matches()) {
53+
return null;
54+
}
55+
56+
List<String> split = split(m.group("args"));
57+
String bodyAfterMagic = m.group("body");
58+
59+
return new ParsedCellMagic(
60+
split.get(0),
61+
split.subList(1, split.size()),
62+
bodyAfterMagic);
63+
}
64+
65+
private ParsedLineMagic parseLineMagic(String cellSource, Matcher matchedLine) {
66+
List<String> split = split(matchedLine.group("args"));
67+
68+
String rawLinePrefix = cellSource.substring(0, matchedLine.start());
69+
String linePrefix = rawLinePrefix.substring(rawLinePrefix.lastIndexOf('\n') + 1);
70+
71+
return new ParsedLineMagic(
72+
split.get(0),
73+
split.subList(1, split.size()),
74+
linePrefix,
75+
matchedLine.group()
76+
);
77+
}
1378

1479
static List<String> split(String args) {
1580
args = args.trim();
@@ -64,69 +129,4 @@ static List<String> split(String args) {
64129

65130
return split;
66131
}
67-
68-
private final Pattern lineMagicPattern;
69-
private final Pattern cellMagicPattern;
70-
private final MagicTranspiler transpiler;
71-
72-
public MagicParser(String lineMagicStart, String cellMagicStart, MagicTranspiler transpiler) {
73-
this.lineMagicPattern = Pattern.compile(lineMagicStart + "(?<args>\\w.*?)$", Pattern.MULTILINE);
74-
this.cellMagicPattern = Pattern.compile("^(?<argsLine>" + cellMagicStart + "(?<args>\\w.*?))\\R(?<body>(?sU).+?)$");
75-
this.transpiler = transpiler;
76-
}
77-
78-
/**
79-
* Replaces cell and line magics in the source with native kernel code.
80-
*/
81-
public String resolveMagics(String cellSource) {
82-
return transpileCellMagic(cellSource).orElse(transpileLineMagics(cellSource));
83-
}
84-
85-
private Optional<String> transpileCellMagic(String cellSource) {
86-
ParsedCellMagic parsedCell = parseCellMagic(cellSource);
87-
return Optional.ofNullable(parsedCell).map(transpiler::transpileCell);
88-
}
89-
90-
String transpileLineMagics(String cellSource) {
91-
92-
StringBuffer out = new StringBuffer();
93-
Matcher m = lineMagicPattern.matcher(cellSource);
94-
95-
while (m.find()) {
96-
ParsedLineMagic parsed = parseLineMagic(cellSource, m);
97-
String transformed = transpiler.transpileLine(parsed);
98-
m.appendReplacement(out, Matcher.quoteReplacement(transformed));
99-
}
100-
101-
m.appendTail(out);
102-
return out.toString();
103-
}
104-
105-
ParsedCellMagic parseCellMagic(String cellSource) {
106-
Matcher m = this.cellMagicPattern.matcher(cellSource);
107-
108-
if (!m.matches()) {
109-
return null;
110-
}
111-
112-
String rawArgsLine = m.group("argsLine");
113-
String rawArgs = m.group("args");
114-
String body = m.group("body");
115-
List<String> split = split(rawArgs);
116-
117-
CellMagicArgs args = new CellMagicArgs(split.get(0), split.subList(1, split.size()), body);
118-
return new ParsedCellMagic(args, rawArgsLine, cellSource);
119-
}
120-
121-
private ParsedLineMagic parseLineMagic(String cellSource, Matcher matchedLine) {
122-
String raw = matchedLine.group();
123-
String rawArgs = matchedLine.group("args");
124-
List<String> split = split(rawArgs);
125-
126-
LineMagicArgs args = new LineMagicArgs(split.get(0), split.subList(1, split.size()));
127-
128-
String rawLinePrefix = cellSource.substring(0, matchedLine.start());
129-
String linePrefix = rawLinePrefix.substring(rawLinePrefix.lastIndexOf('\n') + 1);
130-
return new ParsedLineMagic(args, raw, cellSource, linePrefix);
131-
}
132132
}

0 commit comments

Comments
 (0)