]> gerrit.simantics Code Review - simantics/python.git/commitdiff
Initial commit of Python Integration feature.
authortuorjr <tuorjr@e36c2e66-7d30-0410-bdb2-d9e1f5a6d952>
Mon, 26 Sep 2016 15:33:15 +0000 (15:33 +0000)
committerReino Ruusu <reino.ruusu@vtt.fi>
Tue, 3 Jan 2017 15:09:29 +0000 (17:09 +0200)
git-svn-id: https://www.simantics.org/svn/simantics-incubator/reino@1689 e36c2e66-7d30-0410-bdb2-d9e1f5a6d952

24 files changed:
org.simantics.pythonlink.feature/.project [new file with mode: 0644]
org.simantics.pythonlink.feature/build.properties [new file with mode: 0644]
org.simantics.pythonlink.feature/feature.xml [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/.classpath [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/.project [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.pythonlink.win32.x86_64/build.properties [new file with mode: 0644]
org.simantics.pythonlink/.classpath [new file with mode: 0644]
org.simantics.pythonlink/.project [new file with mode: 0644]
org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs [new file with mode: 0644]
org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.pythonlink/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.pythonlink/build.properties [new file with mode: 0644]
org.simantics.pythonlink/scl/Simantics/Python.scl [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts [new file with mode: 0644]

diff --git a/org.simantics.pythonlink.feature/.project b/org.simantics.pythonlink.feature/.project
new file mode 100644 (file)
index 0000000..a854e6e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.pythonlink.feature</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.FeatureBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.FeatureNature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.pythonlink.feature/build.properties b/org.simantics.pythonlink.feature/build.properties
new file mode 100644 (file)
index 0000000..82ab19c
--- /dev/null
@@ -0,0 +1 @@
+bin.includes = feature.xml\r
diff --git a/org.simantics.pythonlink.feature/feature.xml b/org.simantics.pythonlink.feature/feature.xml
new file mode 100644 (file)
index 0000000..97bea75
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<feature\r
+      id="org.simantics.pythonlink"\r
+      label="Simantics Python Integration"\r
+      version="1.0.0.qualifier">\r
+\r
+   <description url="http://www.example.com/description">\r
+      [Enter Feature Description here.]\r
+   </description>\r
+\r
+   <copyright url="http://www.example.com/copyright">\r
+      [Enter Copyright Description here.]\r
+   </copyright>\r
+\r
+   <license url="http://www.example.com/license">\r
+      [Enter License Description here.]\r
+   </license>\r
+\r
+   <requires>\r
+      <import plugin="org.junit"/>\r
+      <import plugin="org.eclipse.osgi"/>\r
+      <import plugin="org.simantics.scl.runtime"/>\r
+      <import plugin="gnu.trove3" version="3.0.3" match="greaterOrEqual"/>\r
+      <import plugin="org.simantics.scl.compiler"/>\r
+      <import plugin="org.simantics.scl.osgi"/>\r
+      <import plugin="org.simantics.pythonlink" version="1.0.0" match="greaterOrEqual"/>\r
+   </requires>\r
+\r
+   <plugin\r
+         id="org.simantics.pythonlink"\r
+         download-size="0"\r
+         install-size="0"\r
+         version="0.0.0"\r
+         unpack="false"/>\r
+\r
+   <plugin\r
+         id="org.simantics.pythonlink.win32.x86_64"\r
+         download-size="0"\r
+         install-size="0"\r
+         version="0.0.0"\r
+         fragment="true"\r
+         unpack="false"/>\r
+\r
+</feature>\r
diff --git a/org.simantics.pythonlink.win32.x86_64/.classpath b/org.simantics.pythonlink.win32.x86_64/.classpath
new file mode 100644 (file)
index 0000000..b862a29
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.pythonlink.win32.x86_64/.project b/org.simantics.pythonlink.win32.x86_64/.project
new file mode 100644 (file)
index 0000000..26bdfea
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.pythonlink.win32.x86_64</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..295926d
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\r
+org.eclipse.jdt.core.compiler.compliance=1.8\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.8\r
diff --git a/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs b/org.simantics.pythonlink.win32.x86_64/.settings/org.eclipse.pde.core.prefs
new file mode 100644 (file)
index 0000000..d711c29
--- /dev/null
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1\r
+pluginProject.equinox=false\r
+pluginProject.extensions=false\r
+resolve.requirebundle=false\r
diff --git a/org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF b/org.simantics.pythonlink.win32.x86_64/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..166dc32
--- /dev/null
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.simantics.pythonlink.win32.x86_64
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: VTT Technical Research Centre of Finland
+Fragment-Host: org.simantics.pythonlink;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/org.simantics.pythonlink.win32.x86_64/build.properties b/org.simantics.pythonlink.win32.x86_64/build.properties
new file mode 100644 (file)
index 0000000..2d0d26e
--- /dev/null
@@ -0,0 +1,8 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               jnimatlab.dll,\\r
+               jnipython.dll\r
+src.includes = jnimatlab.dll,\\r
+               jnipython.dll\r
diff --git a/org.simantics.pythonlink/.classpath b/org.simantics.pythonlink/.classpath
new file mode 100644 (file)
index 0000000..069739a
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="test"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.pythonlink/.project b/org.simantics.pythonlink/.project
new file mode 100644 (file)
index 0000000..01b4044
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.pythonlink</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs b/org.simantics.pythonlink/.settings/org.eclipse.core.resources.prefs
new file mode 100644 (file)
index 0000000..375bd7b
--- /dev/null
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1\r
+encoding//test/org/simantics/pythonlink/test/TestPythonlink.java=UTF-8\r
diff --git a/org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs b/org.simantics.pythonlink/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..295926d
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\r
+org.eclipse.jdt.core.compiler.compliance=1.8\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.8\r
diff --git a/org.simantics.pythonlink/META-INF/MANIFEST.MF b/org.simantics.pythonlink/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..14c621b
--- /dev/null
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0\r
+Bundle-ManifestVersion: 2\r
+Bundle-Name: Pythonlink\r
+Bundle-SymbolicName: org.simantics.pythonlink\r
+Bundle-Version: 1.0.0.qualifier\r
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8\r
+Require-Bundle: org.junit,\r
+ org.eclipse.osgi,\r
+ org.simantics.scl.runtime,\r
+ gnu.trove3;bundle-version="3.0.3",\r
+ org.simantics.scl.compiler,\r
+ org.simantics.scl.osgi\r
+Export-Package: org.simantics.pythonlink\r
+Bundle-Activator: org.simantics.pythonlink.Activator\r
+Bundle-ActivationPolicy: lazy\r
diff --git a/org.simantics.pythonlink/build.properties b/org.simantics.pythonlink/build.properties
new file mode 100644 (file)
index 0000000..840ba6a
--- /dev/null
@@ -0,0 +1,6 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               scl/\r
+src.includes = scl/
\ No newline at end of file
diff --git a/org.simantics.pythonlink/scl/Simantics/Python.scl b/org.simantics.pythonlink/scl/Simantics/Python.scl
new file mode 100644 (file)
index 0000000..899f577
--- /dev/null
@@ -0,0 +1,104 @@
+import "Vector"\r
+\r
+effect Python\r
+    "Simantics/Python/Python"\r
+    "org.simantics.pythonlink.PythonContext"\r
+\r
+class PythonCompatible a where\r
+    setPythonVariable :: String -> a -> <Python, Proc> ()\r
+    getPythonVariable :: String -> <Python, Proc> a\r
+\r
+importJava "org.simantics.pythonlink.NDArray" where\r
+    data NDArray\r
+    \r
+    @JavaName "<init>"\r
+    ndarray :: Vector Double -> NDArray\r
+    @JavaName "<init>"\r
+    ndarrayM :: Integer -> Integer -> Vector Double -> NDArray\r
+    @JavaName "<init>"\r
+    ndarrayN :: Vector Integer -> Vector Double -> NDArray\r
+    \r
+    @JavaName size\r
+    ndarraySize :: NDArray -> Integer\r
+    @JavaName dims\r
+    ndarrayDims :: NDArray -> Vector Integer\r
+    @JavaName getValues\r
+    ndarrayValues :: NDArray -> Vector Double\r
+    @JavaName getValue\r
+    ndarrayElement :: NDArray -> Integer -> Double\r
+    @JavaName getValue\r
+    ndarrayElementM :: NDArray -> Integer -> Integer -> Double\r
+    @JavaName getValue\r
+    ndarrayElementN :: NDArray -> Vector Integer -> Double\r
+    \r
+    @JavaName toString\r
+    ndarrayToString :: NDArray -> String\r
+    @JavaName equals\r
+    ndarrayEquals :: NDArray -> NDArray -> Boolean\r
+\r
+instance Show NDArray where\r
+    show = ndarrayToString\r
+\r
+importJava "org.simantics.pythonlink.PythonContext" where\r
+    data PythonContext\r
+    \r
+    @JavaName close\r
+    closePythonContext :: PythonContext -> <Proc> ()\r
+    \r
+    executePythonStatement :: String -> <Python, Proc> Integer\r
+    \r
+    setPythonIntegerVariable :: String -> Integer -> <Python, Proc> ()\r
+    setPythonIntegerArrayVariable :: String -> Vector Integer -> <Python, Proc> ()\r
+    setPythonDoubleVariable :: String -> Double -> <Python, Proc> ()\r
+    setPythonDoubleArrayVariable :: String -> Vector Double -> <Python, Proc> ()\r
+    setPythonStringVariable :: String -> String -> <Python, Proc> ()\r
+    setPythonStringArrayVariable :: String -> Vector String -> <Python, Proc> ()\r
+    setPythonNDArrayVariable :: String -> NDArray -> <Python, Proc> ()\r
+    \r
+    getPythonIntegerVariable :: String -> <Python, Proc> Integer\r
+    getPythonIntegerArrayVariable :: String -> <Python, Proc> Vector Integer\r
+    getPythonDoubleVariable :: String -> <Python, Proc> Double\r
+    getPythonDoubleArrayVariable :: String -> <Python, Proc> Vector Double\r
+    getPythonStringVariable :: String -> <Python, Proc> String\r
+    getPythonStringArrayVariable  :: String -> <Python, Proc> Vector String\r
+    getPythonNDArrayVariable :: String -> <Python, Proc> NDArray\r
+    \r
+    runPythonF :: (() -> <Python, Proc> a) -> <Proc> a\r
+    runWithPythonContextF :: PythonContext -> (() -> <Python, Proc> a) -> <Proc> a\r
+\r
+importJava "org.simantics.pythonlink.Python" where\r
+    openPythonContext :: () -> <Proc> PythonContext\r
+    \r
+runPython :: (<Python, Proc> a) -> <Proc> a\r
+runPython v = runPythonF (\_ -> v)\r
+\r
+runWithPythonContext :: PythonContext -> (<Python, Proc> a) -> <Proc> a\r
+runWithPythonContext python v = runWithPythonContextF python (\_ -> v) \r
+\r
+instance PythonCompatible Double where\r
+    setPythonVariable = setPythonDoubleVariable\r
+    getPythonVariable = getPythonDoubleVariable\r
+    \r
+instance PythonCompatible (Vector Double) where\r
+    setPythonVariable = setPythonDoubleArrayVariable\r
+    getPythonVariable = getPythonDoubleArrayVariable\r
+    \r
+instance PythonCompatible Integer where\r
+    setPythonVariable = setPythonIntegerVariable\r
+    getPythonVariable = getPythonIntegerVariable\r
+    \r
+instance PythonCompatible (Vector Integer) where\r
+    setPythonVariable = setPythonIntegerArrayVariable\r
+    getPythonVariable = getPythonIntegerArrayVariable\r
+    \r
+instance PythonCompatible String where\r
+    setPythonVariable = setPythonStringVariable\r
+    getPythonVariable = getPythonStringVariable\r
+    \r
+instance PythonCompatible (Vector String) where\r
+    setPythonVariable = setPythonStringArrayVariable\r
+    getPythonVariable = getPythonStringArrayVariable\r
+    \r
+instance PythonCompatible NDArray where\r
+    setPythonVariable = setPythonNDArrayVariable\r
+    getPythonVariable = getPythonNDArrayVariable\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/Activator.java
new file mode 100644 (file)
index 0000000..83633a4
--- /dev/null
@@ -0,0 +1,31 @@
+package org.simantics.pythonlink;\r
+\r
+import org.osgi.framework.BundleActivator;\r
+import org.osgi.framework.BundleContext;\r
+\r
+public class Activator implements BundleActivator {\r
+\r
+       private static BundleContext context;\r
+\r
+       static BundleContext getContext() {\r
+               return context;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext bundleContext) throws Exception {\r
+               Activator.context = bundleContext;\r
+        System.loadLibrary("jnipython");\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext bundleContext) throws Exception {\r
+               Activator.context = null;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/NDArray.java
new file mode 100644 (file)
index 0000000..69506e9
--- /dev/null
@@ -0,0 +1,93 @@
+package org.simantics.pythonlink;\r
+\r
+import java.util.Arrays;\r
+\r
+public class NDArray {\r
+    int[] dims;\r
+    double[] value;\r
+    \r
+    public NDArray(double[] value) {\r
+        this.value = value;\r
+        dims = new int[] { value.length };\r
+    }\r
+    \r
+    public NDArray(int m, int n, double[] value) {\r
+        if (n*m != value.length) throw new IllegalArgumentException("Invalid dimensions for data vector");\r
+        \r
+        this.value = value;\r
+        dims = new int[] { m, n };\r
+    }\r
+    \r
+    public NDArray(int[] dims, double[] value) {\r
+        int l = dims.length > 0 ? 1 : 0;\r
+        for (int d : dims) l *= d;\r
+        if (l != value.length) throw new IllegalArgumentException("Invalid dimensions for data vector");\r
+\r
+        this.dims = dims;\r
+        this.value = value;\r
+    }\r
+    \r
+    public int size() { return value.length; }\r
+    public int[] dims() { return dims; }\r
+    public double[] getValues() { return value; }\r
+    \r
+    public double getValue(int index) { return value[index]; }\r
+    public double getValue(int i, int j) {\r
+        if (dims.length != 2) throw new IllegalArgumentException("Invalid indices for array of dimension " + dims.length);\r
+        \r
+        return value[dims[1] * i + j];\r
+    }\r
+    public double getValue(int... is) {\r
+        if (dims.length != is.length) throw new IllegalArgumentException("Invalid indices for array of dimension " + dims.length);\r
+        \r
+        int index = 0;\r
+        for (int k = 0; k < dims.length; k++) {\r
+            index = dims[k] * index + is[k];\r
+        }\r
+        return value[index];\r
+    }\r
+    \r
+    @Override\r
+    public boolean equals( Object o ) {\r
+        return o instanceof NDArray &&\r
+               Arrays.equals(dims, ((NDArray)o).dims) &&\r
+               Arrays.equals(value, ((NDArray)o).value);\r
+    }\r
+    \r
+    @Override\r
+    public int hashCode() {\r
+        return Arrays.hashCode(dims) + 11 * Arrays.hashCode(value); \r
+    }\r
+    \r
+    @Override\r
+    public String toString() {\r
+        StringBuilder sb = new StringBuilder();\r
+        sb.append("ndarray(");\r
+        for (int i = 0; i < dims.length; i++) {\r
+            if (i > 0) sb.append('x');\r
+            sb.append(dims[i]);\r
+        }\r
+        sb.append(") ");\r
+        \r
+        if (dims.length > 0)\r
+            buildString(sb, 0, 0);\r
+        else\r
+            sb.append("[]");\r
+        return sb.toString();\r
+    }\r
+\r
+    private void buildString( StringBuilder sb, int d, int i ) {\r
+        if (d == dims.length) {\r
+            sb.append(value[i]);\r
+        }\r
+        else {\r
+            i *= dims[d];\r
+            sb.append('[');\r
+            for (int j = 0; j < dims[d]; j++) {\r
+                if (j > 0) sb.append(", ");\r
+                buildString(sb, d+1, i + j);\r
+            }\r
+            sb.append(']');\r
+        }\r
+    }\r
+}\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java
new file mode 100644 (file)
index 0000000..af5c9e2
--- /dev/null
@@ -0,0 +1,39 @@
+package org.simantics.pythonlink;\r
+\r
+import org.simantics.scl.runtime.SCLContext;\r
+import org.simantics.scl.runtime.function.Function;\r
+import org.simantics.scl.runtime.tuple.Tuple0;\r
+\r
+public class Python {\r
+    private static final String PYTHON_CONTEXT = "Simantics/Python/Python";\r
+\r
+    public static PythonContext openPythonContext() {\r
+        return new PythonContext();\r
+    }\r
+    \r
+    @SuppressWarnings( { "unchecked", "rawtypes" } )\r
+    public static Object runPython(Function f) {\r
+        SCLContext sclContext = SCLContext.getCurrent();\r
+        Object oldContext = sclContext.get(PYTHON_CONTEXT);\r
+        try (PythonContext newContext = openPythonContext()) {\r
+            sclContext.put(PYTHON_CONTEXT, newContext);\r
+            return f.apply(Tuple0.INSTANCE);\r
+        }\r
+        finally {\r
+            sclContext.put(PYTHON_CONTEXT, oldContext);\r
+        }\r
+    }\r
+    \r
+    @SuppressWarnings( { "unchecked", "rawtypes" } )\r
+    public static Object runWithPythonContext(PythonContext context, Function f) {\r
+        SCLContext sclContext = SCLContext.getCurrent();\r
+        Object oldContext = sclContext.get(PYTHON_CONTEXT);\r
+        try {\r
+            sclContext.put(PYTHON_CONTEXT, context);\r
+            return f.apply(Tuple0.INSTANCE);\r
+        }\r
+        finally {\r
+            sclContext.put(PYTHON_CONTEXT, oldContext);\r
+        }\r
+    }    \r
+}\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java
new file mode 100644 (file)
index 0000000..d237c83
--- /dev/null
@@ -0,0 +1,94 @@
+package org.simantics.pythonlink;\r
+\r
+import java.io.Closeable;\r
+\r
+public class PythonContext implements Closeable {\r
+    private long contextID;\r
+    \r
+    PythonContext() {\r
+        contextID = openPythonContextImpl();\r
+    }\r
+    \r
+    @Override\r
+    public void close() {\r
+        long id = contextID;\r
+        contextID = 0;\r
+        closePythonContextImpl(id);\r
+    }\r
+    \r
+    public void executePythonStatement(String statement) {\r
+        executePythonStatementImpl( contextID, statement );\r
+    }\r
+    \r
+    public void setPythonIntegerVariable(String variableName, int value) {\r
+        setPythonIntegerVariableImpl(contextID, variableName, value);\r
+    }\r
+    public void setPythonDoubleVariable(String variableName, double value) {\r
+        setPythonDoubleVariableImpl(contextID, variableName, value);\r
+    }\r
+    public void setPythonStringVariable(String variableName, String value) {\r
+        setPythonStringVariableImpl(contextID, variableName, value);\r
+    }\r
+    \r
+    public void setPythonIntegerArrayVariable(String variableName, int[] value) {\r
+        setPythonIntegerArrayVariableImpl(contextID, variableName, value);\r
+    }\r
+    public void setPythonDoubleArrayVariable(String variableName, double[] value) {\r
+        setPythonDoubleArrayVariableImpl(contextID, variableName, value);\r
+    }\r
+    public void setPythonStringArrayVariable(String variableName, String[] value) {\r
+        setPythonStringArrayVariableImpl(contextID, variableName, value);\r
+    }\r
+    \r
+    public int getPythonIntegerVariable(String variableName) {\r
+        return getPythonIntegerVariableImpl(contextID, variableName);\r
+    }\r
+    public double getPythonDoubleVariable(String variableName) {\r
+        return getPythonDoubleVariableImpl(contextID, variableName);\r
+    }\r
+    public String getPythonStringVariable(String variableName) {\r
+        return getPythonStringVariableImpl(contextID, variableName);\r
+    }\r
+    \r
+    public int[] getPythonIntegerArrayVariable(String variableName) {\r
+        return getPythonIntegerArrayVariableImpl(contextID, variableName);\r
+    }\r
+    public double[] getPythonDoubleArrayVariable(String variableName) {\r
+        return getPythonDoubleArrayVariableImpl(contextID, variableName);\r
+    }\r
+    public String[] getPythonStringArrayVariable(String variableName) {\r
+        return getPythonStringArrayVariableImpl(contextID, variableName);\r
+    }\r
+    \r
+    public void setPythonNDArrayVariable(String variableName, NDArray value) {\r
+        setPythonNDArrayVariableImpl(contextID, variableName, value);\r
+    }\r
+    public NDArray getPythonNDArrayVariable(String variableName) {\r
+        return getPythonNDArrayVariableImpl(contextID, variableName);\r
+    }\r
+\r
+    // Native function declarations\r
+    private static native long openPythonContextImpl();\r
+    private static native void closePythonContextImpl(long contextID);\r
+    \r
+    private static native void executePythonStatementImpl(long contextID, String statement);\r
+    \r
+    private static native void setPythonIntegerVariableImpl(long contextID, String variableName, int value);\r
+    private static native void setPythonDoubleVariableImpl(long contextID, String variableName, double value);\r
+    private static native void setPythonStringVariableImpl(long contextID, String variableName, String value);\r
+    \r
+    private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value);\r
+    private static native void setPythonDoubleArrayVariableImpl(long contextID, String variableName, double[] value);\r
+    private static native void setPythonStringArrayVariableImpl(long contextID, String variableName, String[] value);\r
+    \r
+    private static native int getPythonIntegerVariableImpl(long contextID, String variableName);\r
+    private static native double getPythonDoubleVariableImpl(long contextID, String variableName);\r
+    private static native String getPythonStringVariableImpl(long contextID, String variableName);\r
+    \r
+    private static native int[] getPythonIntegerArrayVariableImpl(long contextID, String variableName);\r
+    private static native double[] getPythonDoubleArrayVariableImpl(long contextID, String variableName);\r
+    private static native String[] getPythonStringArrayVariableImpl(long contextID, String variableName);\r
+    \r
+    private static native void setPythonNDArrayVariableImpl(long contextID, String variableName, NDArray value);\r
+    private static native NDArray getPythonNDArrayVariableImpl(long contextID, String variableName);\r
+}\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTestBase.java
new file mode 100644 (file)
index 0000000..6328fec
--- /dev/null
@@ -0,0 +1,36 @@
+package org.simantics.pythonlink.test;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+import org.junit.Before;
+import org.simantics.scl.compiler.commands.CommandSession;
+import org.simantics.scl.compiler.commands.TestScriptExecutor;
+import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.source.repository.CompositeModuleSourceRepository;
+import org.simantics.scl.compiler.source.repository.SourceRepositories;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.osgi.internal.ServiceBasedModuleSourceRepository;
+
+public class ScriptTestBase {
+    
+    private final String path;
+    
+    public ScriptTestBase(String path) {
+        this.path = path;
+    }
+    
+    protected void test() throws Exception {
+        String testScriptName = Thread.currentThread().getStackTrace()[2].getMethodName();
+        String testPath = path + "/" + testScriptName + ".sts";
+
+        CommandSession session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, null);
+        new TestScriptExecutor(session, 
+                new BufferedReader(
+                        new InputStreamReader(getClass().getResourceAsStream(testPath), Charset.forName("UTF-8"))),
+                        null)
+        .execute();
+    }
+    
+}
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java
new file mode 100644 (file)
index 0000000..4c5318a
--- /dev/null
@@ -0,0 +1,16 @@
+package org.simantics.pythonlink.test;
+
+import org.junit.Test;
+
+public class ScriptTests extends ScriptTestBase {
+    
+    public ScriptTests() {
+        super("scripts");
+    }
+
+    @Test public void Arithmetic() throws Exception { test(); }
+    @Test public void Functions() throws Exception { test(); }
+    @Test public void Functions2() throws Exception { test(); }
+    @Test public void Lists() throws Exception { test(); }
+    
+}
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonlink.java
new file mode 100644 (file)
index 0000000..bc6379d
--- /dev/null
@@ -0,0 +1,104 @@
+package org.simantics.pythonlink.test;\r
+\r
+import static org.junit.Assert.*;\r
+\r
+import org.junit.After;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.simantics.pythonlink.NDArray;\r
+import org.simantics.pythonlink.Python;\r
+import org.simantics.pythonlink.PythonContext;\r
+\r
+public class TestPythonlink {\r
+    PythonContext python;\r
+\r
+    @Before\r
+    public void setUp() throws Exception {\r
+        python = Python.openPythonContext();\r
+    }\r
+\r
+    @After\r
+    public void tearDown() throws Exception {\r
+        python.close();\r
+    }\r
+\r
+    @Test\r
+    public void testInteger() {\r
+        int input = 4;\r
+        python.setPythonIntegerVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo // 2" );\r
+        int output = python.getPythonIntegerVariable( "bar" );\r
+        assertEquals( input / 2, output, 0.0 );\r
+    }\r
+\r
+    @Test\r
+    public void testIntegerArray() {\r
+        int[] input = new int[] { 1, 2 };\r
+        python.setPythonIntegerArrayVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo\nbar.append(3)" );\r
+        int[] output = python.getPythonIntegerArrayVariable( "bar" );\r
+        assertArrayEquals( new int[] { 1, 2, 3 }, output );\r
+    }\r
+\r
+    @Test\r
+    public void testDouble() {\r
+        double input = 2.5;\r
+        python.setPythonDoubleVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo / 2" );\r
+        double output = python.getPythonDoubleVariable( "bar" );\r
+        assertEquals( input / 2, output, 0.0 );\r
+    }\r
+\r
+    @Test\r
+    public void testDoubleArray() {\r
+        double[] input = new double[] { 1.0, 2.0 };\r
+        python.setPythonDoubleArrayVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo\nbar.append(3.0)" );\r
+        double[] output = python.getPythonDoubleArrayVariable( "bar" );\r
+        assertArrayEquals( new double[] { 1.0, 2.0, 3.0 }, output, 0.0 );\r
+    }\r
+    \r
+    @Test\r
+    public void testString() {\r
+        String input = "Foo";\r
+        python.setPythonStringVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo + 'bar!'" );\r
+        String output = python.getPythonStringVariable( "bar" );\r
+        assertEquals( "Foobar!", output );\r
+    }    \r
+    \r
+    @Test\r
+    public void testStringArray() {\r
+        String[] input = new String[] { "Foo" };\r
+        python.setPythonStringArrayVariable( "foo", input );\r
+        python.executePythonStatement( "bar = foo + ['bar!']" );\r
+        String[] output = python.getPythonStringArrayVariable( "bar" );\r
+        assertArrayEquals( new String[] { "Foo", "bar!" }, output );\r
+    }\r
+    \r
+    @Test\r
+    public void testNumpyArrays() {\r
+        NDArray data = new NDArray(new int[] { 2, 3 }, new double[] { 1, 2, 3,  4, 5, 6 });\r
+        python.executePythonStatement( "import numpy" );\r
+        python.setPythonNDArrayVariable( "foo", data );\r
+        python.executePythonStatement( "bar = foo.cumsum(axis = 0)" );\r
+        NDArray result = python.getPythonNDArrayVariable( "bar" );\r
+        assertEquals(new NDArray(new int[] { 2, 3 }, new double[] { 1, 2, 3,  5, 7, 9 }), result);\r
+        assertEquals(5, result.getValue( 1, 0 ), 0.0);\r
+        assertEquals(3, result.getValue( 0, 2 ), 0.0);\r
+        assertEquals(9, result.getValue( 1, 2 ), 0.0);\r
+    }\r
+    \r
+    @Test\r
+    public void testNumpyArrays3() {\r
+        NDArray data = new NDArray(new int[] { 3, 2, 2 }, new double[] { 1, 2,  3, 4,   5, 6,  7, 8,   9, 10,  11, 12 });\r
+        python.executePythonStatement( "import numpy" );\r
+        python.setPythonNDArrayVariable( "foo", data );\r
+        python.executePythonStatement( "bar = numpy.ndarray(shape = (3,2,2), order='f')" );\r
+        python.executePythonStatement( "bar.flat = foo.cumsum(axis = 1).flat" );\r
+        NDArray result = python.getPythonNDArrayVariable( "bar" );\r
+        assertEquals(new NDArray(new int[] { 3, 2, 2 }, new double[] { 1, 2,  4, 6,   5, 6,  12, 14,   9, 10,  20, 22 }), result);\r
+        assertEquals(10, result.getValue( 2, 0, 1 ), 0.0);\r
+        assertEquals(12, result.getValue( 1, 1, 0 ), 0.0);\r
+    }\r
+}\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts
new file mode 100644 (file)
index 0000000..409d9b2
--- /dev/null
@@ -0,0 +1,48 @@
+> import "Simantics/Python"\r
+> import "Vector"\r
+> \r
+> runPython do\r
+>     executePythonStatement "foo = 'bar'\nd = dir()"\r
+>     getPythonStringArrayVariable "d"\r
+vector ["__builtins__", "__doc__", "__loader__", "__name__", "__package__", "__spec__", "foo"]\r
+> runPython do\r
+>     setPythonDoubleVariable "foo" 1\r
+>     executePythonStatement "foo = foo + 1"\r
+>     getPythonDoubleVariable "foo"\r
+2.0\r
+> runPython do\r
+>     setPythonDoubleArrayVariable "foo" (vector [1.0, 2.0, 3.0])\r
+>     executePythonStatement "foo = foo + [4.0]"\r
+>     getPythonDoubleArrayVariable "foo"\r
+vector [1.0, 2.0, 3.0, 4.0]\r
+> runPython do\r
+>     setPythonIntegerVariable "foo" 5\r
+>     executePythonStatement "import math"\r
+>     executePythonStatement "bar = math.factorial(foo)"\r
+>     getPythonIntegerVariable "bar"\r
+120\r
+> runPython do\r
+>     setPythonIntegerArrayVariable "foo" (vector [1, 2, 3, 4])\r
+>     executePythonStatement "foo.append(sum(foo))"\r
+>     getPythonIntegerArrayVariable "foo"\r
+vector [1, 2, 3, 4, 10]\r
+> ndarray (vector [1, 2, 3])\r
+ndarray(3) [1.0, 2.0, 3.0]\r
+> ndarrayM 2 2 (vector [1, 2, 3, 4])\r
+ndarray(2x2) [1.0, 2.0, 3.0, 4.0]\r
+> a = ndarrayN (vector [2, 2, 3]) (vector [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])\r
+> a\r
+ndarray(2x2x3) [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, ...]\r
+> ndarrayDims a\r
+vector [2, 2, 3]\r
+> ndarrayValues a\r
+vector [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0]\r
+> ndarrayElement a 5\r
+6.0\r
+> ndarrayElementN a (vector [0, 1, 2])\r
+6.0\r
+> runPython do\r
+>     setPythonNDArrayVariable "foo" (ndarrayM 2 3 (vector [1, 2, 3,  4, 5, 6]))\r
+>     executePythonStatement "bar = foo.cumsum(1)"\r
+>     getPythonNDArrayVariable "bar"\r
+ndarray(2x3) [1.0, 3.0, 6.0, 4.0, 9.0, 15.0]\r