Skip to content

Commit c2ffa6a

Browse files
committed
Merge branch 'python-script-runner'
2 parents 490bb21 + d1721f8 commit c2ffa6a

File tree

5 files changed

+100
-68
lines changed

5 files changed

+100
-68
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/.classpath
2+
/.idea/
23
/.project
34
/.settings/
45
/target

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,21 @@
22

33
# Python Scripting
44

5-
Test repository for a [PyImageJ](https://github.com/imagej/pyimagej) based SciJava scripting language engine.
5+
This library provides a
6+
[JSR-223-compliant](https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform)
7+
scripting plugin for the [Python](https://python.org/) language, built on
8+
the [scyjava](https://github.com/scijava/scyjava) Python package.
9+
10+
It is implemented as a `ScriptLanguage` plugin for the [SciJava
11+
Common](https://github.com/scijava/scijava-common) platform, which means that
12+
in addition to being usable directly as a `javax.script.ScriptEngineFactory`,
13+
it also provides some functionality on top, such as the ability to generate
14+
lines of script code based on SciJava events.
15+
16+
For a complete list of scripting languages available as part of the SciJava
17+
platform, see the
18+
[Scripting](https://github.com/scijava/scijava-common/wiki/Scripting) page on
19+
the SciJava Common wiki.
20+
21+
See also:
22+
* [Python Scripting](https://imagej.net/scripting/python) on the ImageJ wiki.

repl.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/sh
2+
set -e
3+
cd "$(dirname "$0")"
4+
python -c '
5+
import os.path
6+
import xml.etree.ElementTree as ET
7+
import scyjava
8+
import subprocess
9+
from pathlib import Path
10+
11+
def exec(cmd):
12+
try:
13+
args = cmd.split(" ")
14+
subprocess.check_output(cmd.split(" "))
15+
except subprocess.CalledProcessError as e:
16+
print("== OPERATION FAILED ==")
17+
print(e.stdout.decode())
18+
print(e.stderr.decode())
19+
raise e
20+
21+
pom = ET.parse("pom.xml")
22+
artifactId = pom.find("{http://maven.apache.org/POM/4.0.0}artifactId").text
23+
version = pom.find("{http://maven.apache.org/POM/4.0.0}version").text
24+
jar = Path(f"target/{artifactId}-{version}.jar")
25+
if not jar.exists():
26+
print("Building JAR file...")
27+
exec("mvn -Denforcer.skip -Dmaven.test.skip clean package")
28+
deps_dir = Path("target/dependency")
29+
if not deps_dir.exists():
30+
print("Copying dependencies...")
31+
exec("mvn -DincludeScope=runtime dependency:copy-dependencies")
32+
33+
scyjava.config.add_option("-Djava.awt.headless=true")
34+
scyjava.config.add_classpath(jar.absolute())
35+
deps = scyjava.config.find_jars(deps_dir.absolute())
36+
scyjava.config.add_classpath(*deps)
37+
Context = scyjava.jimport("org.scijava.Context")
38+
context = Context(False)
39+
print(f"Context created with {context.getServiceIndex().size()} services.")
40+
scyjava.enable_python_scripting(context)
41+
ScriptREPL = scyjava.jimport("org.scijava.script.ScriptREPL")
42+
repl = ScriptREPL(context, "Python")
43+
repl.loop()
44+
context.dispose()
45+
'

src/main/java/org/scijava/plugins/scripting/python/PythonScriptEngine.java

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@
3434
import java.util.Collection;
3535
import java.util.HashMap;
3636
import java.util.Map;
37+
import java.util.Optional;
3738
import java.util.Set;
39+
import java.util.function.Function;
3840

3941
import javax.script.Bindings;
42+
import javax.script.ScriptContext;
4043
import javax.script.ScriptEngine;
4144
import javax.script.ScriptException;
4245

@@ -45,11 +48,10 @@
4548
import org.scijava.object.ObjectService;
4649
import org.scijava.plugin.Parameter;
4750
import org.scijava.script.AbstractScriptEngine;
48-
import org.scijava.ui.DialogPrompt;
49-
import org.scijava.ui.UIService;
5051

5152
/**
52-
* A script engine for Python (PyImageJ).
53+
* A script engine for Python (CPython, not Jython!), backed by the
54+
* <a href="https://github.com/scijava/scyjava">scyjava</a> library.
5355
*
5456
* @author Curtis Rueden
5557
* @author Karl Duderstadt
@@ -58,29 +60,30 @@
5860
public class PythonScriptEngine extends AbstractScriptEngine {
5961

6062
@Parameter
61-
ObjectService objectService;
63+
private ObjectService objectService;
6264

6365
@Parameter
64-
LogService logService;
66+
private LogService logService;
6567

66-
@Parameter
67-
UIService uiService;
68-
69-
public PythonScriptEngine(Context context) {
68+
public PythonScriptEngine(final Context context) {
7069
context.inject(this);
7170
setLogService(logService);
7271
engineScopeBindings = new ScriptBindings();
7372
}
7473

7574
@Override
76-
public Object eval(String script) throws ScriptException {
77-
if (objectService.getObjects(PythonScriptRunner.class).stream().count() > 0)
78-
return objectService.getObjects(PythonScriptRunner.class).get(0).run(script, engineScopeBindings, scriptContext);
79-
80-
uiService.showDialog("The PythonScriptRunner could not be found in the ObjectService. To use the\n" +
81-
"Conda Python 3 script engine Fiji must be launched from python inside a conda\n " +
82-
"environment and a PythonScriptRunner must be added to the ObjectService.\n", DialogPrompt.MessageType.ERROR_MESSAGE);
83-
return null;
75+
public Object eval(final String script) throws ScriptException {
76+
final Optional<Function> pythonScriptRunner = //
77+
objectService.getObjects(Function.class).stream()//
78+
.filter(obj -> "PythonScriptRunner".equals(objectService.getName(obj)))//
79+
.findFirst();
80+
if (!pythonScriptRunner.isPresent()) {
81+
throw new IllegalStateException(//
82+
"The PythonScriptRunner could not be found in the ObjectService. To use the\n" +
83+
"Python script engine, you must call scyjava.enable_scijava_scripting(context)\n" +
84+
"with this script engine's associated SciJava context before using it.");
85+
}
86+
return pythonScriptRunner.get().apply(new Args(script, engineScopeBindings, scriptContext));
8487
}
8588

8689
@Override
@@ -105,10 +108,10 @@ public Bindings createBindings() {
105108
}
106109

107110
//Somehow just type casting did not work...
108-
class ScriptBindings implements Bindings {
109-
110-
private Map<String, Object> bindingsMap;
111-
111+
private static class ScriptBindings implements Bindings {
112+
113+
private Map<String, Object> bindingsMap;
114+
112115
ScriptBindings() {
113116
bindingsMap = new HashMap<String, Object>();
114117
}
@@ -173,4 +176,16 @@ public Object remove(Object key) {
173176
return bindingsMap.remove(key);
174177
}
175178
}
179+
180+
private static class Args {
181+
public final String script;
182+
public final Map<String, Object> vars;
183+
public final ScriptContext scriptContext;
184+
185+
public Args(final String script, final Map<String, Object> vars, final ScriptContext scriptContext) {
186+
this.script = script;
187+
this.vars = vars;
188+
this.scriptContext = scriptContext;
189+
}
190+
}
176191
}

src/main/java/org/scijava/plugins/scripting/python/PythonScriptRunner.java

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

0 commit comments

Comments
 (0)