]> gerrit.simantics Code Review - simantics/python.git/commitdiff
Added support for dynamically typed data access and a Variable interface.
authortuorjr <tuorjr@e36c2e66-7d30-0410-bdb2-d9e1f5a6d952>
Tue, 4 Oct 2016 16:22:17 +0000 (16:22 +0000)
committerReino Ruusu <reino.ruusu@vtt.fi>
Tue, 3 Jan 2017 15:09:31 +0000 (17:09 +0200)
Note: Proper function of the Variable interface depends on enhancement #6738.

git-svn-id: https://www.simantics.org/svn/simantics-incubator/reino@1694 e36c2e66-7d30-0410-bdb2-d9e1f5a6d952

20 files changed:
org.simantics.pythonlink.win32.x86_64/jnipython.dll
org.simantics.pythonlink.win32.x86_64/src/sclpy.c
org.simantics.pythonlink.win32.x86_64/src/sclpy.h
org.simantics.pythonlink/META-INF/MANIFEST.MF
org.simantics.pythonlink/runAllTests.launch
org.simantics.pythonlink/runScriptTests.launch
org.simantics.pythonlink/scl/Python.scl
org.simantics.pythonlink/scl/PythonVariable.scl [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/Python.java
org.simantics.pythonlink/src/org/simantics/pythonlink/PythonContext.java
org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNode.java [new file with mode: 0644]
org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNodeManager.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/AllTests.java
org.simantics.pythonlink/test/org/simantics/pythonlink/test/ScriptTests.java
org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonVariable.java [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Matplotlib.sts [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/NDArray.sts [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Python.sts
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variable.sts [new file with mode: 0644]
org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variant.sts [new file with mode: 0644]

index 1960f88295359bb58dfe1cdf4aec385d0841001f..fb4cf4aa31ebd203dcabbfd07966e204eeebf160 100644 (file)
Binary files a/org.simantics.pythonlink.win32.x86_64/jnipython.dll and b/org.simantics.pythonlink.win32.x86_64/jnipython.dll differ
index 4f5da9b5d5fb2daf5a53c9cc7cb884295ae0e273..0db1e388c792b1909059d03895f1f77a8bea8e66 100644 (file)
 //                                                   //\r
 ///////////////////////////////////////////////////////\r
 \r
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\r
-#ifdef _DEBUG\r
-       #undef _DEBUG\r
-       #include <Python.h>  //header for system python import; add include paths\r
-       #include <numpy/arrayobject.h>\r
-       #define _DEBUG 1\r
-#else\r
-       #include <Python.h>  //header for system python import; add include paths\r
-       #include <numpy/arrayobject.h>\r
-#endif\r
-\r
 #include "sclpy.h"\r
 \r
-#include <jni.h> //java connection header\r
-\r
 #include <windows.h>\r
 \r
-#define JAVA_MAXINT (0x7fffffff)\r
-\r
-#define RUNTIME_EXCEPTION "java/lang/RuntimeException"\r
-#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException"\r
-#define STRING_CLASS "java/lang/String"\r
-\r
-#define PACKAGE_PREFIX "org/simantics/pythonlink/"\r
-\r
-#define NDARRAY_CLASS (PACKAGE_PREFIX "NDArray")\r
-\r
 jint throwException( JNIEnv *env, char *className, char *message )\r
 {\r
     jclass exClass = (*env)->FindClass( env, className);\r
@@ -52,9 +29,20 @@ jint throwIllegalArgumentException( JNIEnv *env, char *message ) {
 }\r
 \r
 int moduleCount = 0;\r
+int initCalled = 0;\r
+int hasNumpy = 0;\r
 \r
 JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) {\r
        char name[16];\r
+\r
+       if (!initCalled) {\r
+        Py_Initialize();\r
+        initCalled = 1;\r
+\r
+       hasNumpy = _import_array();\r
+       hasNumpy = hasNumpy != -1;\r
+       }\r
+\r
        sprintf(name, "SCL_%d", ++moduleCount);\r
 \r
        {\r
@@ -62,6 +50,7 @@ JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContex
                PyObject *main = PyImport_AddModule("__main__");\r
 \r
                PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0);\r
+\r
                return (jlong)module;\r
        }\r
 }\r
@@ -71,6 +60,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContext
        Py_XDECREF(module);\r
 }\r
 \r
+PyObject *getPythonBool(jboolean value) {\r
+       if (value) {\r
+               Py_RETURN_TRUE;\r
+       }\r
+       else {\r
+               Py_RETURN_FALSE;\r
+       }\r
+}\r
+\r
 PyObject *getPythonString(JNIEnv *env, jstring string) {\r
        jsize len = (*env)->GetStringLength(env, string);\r
        const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
@@ -102,6 +100,30 @@ PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) {
        return result;\r
 }\r
 \r
+PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) {\r
+       jsize nitems = (*env)->GetArrayLength(env, value);\r
+       jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL);\r
+       jint i;\r
+\r
+       PyObject *result = PyList_New(nitems);\r
+       for (i = 0; i < nitems; i++) {\r
+               PyList_SetItem(result, i, getPythonBool(values[i]));\r
+       }\r
+\r
+       (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT);\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) {\r
+       jint len = (*env)->GetArrayLength(env, value);\r
+       jbyte *values = (*env)->GetByteArrayElements(env, value, NULL);\r
+\r
+       PyObject *result = PyByteArray_FromStringAndSize(values, len);\r
+\r
+       (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT);\r
+       return result;\r
+}\r
+\r
 PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {\r
        jsize nitems = (*env)->GetArrayLength(env, value);\r
        jint *values = (*env)->GetIntArrayElements(env, value, NULL);\r
@@ -116,6 +138,34 @@ PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) {
        return result;\r
 }\r
 \r
+PyObject *getPythonLongList(JNIEnv *env, jlongArray value) {\r
+       jsize nitems = (*env)->GetArrayLength(env, value);\r
+       jlong *values = (*env)->GetLongArrayElements(env, value, NULL);\r
+       jint i;\r
+\r
+       PyObject *result = PyList_New(nitems);\r
+       for (i = 0; i < nitems; i++) {\r
+               PyList_SetItem(result, i, PyLong_FromLongLong(values[i]));\r
+       }\r
+\r
+       (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT);\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) {\r
+       jsize nitems = (*env)->GetArrayLength(env, value);\r
+       float *values = (*env)->GetFloatArrayElements(env, value, NULL);\r
+       jint i;\r
+\r
+       PyObject *result = PyList_New(nitems);\r
+       for (i = 0; i < nitems; i++) {\r
+               PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i]));\r
+       }\r
+\r
+       (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT);\r
+       return result;\r
+}\r
+\r
 PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) {\r
        jsize nitems = (*env)->GetArrayLength(env, value);\r
        double *values = (*env)->GetDoubleArrayElements(env, value, NULL);\r
@@ -168,6 +218,274 @@ PyObject *getPythonNDArray(JNIEnv *env, jobject value) {
        }\r
 }\r
 \r
+PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z");\r
+\r
+       jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object);\r
+       return getPythonBool(bvalue);\r
+}\r
+\r
+PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B");\r
+\r
+       jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object);\r
+       return PyLong_FromLong(v);\r
+}\r
+\r
+PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I");\r
+\r
+       jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object);\r
+       return PyLong_FromLong(v);\r
+}\r
+\r
+PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J");\r
+\r
+       jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object);\r
+       return PyLong_FromLongLong(v);\r
+}\r
+\r
+PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F");\r
+\r
+       jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object);\r
+       return PyFloat_FromDouble(v);\r
+}\r
+\r
+PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D");\r
+\r
+       jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object);\r
+       return PyFloat_FromDouble(v);\r
+}\r
+\r
+PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";");\r
+\r
+       jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
+       jsize len = (*env)->GetStringLength(env, string);\r
+       const jchar *chars = (*env)->GetStringChars(env, string, NULL);\r
+\r
+       PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL);\r
+\r
+       (*env)->ReleaseStringChars(env, string, chars);\r
+       return value;\r
+}\r
+\r
+PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
+       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
+       jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
+       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
+\r
+       jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS);\r
+       jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
+       jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I");\r
+\r
+       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
+       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
+\r
+       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
+       jint n = (*env)->CallIntMethod(env, type, getComponentCount);\r
+       jint i;\r
+\r
+       PyObject *result = PyDict_New();\r
+       for (i = 0; i < n; i++) {\r
+               jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i);\r
+               jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField);\r
+               jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);\r
+               jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);\r
+\r
+               PyObject *item = getPythonObject(env, componentObject, componentBinding);\r
+               PyDict_SetItem(result, getPythonString(env, fieldName), item);\r
+       }\r
+\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
+       jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
+       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
+       jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";");\r
+\r
+       jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
+\r
+       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
+\r
+       PyObject *result = PyList_New(size);\r
+\r
+       jint i;\r
+       for (i = 0; i < size; i++) {\r
+               jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);\r
+               if (item != NULL)\r
+                       PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));\r
+               else\r
+                       PyList_SetItem(result, i, Py_None);\r
+       }\r
+\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS);\r
+       jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS);\r
+       jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";");\r
+       jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";");\r
+       jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I");\r
+       jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V");\r
+\r
+       jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod);\r
+       jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod);\r
+\r
+       jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object);\r
+       jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
+       jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL);\r
+\r
+       PyObject *result = PyDict_New();\r
+       jint i;\r
+\r
+       (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values);\r
+\r
+       for (i = 0; i < size; i++) {\r
+               jobject key = (*env)->GetObjectArrayElement(env, keys, i);\r
+               jobject item = (*env)->GetObjectArrayElement(env, values, i);\r
+               PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));\r
+       }\r
+\r
+       (*env)->DeleteLocalRef(env, keys);\r
+       (*env)->DeleteLocalRef(env, values);\r
+\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
+       jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z");\r
+\r
+       jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object);\r
+\r
+       if (hasValue) {\r
+               jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";");\r
+               jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
+\r
+               jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod);\r
+               jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
+\r
+               return getPythonObject(env, value, componentBinding);\r
+       }\r
+       else {\r
+               return Py_None;\r
+       }\r
+}\r
+\r
+PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
+       jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";");\r
+       jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I");\r
+       jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
+       jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";");\r
+\r
+       jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS);\r
+       jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";");\r
+\r
+       jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS);\r
+       jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";");\r
+\r
+       jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object);\r
+       jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object);\r
+\r
+       jobject type = (*env)->CallObjectMethod(env, binding, typeMethod);\r
+       jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag);\r
+       jstring compName = (*env)->GetObjectField(env, typeComponent, nameField);\r
+\r
+       jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag);\r
+\r
+       PyObject *result = PyTuple_New(2);\r
+       PyTuple_SetItem(result, 0, getPythonString(env, compName));\r
+       PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding));\r
+\r
+       return result;\r
+}\r
+\r
+PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) {\r
+       jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
+       jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
+       jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";");\r
+\r
+       jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object);\r
+       jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object);\r
+\r
+       return getPythonObject(env, content, contentBinding);\r
+}\r
+\r
+PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) {\r
+       jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS);\r
+       jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS);\r
+       jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS);\r
+       jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS);\r
+       jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS);\r
+       jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS);\r
+       jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS);\r
+       jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS);\r
+       jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS);\r
+       jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS);\r
+       jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS);\r
+       jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS);\r
+       jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS);\r
+\r
+       if ((*env)->IsInstanceOf(env, binding, booleanBinding)) {\r
+               return getPythonBooleanObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, byteBinding)) {\r
+               return getPythonByteObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, integerBinding)) {\r
+               return getPythonIntegerObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, longBinding)) {\r
+               return getPythonLongObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, floatBinding)) {\r
+               return getPythonFloatObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) {\r
+               return getPythonDoubleObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, stringBinding)) {\r
+               return getPythonStringObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, recordBinding)) {\r
+               return getPythonRecordObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) {\r
+               return getPythonArrayObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, mapBinding)) {\r
+               return getPythonMapObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) {\r
+               return getPythonOptionalObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, untionBinding)) {\r
+               return getPythonUnionObject(env, value, binding);\r
+       }\r
+       else if ((*env)->IsInstanceOf(env, binding, variantBinding)) {\r
+               return getPythonVariantObject(env, value, binding);\r
+       }\r
+       else {\r
+               return Py_None;\r
+       }\r
+}\r
+\r
 void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {\r
        if (name && value) {\r
                PyDict_SetItem(PyModule_GetDict(module), name, value);\r
@@ -177,6 +495,62 @@ void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
        Py_XDECREF(value);\r
 }\r
 \r
+static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
+       if (d == nd) {\r
+               ncont[d] = 1;\r
+               return 1;\r
+       }\r
+       else {\r
+               npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);\r
+               ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;\r
+               return ncont[d];\r
+       }\r
+}\r
+\r
+static void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
+       if (ncont[d] > 0) {\r
+               (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);\r
+               *offset += ncont[d];\r
+       }\r
+       else {\r
+               int i;\r
+               for (i = 0; i < dims[d]; i++) {\r
+                       copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);\r
+               }\r
+       }\r
+}\r
+\r
+jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) {\r
+       jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean");\r
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;");\r
+\r
+       return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True));\r
+}\r
+\r
+jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) {\r
+       jclass longClass = (*env)->FindClass(env, "java/lang/Long");\r
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;");\r
+\r
+       return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value));\r
+}\r
+\r
+jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) {\r
+       jclass doubleClass = (*env)->FindClass(env, "java/lang/Double");\r
+       jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;");\r
+\r
+       return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value));\r
+}\r
+\r
+jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) {\r
+       Py_ssize_t size = PyByteArray_Size(value);\r
+       jbyteArray result = (*env)->NewByteArray(env, (jsize)size);\r
+       char *bytes = PyByteArray_AsString(value);\r
+\r
+       (*env)->SetByteArrayRegion(env, result, 0, size, bytes);\r
+\r
+       return result;\r
+}\r
+\r
 jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {\r
        PyObject *utf16Value = PyUnicode_AsUTF16String(string);\r
        Py_ssize_t len = PyBytes_Size(utf16Value) / 2;\r
@@ -190,15 +564,15 @@ jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) {
        return result;\r
 }\r
 \r
-jobjectArray pythonStringListAsJavaArray(JNIEnv *env, PyObject *list) {\r
-       Py_ssize_t len = PyList_Size(list);\r
+jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
        jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
        jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL);\r
 \r
        jint i;\r
 \r
        for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PyList_GetItem(list, i);\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
                if (PyUnicode_Check(item)) {\r
                        jstring value = pythonStringAsJavaString(env, item);\r
                        (*env)->SetObjectArrayElement(env, array, i, value);\r
@@ -212,15 +586,15 @@ jobjectArray pythonStringListAsJavaArray(JNIEnv *env, PyObject *list) {
        return array;\r
 }\r
 \r
-jdoubleArray pythonListAsDoubleArray(JNIEnv *env, PyObject *list) {\r
-       Py_ssize_t len = PyList_Size(list);\r
+jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
        jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
        jdoubleArray array = (*env)->NewDoubleArray(env, jlen);\r
 \r
        jint i;\r
 \r
        for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PyList_GetItem(list, i);\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
                if (PyFloat_Check(item)) {\r
                        double value = PyFloat_AsDouble(item);\r
                        (*env)->SetDoubleArrayRegion(env, array, i, 1, &value);\r
@@ -234,29 +608,107 @@ jdoubleArray pythonListAsDoubleArray(JNIEnv *env, PyObject *list) {
        return array;\r
 }\r
 \r
-npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
-       if (d == nd) {\r
-               ncont[d] = 1;\r
-               return 1;\r
+jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) {\r
+       if (PyBool_Check(value))\r
+               return pythonBoolAsBooleanObject(env, value);\r
+       else if (PyLong_Check(value))\r
+               return pythonLongAsLongObject(env, value);\r
+       else if (PyFloat_Check(value))\r
+               return pythonFloatAsDoubleObject(env, value);\r
+       else if (PyUnicode_Check(value))\r
+               return pythonStringAsJavaString(env, value);\r
+       else if (PyByteArray_Check(value))\r
+               return pythonByteArrayAsByteArray(env, value);\r
+       else if (PyDict_Check(value))\r
+               return pythonDictionaryAsMap(env, value);\r
+       else if (hasNumpy && PyArray_Check(value))\r
+               return pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
+       else if (PySequence_Check(value))\r
+               return pythonSequenceAsObjectArray(env, value);\r
+       else\r
+               return NULL;\r
+}\r
+\r
+jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
+       jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL);\r
+\r
+       jint i;\r
+\r
+       for (i = 0; i < jlen; i++) {\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
+               jobject object = pythonObjectAsObject(env, item);\r
+               (*env)->SetObjectArrayElement(env, array, i, object);\r
        }\r
-       else {\r
-               npy_intp n = nContiguous(d+1, nd, strides, dims, ncont);\r
-               ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0;\r
-               return ncont[d];\r
+\r
+       return array;\r
+}\r
+\r
+jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
+       jbooleanArray array = (*env)->NewBooleanArray(env, jlen);\r
+\r
+       jint i;\r
+\r
+       for (i = 0; i < jlen; i++) {\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
+               if (PyBool_Check(item)) {\r
+                       jboolean value = item == Py_True;\r
+                       (*env)->SetBooleanArrayRegion(env, array, i, 1, &value);\r
+               }\r
+               else {\r
+                       throwException(env, RUNTIME_EXCEPTION, "List item not a boolean");\r
+                       return NULL;\r
+               }\r
        }\r
+\r
+       return array;\r
 }\r
 \r
-void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) {\r
-       if (ncont[d] > 0) {\r
-               (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data);\r
-               *offset += ncont[d];\r
+jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
+       jintArray array = (*env)->NewIntArray(env, jlen);\r
+\r
+       jint i;\r
+\r
+       for (i = 0; i < jlen; i++) {\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
+               if (PyLong_Check(item)) {\r
+                       jint value = PyLong_AsLong(item);\r
+                       (*env)->SetIntArrayRegion(env, array, i, 1, &value);\r
+               }\r
+               else {\r
+                       throwException(env, RUNTIME_EXCEPTION, "List item not an integer");\r
+                       return NULL;\r
+               }\r
        }\r
-       else {\r
-               int i;\r
-               for (i = 0; i < dims[d]; i++) {\r
-                       copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont);\r
+\r
+       return array;\r
+}\r
+\r
+jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) {\r
+       Py_ssize_t len = PySequence_Size(seq);\r
+       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
+       jlongArray array = (*env)->NewLongArray(env, jlen);\r
+\r
+       jint i;\r
+\r
+       for (i = 0; i < jlen; i++) {\r
+               PyObject *item = PySequence_GetItem(seq, i);\r
+               if (PyLong_Check(item)) {\r
+                       jlong value = PyLong_AsLongLong(item);\r
+                       (*env)->SetLongArrayRegion(env, array, i, 1, &value);\r
+               }\r
+               else {\r
+                       throwException(env, RUNTIME_EXCEPTION, "List item not an integer");\r
+                       return NULL;\r
                }\r
        }\r
+\r
+       return array;\r
 }\r
 \r
 jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {\r
@@ -303,33 +755,49 @@ jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) {
        }\r
 }\r
 \r
-jintArray pythonListAsIntegerArray(JNIEnv *env, PyObject *list) {\r
-       Py_ssize_t len = PyList_Size(list);\r
-       jsize jlen = (jsize)min(len, JAVA_MAXINT);\r
-       jdoubleArray array = (*env)->NewIntArray(env, jlen);\r
+jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) {\r
+       jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap");\r
+       jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "<init>", "(I)V");\r
+       jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";");\r
 \r
-       jint i;\r
+       Py_ssize_t size = PyDict_Size(dict);\r
+       jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size);\r
 \r
-       for (i = 0; i < jlen; i++) {\r
-               PyObject *item = PyList_GetItem(list, i);\r
-               if (PyLong_Check(item)) {\r
-                       jint value = PyLong_AsLong(item);\r
-                       (*env)->SetIntArrayRegion(env, array, i, 1, &value);\r
-               }\r
-               else {\r
-                       throwException(env, RUNTIME_EXCEPTION, "List item not an integer");\r
-                       return NULL;\r
-               }\r
+       PyObject *key, *value;\r
+       Py_ssize_t pos = 0;\r
+\r
+       while (PyDict_Next(dict, &pos, &key, &value)) {\r
+               jobject keyObject = pythonObjectAsObject(env, key);\r
+               jobject valueObject = pythonObjectAsObject(env, value);\r
+               (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject);\r
        }\r
 \r
-       return array;\r
+       return map;\r
 }\r
 \r
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jint value) {\r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
        PyObject *pythonName = getPythonString(env, variableName);\r
-       PyObject *val = PyLong_FromLong(value);\r
+       PyObject *val = getPythonBool(value);\r
+\r
+       setPythonVariable(module, pythonName, val);\r
+}\r
+\r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+       PyObject *val = getPythonBooleanList(env, value);\r
+\r
+       setPythonVariable(module, pythonName, val);\r
+}\r
+\r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+       PyObject *val = PyLong_FromLongLong(value);\r
 \r
        setPythonVariable(module, pythonName, val);\r
 }\r
@@ -343,6 +811,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonInte
        setPythonVariable(module, pythonName, val);\r
 }\r
 \r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+       PyObject *val = getPythonLongList(env, value);\r
+\r
+       setPythonVariable(module, pythonName, val);\r
+}\r
+\r
 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
@@ -352,6 +829,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoub
        setPythonVariable(module, pythonName, val);\r
 }\r
 \r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+       PyObject *val = getPythonFloatList(env, value);\r
+\r
+       setPythonVariable(module, pythonName, val);\r
+}\r
+\r
 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
@@ -382,7 +868,7 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonStri
 JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
-       if (_import_array() < 0) {\r
+       if (!hasNumpy) {\r
                throwException(env, RUNTIME_EXCEPTION, "Importing numpy failed");\r
                return;\r
        }\r
@@ -395,6 +881,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDAr
        }\r
 }\r
 \r
+JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+       PyObject *val = getPythonObject(env, value, binding);\r
+\r
+       setPythonVariable(module, pythonName, val);\r
+}\r
+\r
 JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
@@ -418,8 +913,6 @@ JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePython
                                throwException(env, RUNTIME_EXCEPTION, message);\r
                        }\r
 \r
-                       // Py_XDECREF(globals);\r
-\r
                        (*env)->ReleaseStringUTFChars(env, statement, utfchars);\r
 \r
                        return result != NULL ? 0 : 1;\r
@@ -443,7 +936,10 @@ JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonS
                return 0;\r
        }\r
 \r
-       return pythonStringAsJavaString(env, value);\r
+       {\r
+               jstring result = pythonStringAsJavaString(env, value);\r
+               return result;\r
+       }\r
 }\r
 \r
 JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
@@ -457,15 +953,59 @@ JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPy
                return 0;\r
        }\r
 \r
-       if (!PyList_Check(value)) {\r
-               throwException(env, RUNTIME_EXCEPTION, "Python variable not a list");\r
+       if (!PySequence_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a sequence");\r
+               return 0;\r
+       }\r
+\r
+       {\r
+               jobjectArray result = pythonSequenceAsStringArray(env, value);\r
+               return result;\r
+       }\r
+}\r
+\r
+JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+\r
+       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
+       if (value == NULL) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not found");\r
+               return 0;\r
+       }\r
+\r
+       if (!PyBool_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a boolean");\r
                return 0;\r
        }\r
 \r
-       return pythonStringListAsJavaArray(env, value);\r
+       return value == Py_True;\r
 }\r
 \r
-JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+\r
+       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
+       if (value == NULL) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not found");\r
+               return 0;\r
+       }\r
+\r
+       if (!PySequence_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a sequence");\r
+               return 0;\r
+       }\r
+\r
+       {\r
+               jbooleanArray result = pythonSequenceAsBooleanArray(env, value);\r
+               return result;\r
+       }\r
+}\r
+\r
+JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
        PyObject *pythonName = getPythonString(env, variableName);\r
@@ -481,7 +1021,10 @@ JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonInte
                return 0;\r
        }\r
 \r
-       return PyLong_AsLong(value);\r
+       {\r
+               jlong result = PyLong_AsLongLong(value);\r
+               return result;\r
+       }\r
 }\r
 \r
 JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
@@ -495,12 +1038,37 @@ JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPytho
                return NULL;\r
        }\r
 \r
-       if (!PyList_Check(value)) {\r
-               throwException(env, RUNTIME_EXCEPTION, "Python variable not a list");\r
+       if (!PySequence_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a sequence");\r
                return NULL;\r
        }\r
 \r
-       return pythonListAsIntegerArray(env, value);\r
+       {\r
+               jintArray result = pythonSequenceAsIntegerArray(env, value);\r
+               return result;\r
+       }\r
+}\r
+\r
+JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+\r
+       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
+       if (value == NULL) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not found");\r
+               return NULL;\r
+       }\r
+\r
+       if (!PySequence_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a sequence");\r
+               return NULL;\r
+       }\r
+\r
+       {\r
+               jlongArray result = pythonSequenceAsLongArray(env, value);\r
+               return result;\r
+       }\r
 }\r
 \r
 JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
@@ -519,7 +1087,10 @@ JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonD
                return 0.0;\r
        }\r
 \r
-       return PyFloat_AsDouble(value);\r
+       {\r
+               jdouble result = PyFloat_AsDouble(value);\r
+               return result;\r
+       }\r
 }\r
 \r
 JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
@@ -533,18 +1104,21 @@ JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPy
                return NULL;\r
        }\r
 \r
-       if (!PyList_Check(value)) {\r
-               throwException(env, RUNTIME_EXCEPTION, "Python variable not a list");\r
+       if (!PySequence_Check(value)) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not a sequence");\r
                return NULL;\r
        }\r
 \r
-       return pythonListAsDoubleArray(env, value);\r
+       {\r
+               jdoubleArray result = pythonSequenceAsDoubleArray(env, value);\r
+               return result;\r
+       }\r
 }\r
 \r
 JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
        PyObject *module = (PyObject*)contextID;\r
 \r
-       if (_import_array() < 0) {\r
+       if (!hasNumpy) {\r
                throwException(env, RUNTIME_EXCEPTION, "Importing numpy failed");\r
                return NULL;\r
        }\r
@@ -568,8 +1142,88 @@ JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonN
                        return NULL;\r
                }\r
 \r
-               return pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
+               {\r
+                       jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value);\r
+                       return result;\r
+               }\r
+       }\r
+}\r
+\r
+JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+       PyObject *module = (PyObject*)contextID;\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+\r
+       PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);\r
+       if (value == NULL) {\r
+               throwException(env, RUNTIME_EXCEPTION, "Python variable not found");\r
+               return NULL;\r
        }\r
+\r
+       hasNumpy = _import_array() != -1;\r
+\r
+       {\r
+               jobject result = pythonObjectAsObject(env, value);\r
+               return result;\r
+       }\r
+}\r
+\r
+JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) {\r
+       PyObject *module = (PyObject*)contextID;\r
+       PyObject *dict = PyModule_GetDict(module);\r
+\r
+       PyObject *pythonName = getPythonString(env, variableName);\r
+\r
+       if (!PyDict_Contains(dict, pythonName)) {\r
+               return 0;\r
+       }\r
+\r
+       {\r
+               PyObject *value = PyDict_GetItem(dict, pythonName);\r
+\r
+               jint result;\r
+\r
+               if (PyBool_Check(value))\r
+                       result = 1;\r
+               else if (PyLong_Check(value))\r
+                       result = 2;\r
+               else if (PyFloat_Check(value))\r
+                       result = 3;\r
+               else if (PyUnicode_Check(value))\r
+                       result = 4;\r
+               else if (PyByteArray_Check(value))\r
+                       result = 5;\r
+               else if (PyDict_Check(value))\r
+                       result = 6;\r
+               else if (hasNumpy && PyArray_Check(value))\r
+                       result = 7;\r
+               else if (PySequence_Check(value))\r
+                       result = 8;\r
+               else\r
+                       result = -1;\r
+\r
+               return result;\r
+       }\r
+}\r
+\r
+JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) {\r
+       PyObject *module = (PyObject*)contextID;\r
+       PyObject *dict = PyModule_GetDict(module);\r
+\r
+       PyObject *keys = PyDict_Keys(dict);\r
+       Py_ssize_t size = PyList_Size(keys);\r
+\r
+       jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL);\r
+\r
+       Py_ssize_t i;\r
+       for (i = 0; i < size; i++) {\r
+               jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i));\r
+               (*env)->SetObjectArrayElement(env, result, (jint)i, javaName);\r
+       }\r
+\r
+       Py_XDECREF(keys);\r
+\r
+       return result;\r
 }\r
 \r
 BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\r
@@ -580,12 +1234,10 @@ BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
         case DLL_PROCESS_ATTACH:\r
             // attach to process\r
             // return FALSE to fail DLL load\r
-            Py_Initialize();\r
             break;\r
 \r
         case DLL_PROCESS_DETACH:\r
             // detach from process\r
-               Py_Finalize();\r
             break;\r
 \r
         case DLL_THREAD_ATTACH:\r
index ec3b400325b6f6e4b02ee2f701bcf3bfede88c30..4a2c7de919bcd90700bb9f17f968b7db8c3ff726 100644 (file)
@@ -1,6 +1,19 @@
 #ifndef __MAIN_H__\r
 #define __MAIN_H__\r
 \r
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\r
+#ifdef _DEBUG\r
+       #undef _DEBUG\r
+       #include <Python.h>  //header for system python import; add include paths\r
+       #include <numpy/arrayobject.h>\r
+       #define _DEBUG 1\r
+#else\r
+       #include <Python.h>  //header for system python import; add include paths\r
+       #include <numpy/arrayobject.h>\r
+#endif\r
+\r
+#include <jni.h> //java connection header\r
+\r
 /*  To use this exported function of dll, include this header\r
  *  in your project.\r
  */\r
     #define DLL_EXPORT __declspec(dllimport)\r
 #endif\r
 \r
+\r
+#define JAVA_MAXINT (0x7fffffff)\r
+\r
+#define RUNTIME_EXCEPTION "java/lang/RuntimeException"\r
+#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException"\r
+#define OBJECT_CLASS "java/lang/Object"\r
+#define STRING_CLASS "java/lang/String"\r
+#define MAP_CLASS "java/util/Map"\r
+#define SET_CLASS "java/util/Set"\r
+\r
+#define PACKAGE_PREFIX "org/simantics/pythonlink/"\r
+\r
+#define NDARRAY_CLASS (PACKAGE_PREFIX "NDArray")\r
+\r
+#define VARIANT_CLASS "org/simantics/databoard/binding/mutable/Variant"\r
+#define BINDINGS_CLASS "org/simantics/databoard/Bindings"\r
+#define BINDING_CLASS "org/simantics/databoard/binding/Binding"\r
+#define DATATYPE_CLASS "org/simantics/databoard/type/Datatype"\r
+\r
+#define BOOLEANTYPE_CLASS "org/simantics/databoard/type/BooleanType"\r
+#define BYTETYPE_CLASS "org/simantics/databoard/type/ByteType"\r
+#define INTEGERTYPE_CLASS "org/simantics/databoard/type/IntegerType"\r
+#define LONGTYPE_CLASS "org/simantics/databoard/type/LongType"\r
+#define FLOATTYPE_CLASS "org/simantics/databoard/type/FloatType"\r
+#define DOUBLETYPE_CLASS "org/simantics/databoard/type/DoubleType"\r
+#define STRINGTYPE_CLASS "org/simantics/databoard/type/StringType"\r
+#define RECORDTYPE_CLASS "org/simantics/databoard/type/RecordType"\r
+#define ARRAYTYPE_CLASS "org/simantics/databoard/type/ArrayType"\r
+#define MAPTYPE_CLASS "org/simantics/databoard/type/MapType"\r
+#define OPTIONALTYPE_CLASS "org/simantics/databoard/type/OptionalType"\r
+#define UNIONTYPE_CLASS "org/simantics/databoard/type/UnionType"\r
+#define VARIANTTYPE_CLASS "org/simantics/databoard/type/VariantType"\r
+\r
+#define BOOLEANBINDING_CLASS "org/simantics/databoard/binding/BooleanBinding"\r
+#define BYTEBINDING_CLASS "org/simantics/databoard/binding/ByteBinding"\r
+#define INTEGERBINDING_CLASS "org/simantics/databoard/binding/IntegerBinding"\r
+#define LONGBINDING_CLASS "org/simantics/databoard/binding/LongBinding"\r
+#define FLOATBINDING_CLASS "org/simantics/databoard/binding/FloatBinding"\r
+#define DOUBLEBINDING_CLASS "org/simantics/databoard/binding/DoubleBinding"\r
+#define STRINGBINDING_CLASS "org/simantics/databoard/binding/StringBinding"\r
+#define RECORDBINDING_CLASS "org/simantics/databoard/binding/RecordBinding"\r
+#define ARRAYBINDING_CLASS "org/simantics/databoard/binding/ArrayBinding"\r
+#define MAPBINDING_CLASS "org/simantics/databoard/binding/MapBinding"\r
+#define OPTIONALBINDING_CLASS "org/simantics/databoard/binding/OptionalBinding"\r
+#define UNIONBINDING_CLASS "org/simantics/databoard/binding/UnionBinding"\r
+#define VARIANTBINDING_CLASS "org/simantics/databoard/binding/VariantBinding"\r
+\r
+#define COMPONENT_CLASS "org/simantics/databoard/type/Component"\r
+#define TAGGEDOBJECT_CLASS "org/simantics/databoard/binding/mutable/TaggedObject"\r
+\r
+PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value);\r
+PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value);\r
+PyObject *getPythonIntegerList(JNIEnv *env, jintArray value);\r
+PyObject *getPythonLongList(JNIEnv *env, jlongArray value);\r
+PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value);\r
+PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value);\r
+\r
+PyObject *getPythonObject(JNIEnv *env, jobject object, jobject binding);\r
+\r
+PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonRecordObject(JNIEnv *env, jobjectArray object, jobject binding);\r
+PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding);\r
+PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding);\r
+\r
+void setPythonVariable(PyObject *module, PyObject *name, PyObject *value);\r
+\r
+jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value);\r
+jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value);\r
+jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value);\r
+jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value);\r
+jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string);\r
+jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq);\r
+jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *list);\r
+jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *list);\r
+jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *list);\r
+jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *list);\r
+jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict);\r
+jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array);\r
+jobject pythonObjectAsObject(JNIEnv *env, PyObject *value);\r
+\r
 #endif // __MAIN_H__\r
index 14c621bfe06676151d93fc28b134378b129005d1..427f880d040b4c1ba3eb48433f26e2689cab3e89 100644 (file)
@@ -9,7 +9,14 @@ Require-Bundle: org.junit,
  org.simantics.scl.runtime,\r
  gnu.trove3;bundle-version="3.0.3",\r
  org.simantics.scl.compiler,\r
- org.simantics.scl.osgi\r
+ org.simantics.scl.osgi,\r
+ org.simantics.db.layer0;bundle-version="1.1.0",\r
+ org.simantics.simulator.variable,\r
+ org.simantics,\r
+ org.simantics.application,\r
+ org.simantics.db.management,\r
+ org.simantics.scl.db;bundle-version="0.1.3",\r
+ org.simantics.modeling;bundle-version="1.1.1"\r
 Export-Package: org.simantics.pythonlink\r
 Bundle-Activator: org.simantics.pythonlink.Activator\r
 Bundle-ActivationPolicy: lazy\r
index 8b340917c0636a40dc3246b887dae8a6e9afa8c4..4444941d25a73a8efcc6f2fb649020e5a04f6248 100644 (file)
@@ -13,6 +13,7 @@
 <booleanAttribute key="clearwslog" value="false"/>\r
 <stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>\r
 <booleanAttribute key="default" value="false"/>\r
+<stringAttribute key="deselected_workspace_plugins" value="com.famfamfam.silk,org.simantics.acorn,org.simantics.annotation.ui,org.simantics.backup,org.simantics.backup.db,org.simantics.backup.ontology,org.simantics.basicexpression,org.simantics.browsing.ui,org.simantics.browsing.ui.common,org.simantics.browsing.ui.graph,org.simantics.browsing.ui.graph.impl,org.simantics.browsing.ui.model,org.simantics.browsing.ui.nattable,org.simantics.browsing.ui.platform,org.simantics.browsing.ui.swt,org.simantics.charts,org.simantics.db.procore.ui,org.simantics.debug.browser,org.simantics.debug.browser.ui,org.simantics.debug.graphical,org.simantics.debug.ui,org.simantics.desktop.product,org.simantics.desktop.ui,org.simantics.desktop.ui.ontology,org.simantics.diagram,org.simantics.diagram.connection,org.simantics.diagram.profile,org.simantics.diagram.svg,org.simantics.document,org.simantics.document.linking.ontology,org.simantics.document.linking.ui,org.simantics.document.server,org.simantics.document.server.io,org.simantics.document.swt.core,org.simantics.document.ui,org.simantics.document.ui.ontology,org.simantics.dublincore.ontology,org.simantics.editors,org.simantics.editors.win32,org.simantics.equation,org.simantics.event,org.simantics.excel,org.simantics.export.core,org.simantics.export.ui,org.simantics.fileimport,org.simantics.fileimport.ui,org.simantics.g2d,org.simantics.graphfile,org.simantics.graphviz,org.simantics.graphviz.ui,org.simantics.help.base,org.simantics.help.core,org.simantics.help.files,org.simantics.help.ontology,org.simantics.help.ui,org.simantics.history,org.simantics.image.ui,org.simantics.issues,org.simantics.issues.common,org.simantics.issues.ui,org.simantics.issues.ui.ontology,org.simantics.mapping,org.simantics.matlablink,org.simantics.matlablink.win32.x86_64,org.simantics.message,org.simantics.message.ui,org.simantics.migration.ui,org.simantics.modeling,org.simantics.modeling.template2d.ui,org.simantics.modeling.ui,org.simantics.nativemem,org.simantics.objmap2,org.simantics.scenegraph,org.simantics.scenegraph.loader,org.simantics.scenegraph.profile,org.simantics.scenegraph.swing,org.simantics.scenegraph.ui,org.simantics.scl.commands,org.simantics.scl.compiler.dummy,org.simantics.scl.compiler.tests,org.simantics.scl.data,org.simantics.scl.db,org.simantics.scl.expressions,org.simantics.scl.osgi.tests,org.simantics.scl.ui,org.simantics.scl.ui.editor,org.simantics.selectionview,org.simantics.simulation,org.simantics.simulation.sequences,org.simantics.simulation.ui,org.simantics.spreadsheet,org.simantics.spreadsheet.common,org.simantics.spreadsheet.fileimport,org.simantics.spreadsheet.graph,org.simantics.spreadsheet.ui,org.simantics.structural.synchronization,org.simantics.structural.synchronization.client,org.simantics.structural.ui,org.simantics.structural2,org.simantics.team.ui,org.simantics.threadlog,org.simantics.trend,org.simantics.ui,org.simantics.utils.thread.swt,org.simantics.utils.ui,org.simantics.utils.ui.workbench,org.simantics.views,org.simantics.views.swt,org.simantics.views.swt.client,org.simantics.wiki.ui,org.simantics.workbench,org.simantics.workbench.ontology,org.simantics.workbench.search,winterwell.markdown"/>\r
 <stringAttribute key="featureDefaultLocation" value="workspace"/>\r
 <stringAttribute key="featurePluginResolution" value="workspace"/>\r
 <booleanAttribute key="includeOptional" value="true"/>\r
 <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.simantics.pythonlink"/>\r
 <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>\r
 <stringAttribute key="pde.version" value="3.3"/>\r
-<stringAttribute key="product" value="fi.vtt.apros.bootstrap.product"/>\r
+<stringAttribute key="product" value="org.simantics.project.headless"/>\r
 <booleanAttribute key="run_in_ui_thread" value="true"/>\r
 <setAttribute key="selected_features">\r
+<setEntry value="com.lowagie.text:default"/>\r
+<setEntry value="org.apache.lucene4:default"/>\r
+<setEntry value="org.jfree:default"/>\r
+<setEntry value="org.simantics.browsing.ui:default"/>\r
+<setEntry value="org.simantics.charts:default"/>\r
+<setEntry value="org.simantics.db.client:default"/>\r
+<setEntry value="org.simantics.document.base:default"/>\r
+<setEntry value="org.simantics.document.swt:default"/>\r
+<setEntry value="org.simantics.event.feature:default"/>\r
+<setEntry value="org.simantics.g2d:default"/>\r
+<setEntry value="org.simantics.layer0:default"/>\r
+<setEntry value="org.simantics.migration:default"/>\r
+<setEntry value="org.simantics.modeling:default"/>\r
 <setEntry value="org.simantics.pythonlink:default"/>\r
 <setEntry value="org.simantics.scl:default"/>\r
+<setEntry value="org.simantics.selectionview:default"/>\r
+<setEntry value="org.simantics.simulation:default"/>\r
+<setEntry value="org.simantics.spreadsheet.ui:default"/>\r
+<setEntry value="org.simantics.spreadsheet:default"/>\r
+<setEntry value="org.simantics.structural:default"/>\r
+<setEntry value="org.simantics.views.swt.client.feature:default"/>\r
+<setEntry value="org.simantics.views.swt.feature:default"/>\r
 </setAttribute>\r
+<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,com.ibm.icu@default:default,freemarker@default:default,gnu.trove3@default:default,jakarta-regexp@default:default,javax.annotation@default:default,javax.el@default:default,javax.inject@default:default,javax.servlet.jsp@default:default,javax.servlet@default:default,javax.xml@default:default,org.antlr.runtime@default:default,org.apache.ant@default:default,org.apache.batik.css@default:default,org.apache.batik.util.gui@default:default,org.apache.batik.util@default:default,org.apache.commons.collections@default:default,org.apache.commons.io@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging*1.2.0@default:default,org.apache.log4j@default:default,org.apache.lucene4.analyzers-common@default:default,org.apache.lucene4.core@default:default,org.apache.lucene4.queries@default:default,org.apache.lucene4.queryparser@default:default,org.apache.lucene4.sandbox@default:default,org.eclipse.ant.core@default:default,org.eclipse.compare.core@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.core.databinding@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filesystem.java7@default:false,org.eclipse.core.filesystem.win32.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.net.win32.x86_64@default:false,org.eclipse.core.net@default:default,org.eclipse.core.resources.win32.x86_64@default:false,org.eclipse.core.resources@default:default,org.eclipse.core.runtime.compatibility.registry@default:false,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.ecf.provider.filetransfer.ssl@default:false,org.eclipse.ecf.provider.filetransfer@default:default,org.eclipse.ecf.ssl@default:false,org.eclipse.ecf@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.bidi@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.concurrent@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.console@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.director.app@default:default,org.eclipse.equinox.p2.director@default:default,org.eclipse.equinox.p2.directorywatcher@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.extensionlocation@default:default,org.eclipse.equinox.p2.garbagecollector@default:default,org.eclipse.equinox.p2.jarprocessor@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.operations@default:default,org.eclipse.equinox.p2.publisher.eclipse@default:default,org.eclipse.equinox.p2.publisher@default:default,org.eclipse.equinox.p2.reconciler.dropins@default:default,org.eclipse.equinox.p2.repository.tools@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.p2.touchpoint.eclipse@default:default,org.eclipse.equinox.p2.touchpoint.natives@default:default,org.eclipse.equinox.p2.transport.ecf@default:default,org.eclipse.equinox.p2.updatechecker@default:default,org.eclipse.equinox.p2.updatesite@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.security.win32.x86_64@default:false,org.eclipse.equinox.security@default:default,org.eclipse.equinox.simpleconfigurator.manipulator@default:default,org.eclipse.equinox.simpleconfigurator@1:true,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt.win32.win32.x86_64@default:false,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.ui.trace@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.hamcrest.core@default:default,org.junit@default:default,org.mozilla.rhino@default:default,org.objectweb.asm.analysis@default:default,org.objectweb.asm.commons@default:default,org.objectweb.asm.tree@default:default,org.objectweb.asm.util@default:default,org.objectweb.asm@default:default,org.sat4j.core@default:default,org.sat4j.pb@default:default,org.slf4j.api*1.7.20@default:default,org.tukaani.xz@default:default,org.w3c.css.sac@default:default,org.w3c.dom.events@default:default,org.w3c.dom.smil@default:default,org.w3c.dom.svg@default:default"/>\r
+<stringAttribute key="selected_workspace_plugins" value="org.apache.batik@default:default,org.simantics.action.ontology@default:default,org.simantics.annotation.ontology@default:default,org.simantics.application@default:default,org.simantics.browsing.ui.ontology@default:default,org.simantics.charts.ontology@default:default,org.simantics.color.ontology@default:default,org.simantics.common@default:default,org.simantics.compressions@default:default,org.simantics.databoard@default:default,org.simantics.datatypes.ontology@default:default,org.simantics.datatypes@default:default,org.simantics.db.common@default:default,org.simantics.db.impl@default:default,org.simantics.db.indexing@default:default,org.simantics.db.layer0@default:default,org.simantics.db.management@default:default,org.simantics.db.procore.server.environment@default:default,org.simantics.db.procore@default:default,org.simantics.db.server@default:default,org.simantics.db.services@default:default,org.simantics.db@default:default,org.simantics.diagram.ontology@default:default,org.simantics.document.base.ontology@default:default,org.simantics.document.ontology@default:default,org.simantics.document.swt.ontology@default:default,org.simantics.event.ontology@default:default,org.simantics.fastlz@default:default,org.simantics.g2d.ontology@default:default,org.simantics.graph.compiler@default:default,org.simantics.graph.db@default:default,org.simantics.graph@default:default,org.simantics.graphfile.ontology@default:default,org.simantics.image.ontology@default:default,org.simantics.image2.ontology@default:default,org.simantics.issues.ontology@default:default,org.simantics.layer0.utils@default:default,org.simantics.layer0@default:default,org.simantics.layer0x.ontology@default:default,org.simantics.logback.configuration@default:false,org.simantics.ltk.antlr@default:default,org.simantics.ltk@default:default,org.simantics.lz4@default:default,org.simantics.modeling.ontology@default:default,org.simantics.modeling.template2d.ontology@default:default,org.simantics.platform.ui.ontology@default:default,org.simantics.project.ontology@default:default,org.simantics.project@default:default,org.simantics.pythonlink.win32.x86_64@default:false,org.simantics.pythonlink@default:default,org.simantics.scenegraph.ontology@default:default,org.simantics.scl.compiler@default:default,org.simantics.scl.osgi@default:default,org.simantics.scl.reflection@default:default,org.simantics.scl.runtime@default:default,org.simantics.selectionview.ontology@default:default,org.simantics.selectionview.ui.ontology@default:default,org.simantics.silk.ontology@default:default,org.simantics.simulation.ontology@default:default,org.simantics.simulator.variable@default:default,org.simantics.softwareconfiguration.ontology@default:default,org.simantics.spreadsheet.ontology@default:default,org.simantics.structural.ontology@default:default,org.simantics.user.ontology@default:default,org.simantics.utils.datastructures@default:default,org.simantics.utils.thread@default:default,org.simantics.utils@default:default,org.simantics.viewpoint.ontology@default:default,org.simantics.views.ontology@default:default,org.simantics@default:default"/>\r
 <booleanAttribute key="show_selected_only" value="false"/>\r
 <booleanAttribute key="tracing" value="false"/>\r
 <booleanAttribute key="useCustomFeatures" value="true"/>\r
index b4c34eb2f3f3db4b550313da17b0d4007a875fc3..dadf3346d2d9887196c9af531604617e12862d48 100644 (file)
 <stringAttribute key="pde.version" value="3.3"/>\r
 <stringAttribute key="product" value="fi.vtt.apros.bootstrap.product"/>\r
 <booleanAttribute key="run_in_ui_thread" value="true"/>\r
-<setAttribute key="selected_features"/>\r
-<stringAttribute key="selected_target_plugins" value="com.ibm.icu@default:default,gnu.trove3@default:default,javax.annotation@default:default,javax.inject@default:default,javax.servlet@default:default,javax.xml@default:default,org.apache.commons.collections@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.runtime@default:true,org.eclipse.equinox.app@default:default,org.eclipse.equinox.bidi@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.util@default:default,org.eclipse.help@default:default,org.eclipse.jface@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt.win32.win32.x86_64@default:false,org.eclipse.swt@default:default,org.hamcrest.core@default:default,org.junit@default:default,org.objectweb.asm.analysis@default:default,org.objectweb.asm.commons@default:default,org.objectweb.asm.tree@default:default,org.objectweb.asm.util@default:default,org.objectweb.asm@default:default"/>\r
-<stringAttribute key="selected_workspace_plugins" value="org.simantics.common@default:default,org.simantics.databoard@default:default,org.simantics.pythonlink.win32.x86_64*1.0.0.qualifier@default:false,org.simantics.pythonlink@default:default,org.simantics.scl.compiler@default:default,org.simantics.scl.osgi@default:default,org.simantics.scl.runtime@default:default"/>\r
+<setAttribute key="selected_features">\r
+<setEntry value="com.lowagie.text:default"/>\r
+<setEntry value="org.apache.lucene4:default"/>\r
+<setEntry value="org.eclipse.e4.rcp:default"/>\r
+<setEntry value="org.eclipse.ecf.core.feature:default"/>\r
+<setEntry value="org.eclipse.ecf.core.ssl.feature:default"/>\r
+<setEntry value="org.eclipse.ecf.filetransfer.feature:default"/>\r
+<setEntry value="org.eclipse.ecf.filetransfer.httpclient4.feature:default"/>\r
+<setEntry value="org.eclipse.ecf.filetransfer.httpclient4.ssl.feature:default"/>\r
+<setEntry value="org.eclipse.ecf.filetransfer.ssl.feature:default"/>\r
+<setEntry value="org.eclipse.emf.common:default"/>\r
+<setEntry value="org.eclipse.emf.ecore:default"/>\r
+<setEntry value="org.eclipse.rcp:default"/>\r
+<setEntry value="org.jfree:default"/>\r
+<setEntry value="org.simantics.browsing.ui:default"/>\r
+<setEntry value="org.simantics.charts:default"/>\r
+<setEntry value="org.simantics.data:default"/>\r
+<setEntry value="org.simantics.db.client:default"/>\r
+<setEntry value="org.simantics.document.base:default"/>\r
+<setEntry value="org.simantics.document.swt:default"/>\r
+<setEntry value="org.simantics.event.feature:default"/>\r
+<setEntry value="org.simantics.g2d:default"/>\r
+<setEntry value="org.simantics.layer0:default"/>\r
+<setEntry value="org.simantics.migration:default"/>\r
+<setEntry value="org.simantics.modeling:default"/>\r
+<setEntry value="org.simantics.pythonlink:default"/>\r
+<setEntry value="org.simantics.rcp:default"/>\r
+<setEntry value="org.simantics.scl:default"/>\r
+<setEntry value="org.simantics.selectionview:default"/>\r
+<setEntry value="org.simantics.simulation:default"/>\r
+<setEntry value="org.simantics.spreadsheet.ui:default"/>\r
+<setEntry value="org.simantics.spreadsheet:default"/>\r
+<setEntry value="org.simantics.structural:default"/>\r
+<setEntry value="org.simantics.ui.workbench:default"/>\r
+<setEntry value="org.simantics.views.swt.client.feature:default"/>\r
+<setEntry value="org.simantics.views.swt.feature:default"/>\r
+</setAttribute>\r
+<stringAttribute key="selected_target_plugins" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,com.ibm.icu@default:default,com.lowagie.text@default:default,freemarker@default:default,gnu.trove2@default:default,gnu.trove3@default:default,jakarta-regexp@default:default,javax.annotation@default:default,javax.el@default:default,javax.inject@default:default,javax.servlet.jsp@default:default,javax.servlet@default:default,javax.vecmath@default:default,javax.xml@default:default,org.antlr.runtime@default:default,org.apache.ant@default:default,org.apache.batik.css@default:default,org.apache.batik.util.gui@default:default,org.apache.batik.util@default:default,org.apache.commons.collections@default:default,org.apache.commons.compress@default:default,org.apache.commons.io@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging*1.2.0@default:default,org.apache.log4j@default:default,org.apache.lucene4.analyzers-common@default:default,org.apache.lucene4.core@default:default,org.apache.lucene4.queries@default:default,org.apache.lucene4.queryparser@default:default,org.apache.lucene4.sandbox@default:default,org.bouncycastle.bcmail-jdk14@default:default,org.bouncycastle.bcprov-jdk14@default:default,org.bouncycastle.bctsp-jdk14@default:default,org.eclipse.ant.core@default:default,org.eclipse.compare.core@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding.observable@default:default,org.eclipse.core.databinding.property@default:default,org.eclipse.core.databinding@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filebuffers@default:default,org.eclipse.core.filesystem.java7@default:false,org.eclipse.core.filesystem.win32.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.net.win32.x86_64@default:false,org.eclipse.core.net@default:default,org.eclipse.core.resources.win32.x86_64@default:false,org.eclipse.core.resources@default:default,org.eclipse.core.runtime.compatibility.registry@default:false,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.ecf.filetransfer@default:default,org.eclipse.ecf.identity@default:default,org.eclipse.ecf.provider.filetransfer.ssl@default:false,org.eclipse.ecf.provider.filetransfer@default:default,org.eclipse.ecf.ssl@default:false,org.eclipse.ecf@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.bidi@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.concurrent@default:default,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.frameworkadmin.equinox@default:default,org.eclipse.equinox.frameworkadmin@default:default,org.eclipse.equinox.p2.artifact.repository@default:default,org.eclipse.equinox.p2.console@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.director.app@default:default,org.eclipse.equinox.p2.director@default:default,org.eclipse.equinox.p2.directorywatcher@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.extensionlocation@default:default,org.eclipse.equinox.p2.garbagecollector@default:default,org.eclipse.equinox.p2.jarprocessor@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.operations@default:default,org.eclipse.equinox.p2.publisher.eclipse@default:default,org.eclipse.equinox.p2.publisher@default:default,org.eclipse.equinox.p2.reconciler.dropins@default:default,org.eclipse.equinox.p2.repository.tools@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.p2.touchpoint.eclipse@default:default,org.eclipse.equinox.p2.touchpoint.natives@default:default,org.eclipse.equinox.p2.transport.ecf@default:default,org.eclipse.equinox.p2.updatechecker@default:default,org.eclipse.equinox.p2.updatesite@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.security.win32.x86_64@default:false,org.eclipse.equinox.security@default:default,org.eclipse.equinox.simpleconfigurator.manipulator@default:default,org.eclipse.equinox.simpleconfigurator@1:true,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.util@default:default,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface.text@default:default,org.eclipse.jface@default:default,org.eclipse.nebula.widgets.pgroup@default:default,org.eclipse.nebula.widgets.tablecombo@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.eclipse.swt.win32.win32.x86_64@default:false,org.eclipse.swt@default:default,org.eclipse.text@default:default,org.eclipse.ui.editors@default:default,org.eclipse.ui.forms@default:default,org.eclipse.ui.ide@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.win32@default:false,org.eclipse.ui.workbench.texteditor@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.hamcrest.core@default:default,org.jfree.jchart@default:default,org.jfree.jcommon@default:default,org.junit@default:default,org.mozilla.rhino@default:default,org.objectweb.asm.analysis@default:default,org.objectweb.asm.commons@default:default,org.objectweb.asm.tree@default:default,org.objectweb.asm.util@default:default,org.objectweb.asm@default:default,org.sat4j.core@default:default,org.sat4j.pb@default:default,org.slf4j.api*1.7.20@default:default,org.tukaani.xz@default:default,org.w3c.css.sac@default:default,org.w3c.dom.events@default:default,org.w3c.dom.smil@default:default,org.w3c.dom.svg@default:default"/>\r
+<stringAttribute key="selected_workspace_plugins" value="org.apache.batik@default:default,org.simantics.action.ontology@default:default,org.simantics.annotation.ontology@default:default,org.simantics.application@default:default,org.simantics.basicexpression@default:default,org.simantics.browsing.ui.common@default:default,org.simantics.browsing.ui.model@default:default,org.simantics.browsing.ui.ontology@default:default,org.simantics.browsing.ui@default:default,org.simantics.charts.ontology@default:default,org.simantics.color.ontology@default:default,org.simantics.common@default:default,org.simantics.compressions@default:default,org.simantics.databoard@default:default,org.simantics.datatypes.ontology@default:default,org.simantics.datatypes@default:default,org.simantics.db.common@default:default,org.simantics.db.impl@default:default,org.simantics.db.indexing@default:default,org.simantics.db.layer0@default:default,org.simantics.db.management@default:default,org.simantics.db.procore.server.environment@default:default,org.simantics.db.procore@default:default,org.simantics.db.server@default:default,org.simantics.db.services@default:default,org.simantics.db@default:default,org.simantics.diagram.connection@default:default,org.simantics.diagram.ontology@default:default,org.simantics.diagram@default:default,org.simantics.document.base.ontology@default:default,org.simantics.document.ontology@default:default,org.simantics.document.swt.ontology@default:default,org.simantics.event.ontology@default:default,org.simantics.export.core@default:default,org.simantics.fastlz@default:default,org.simantics.g2d.ontology@default:default,org.simantics.g2d@default:default,org.simantics.graph.compiler@default:default,org.simantics.graph.db@default:default,org.simantics.graph@default:default,org.simantics.graphfile.ontology@default:default,org.simantics.graphviz.ui@default:default,org.simantics.graphviz@default:default,org.simantics.history@default:default,org.simantics.image.ontology@default:default,org.simantics.image2.ontology@default:default,org.simantics.issues.common@default:default,org.simantics.issues.ontology@default:default,org.simantics.issues.ui.ontology@default:default,org.simantics.issues@default:default,org.simantics.layer0.utils@default:default,org.simantics.layer0@default:default,org.simantics.layer0x.ontology@default:default,org.simantics.logback.configuration@default:false,org.simantics.ltk.antlr@default:default,org.simantics.ltk@default:default,org.simantics.lz4@default:default,org.simantics.mapping@default:default,org.simantics.modeling.ontology@default:default,org.simantics.modeling.template2d.ontology@default:default,org.simantics.modeling@default:default,org.simantics.platform.ui.ontology@default:default,org.simantics.project.ontology@default:default,org.simantics.project@default:default,org.simantics.pythonlink.win32.x86_64@default:false,org.simantics.pythonlink@default:default,org.simantics.scenegraph.loader@default:default,org.simantics.scenegraph.ontology@default:default,org.simantics.scenegraph.profile@default:default,org.simantics.scenegraph@default:default,org.simantics.scl.commands@default:default,org.simantics.scl.compiler@default:default,org.simantics.scl.db@default:default,org.simantics.scl.osgi@default:default,org.simantics.scl.reflection@default:default,org.simantics.scl.runtime@default:default,org.simantics.scl.ui@default:default,org.simantics.selectionview.ontology@default:default,org.simantics.selectionview.ui.ontology@default:default,org.simantics.silk.ontology@default:default,org.simantics.simulation.ontology@default:default,org.simantics.simulation@default:default,org.simantics.simulator.variable@default:default,org.simantics.softwareconfiguration.ontology@default:default,org.simantics.spreadsheet.ontology@default:default,org.simantics.structural.ontology@default:default,org.simantics.structural2@default:default,org.simantics.threadlog@default:default,org.simantics.trend@default:default,org.simantics.ui@default:default,org.simantics.user.ontology@default:default,org.simantics.utils.datastructures@default:default,org.simantics.utils.thread.swt@default:default,org.simantics.utils.thread@default:default,org.simantics.utils.ui.workbench@default:default,org.simantics.utils.ui@default:default,org.simantics.utils@default:default,org.simantics.viewpoint.ontology@default:default,org.simantics.views.ontology@default:default,org.simantics@default:default"/>\r
 <booleanAttribute key="show_selected_only" value="false"/>\r
 <booleanAttribute key="tracing" value="false"/>\r
-<booleanAttribute key="useCustomFeatures" value="false"/>\r
+<booleanAttribute key="useCustomFeatures" value="true"/>\r
 <booleanAttribute key="useDefaultConfig" value="true"/>\r
 <booleanAttribute key="useDefaultConfigArea" value="false"/>\r
 <booleanAttribute key="useProduct" value="false"/>\r
index b1ca052ef2b026c3a3f00ebdcf05b2784e3962d8..5fc78318e62b88ce0f7fee4ed2b539613abec558 100644 (file)
@@ -1,5 +1,3 @@
-import "Vector"\r
-\r
 effect Python\r
     "Simantics/Python/Python"\r
     "org.simantics.pythonlink.PythonContext"\r
@@ -36,6 +34,27 @@ importJava "org.simantics.pythonlink.NDArray" where
     @JavaName equals\r
     ndarrayEquals :: NDArray -> NDArray -> Boolean\r
 \r
+class NDArrayInput a where\r
+    ndarrayInput :: a -> ([Integer], [Double])\r
+    \r
+instance NDArrayInput [Double] where\r
+    ndarrayInput v = ([length v], v)\r
+    \r
+instance (NDArrayInput [a]) => NDArrayInput [[a]] where\r
+    ndarrayInput v = let\r
+        inp = map ndarrayInput v\r
+        dims = map fst inp\r
+        vals = join $ map snd inp\r
+      in\r
+        if not (all (== (dims!0)) dims) then\r
+            fail "List of lists not of uniform dimension"\r
+          else\r
+            ([length v] + (dims!0), vals)\r
+\r
+ndarrayFromList :: NDArrayInput a => a -> NDArray\r
+ndarrayFromList v = ndarrayN (vector dims) (vector vals) where\r
+    (dims, vals) = ndarrayInput v\r
+\r
 instance Show NDArray where\r
     show = ndarrayToString\r
 \r
@@ -50,22 +69,35 @@ importJava "org.simantics.pythonlink.PythonContext" where
     \r
     executePythonStatement :: String -> <Python> ()\r
     \r
+    setPythonBooleanVariable :: String -> Boolean -> <Python> ()\r
     setPythonIntegerVariable :: String -> Integer -> <Python> ()\r
-    setPythonIntegerArrayVariable :: String -> Vector Integer -> <Python> ()\r
+    setPythonLongVariable :: String -> Long -> <Python> ()\r
     setPythonDoubleVariable :: String -> Double -> <Python> ()\r
-    setPythonDoubleArrayVariable :: String -> Vector Double -> <Python> ()\r
     setPythonStringVariable :: String -> String -> <Python> ()\r
+    \r
+    setPythonBooleanArrayVariable :: String -> Vector Boolean -> <Python> ()\r
+    setPythonIntegerArrayVariable :: String -> Vector Integer -> <Python> ()\r
+    setPythonLongArrayVariable :: String -> Vector Long -> <Python> ()\r
+    setPythonDoubleArrayVariable :: String -> Vector Double -> <Python> ()\r
     setPythonStringArrayVariable :: String -> Vector String -> <Python> ()\r
     setPythonNDArrayVariable :: String -> NDArray -> <Python> ()\r
     \r
+    getPythonBooleanVariable :: String -> <Python> Boolean\r
     getPythonIntegerVariable :: String -> <Python> Integer\r
-    getPythonIntegerArrayVariable :: String -> <Python> Vector Integer\r
+    getPythonLongVariable :: String -> <Python> Long\r
     getPythonDoubleVariable :: String -> <Python> Double\r
-    getPythonDoubleArrayVariable :: String -> <Python> Vector Double\r
     getPythonStringVariable :: String -> <Python> String\r
+    \r
+    getPythonBooleanArrayVariable :: String -> <Python> Vector Boolean\r
+    getPythonIntegerArrayVariable :: String -> <Python> Vector Integer\r
+    getPythonLongArrayVariable :: String -> <Python> Vector Long\r
+    getPythonDoubleArrayVariable :: String -> <Python> Vector Double\r
     getPythonStringArrayVariable  :: String -> <Python> Vector String\r
     getPythonNDArrayVariable :: String -> <Python> NDArray\r
     \r
+    setPythonVariantVariable :: String -> Variant -> <Python> ()\r
+    getPythonVariantVariable :: String -> <Python> Variant\r
+\r
 importJava "org.simantics.pythonlink.Python" where\r
     openPythonContext :: <Proc> PythonContext\r
     \r
diff --git a/org.simantics.pythonlink/scl/PythonVariable.scl b/org.simantics.pythonlink/scl/PythonVariable.scl
new file mode 100644 (file)
index 0000000..55db31c
--- /dev/null
@@ -0,0 +1,5 @@
+include "Python"\r
+include "Simantics/Variables"\r
+\r
+importJava "org.simantics.pythonlink.Python" where\r
+    getPythonContextVariable :: PythonContext -> <Proc> Variable\r
index 07921fd2c530b10a4850544db2f5720a8f814dff..9d00c447a1dc81b67a8349ca7f9129506ef4702f 100644 (file)
@@ -1,8 +1,20 @@
 package org.simantics.pythonlink;\r
 \r
+import java.util.List;\r
+import java.util.concurrent.TimeUnit;\r
+\r
+import org.simantics.db.layer0.variable.NodeSupport;\r
+import org.simantics.db.layer0.variable.StandardGraphChildVariable;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.VariableNode;\r
+import org.simantics.pythonlink.PythonContext.Listener;\r
+import org.simantics.pythonlink.variable.PythonNode;\r
+import org.simantics.pythonlink.variable.PythonNodeManager;\r
 import org.simantics.scl.runtime.SCLContext;\r
 import org.simantics.scl.runtime.function.Function;\r
 import org.simantics.scl.runtime.tuple.Tuple0;\r
+import org.simantics.simulator.variable.NodeManager;\r
+import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
 \r
 public class Python {\r
     private static final String PYTHON_CONTEXT = "Simantics/Python/Python";\r
@@ -11,6 +23,50 @@ public class Python {
         return new PythonContext();\r
     }\r
     \r
+    public static Variable getPythonContextVariable(PythonContext context) {\r
+       NodeManager<PythonNode> nodeManager = new PythonNodeManager(context);\r
+       PythonNode root;\r
+               try {\r
+                       root = nodeManager.getNode("/");\r
+               } catch (NodeManagerException e) {\r
+                       // Should not happen\r
+                       throw new RuntimeException("Getting root Python node failed");\r
+               }\r
+               \r
+               final NodeSupport<PythonNode> support = new NodeSupport<PythonNode>(nodeManager, 0, TimeUnit.NANOSECONDS);\r
+               \r
+               context.addListener(new Listener() {\r
+            @Override\r
+            public void updated(String variableName) {\r
+                try {\r
+                    PythonNode root = nodeManager.getNode("/");\r
+                    if (variableName != null) {\r
+                        PythonNode node = nodeManager.getNode(variableName);\r
+                        if (node != null) support.valueCache.removeListening(node);\r
+                        support.structureCache.removeListening(root);\r
+                    }\r
+                    else {\r
+                        List<PythonNode> props = nodeManager.getProperties(root);\r
+                        for (PythonNode p : props)\r
+                            support.valueCache.removeListening(p);\r
+                        support.structureCache.removeListening(root);\r
+                    }\r
+                    \r
+                    support.valueCache.clearExpired();\r
+                    support.structureCache.clearExpired();\r
+                } catch (NodeManagerException e) {\r
+                    e.printStackTrace();\r
+                }\r
+            }\r
+            \r
+            @Override\r
+            public void closed() {\r
+            }\r
+        });\r
+               \r
+       return new StandardGraphChildVariable(null, new VariableNode<PythonNode>(support, root), null);\r
+    }\r
+    \r
     @SuppressWarnings( { "unchecked", "rawtypes" } )\r
     public static Object runPythonF(Function f) {\r
         SCLContext sclContext = SCLContext.getCurrent();\r
index 5341cc233c16c02076e00bbfa8684aa09d14c001..6c96dd3bde8a877e1e2115c4f1686f4101a44200 100644 (file)
@@ -1,21 +1,73 @@
 package org.simantics.pythonlink;\r
 \r
 import java.io.Closeable;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.ExecutionException;\r
+import java.util.concurrent.ExecutorService;\r
+import java.util.concurrent.Executors;\r
+import java.util.regex.Pattern;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
 \r
 public class PythonContext implements Closeable {\r
     private long contextID;\r
     \r
+    public interface Listener {\r
+       void updated(String variableName);\r
+       void closed();\r
+    }\r
+    \r
+    static ExecutorService pythonExecutor = Executors.newSingleThreadExecutor();\r
+    \r
+    Set<Listener> listeners = new HashSet<>();\r
+    \r
+    public enum VariableType {\r
+       NO_VARIABLE,\r
+       BOOLEAN,\r
+       LONG,\r
+       FLOAT,\r
+       STRING,\r
+       BYTEARRAY,\r
+       DICTIONARY,\r
+       NDARRAY,\r
+       SEQUENCE,\r
+       UNKNOWN\r
+    }\r
+    \r
+    static Pattern namePattern = Pattern.compile("([a-zA-Z_][a-zA-Z_0-9]*)");\r
+    \r
     PythonContext() {\r
         contextID = createContextImpl();\r
     }\r
     \r
+    public void addListener(Listener listener) {\r
+       listeners.add(listener);\r
+    }\r
+    \r
+    public void removeListener(Listener listener) {\r
+               listeners.remove(listener);\r
+    }\r
+    \r
     @Override\r
     public void close() {\r
         long id = contextID;\r
         contextID = 0;\r
         if (id != 0) deleteContextImpl(id);\r
+        \r
+       for (Listener l : listeners) {\r
+               l.closed();\r
+       }\r
     }\r
 \r
+       public boolean isOpen() {\r
+               return contextID != 0;\r
+       }\r
+       \r
     @Override\r
     protected void finalize() throws Throwable {\r
         super.finalize();\r
@@ -23,82 +75,220 @@ public class PythonContext implements Closeable {
     }\r
     \r
     public void executePythonStatement(String statement) {\r
-        executePythonStatementImpl( contextID, statement );\r
+        execute(() -> executePythonStatementImpl( contextID, statement ));\r
+       for (Listener l : listeners) { l.updated(null); }\r
     }\r
 \r
     // Setters\r
     \r
+    public void setPythonBooleanVariable(String variableName, boolean value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonBooleanVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+\r
     public void setPythonIntegerVariable(String variableName, int value) {\r
-        setPythonIntegerVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    public void setPythonLongVariable(String variableName, long value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonDoubleVariable(String variableName, double value) {\r
-        setPythonDoubleVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonDoubleVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonStringVariable(String variableName, String value) {\r
-        setPythonStringVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonStringVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     \r
+    public void setPythonBooleanArrayVariable(String variableName, boolean[] value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonBooleanArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
     public void setPythonIntegerArrayVariable(String variableName, int[] value) {\r
-        setPythonIntegerArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonIntegerArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    public void setPythonLongArrayVariable(String variableName, long[] value) {\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonLongArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonDoubleArrayVariable(String variableName, double[] value) {\r
-        setPythonDoubleArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonDoubleArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
     public void setPythonStringArrayVariable(String variableName, String[] value) {\r
-        setPythonStringArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonStringArrayVariableImpl(contextID, variableName, value));\r
+       for (Listener l : listeners) { l.updated(variableName); }\r
     }\r
 \r
     // Getters\r
     \r
+    public boolean getPythonBooleanVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return getPythonBooleanVariableImpl(contextID, variableName);\r
+    }\r
     public int getPythonIntegerVariable(String variableName) {\r
-        return getPythonIntegerVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+       long value = execute(() -> getPythonLongVariableImpl(contextID, variableName));\r
+       if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE)\r
+               throw new RuntimeException("Python value not in integer range");\r
+        return (int) value;\r
+    }\r
+    public long getPythonLongVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonLongVariableImpl(contextID, variableName));\r
     }\r
     public double getPythonDoubleVariable(String variableName) {\r
-        return getPythonDoubleVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonDoubleVariableImpl(contextID, variableName));\r
     }\r
     public String getPythonStringVariable(String variableName) {\r
-        return getPythonStringVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonStringVariableImpl(contextID, variableName));\r
     }\r
     \r
+    public boolean[] getPythonBooleanArrayVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonBooleanArrayVariableImpl(contextID, variableName));\r
+    }\r
     public int[] getPythonIntegerArrayVariable(String variableName) {\r
-        return getPythonIntegerArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonIntegerArrayVariableImpl(contextID, variableName));\r
+    }\r
+    public long[] getPythonLongArrayVariable(String variableName) {\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonLongArrayVariableImpl(contextID, variableName));\r
     }\r
     public double[] getPythonDoubleArrayVariable(String variableName) {\r
-        return getPythonDoubleArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonDoubleArrayVariableImpl(contextID, variableName));\r
     }\r
     public String[] getPythonStringArrayVariable(String variableName) {\r
-        return getPythonStringArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonStringArrayVariableImpl(contextID, variableName));\r
     }\r
     \r
     public void setPythonNDArrayVariable(String variableName, NDArray value) {\r
-        setPythonNDArrayVariableImpl(contextID, variableName, value);\r
+        checkValidName(variableName);\r
+        execute(() -> setPythonNDArrayVariableImpl(contextID, variableName, value));\r
     }\r
     public NDArray getPythonNDArrayVariable(String variableName) {\r
-        return getPythonNDArrayVariableImpl(contextID, variableName);\r
+        checkValidName(variableName);\r
+        return execute(() -> getPythonNDArrayVariableImpl(contextID, variableName));\r
     }\r
 \r
+    public Object getPythonVariantVariable(String variableName, Binding binding) {\r
+        checkValidName(variableName);\r
+       Object result = execute(() -> getPythonVariantVariableImpl(contextID, variableName));\r
+       try {\r
+                       return Bindings.OBJECT.getContent(result, binding);\r
+               } catch (BindingException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+    }\r
+    \r
+    public Variant getPythonVariantVariable(String variableName) {\r
+        checkValidName(variableName);\r
+       return Variant.ofInstance(execute(() -> getPythonVariantVariableImpl(contextID, variableName)));\r
+    }\r
+\r
+    public void setPythonVariantVariable(String variableName, Variant value) {\r
+       setPythonVariantVariable(variableName, value.getValue(), value.getBinding());\r
+    }\r
+    \r
+    public void setPythonVariantVariable(String variableName, Object value, Binding binding) {\r
+        checkValidName(variableName);\r
+        if (!binding.isInstance(value)) throw new IllegalArgumentException("Invalid object binding");\r
+        \r
+        execute(() -> setPythonVariantVariableImpl(contextID, variableName, value, binding));\r
+        \r
+       for (Listener l : listeners) { l.updated(variableName); }\r
+    }\r
+    \r
+    public VariableType getPythonVariableType(String variableName) {\r
+        checkValidName(variableName);\r
+       int code = execute(() -> getPythonVariableTypeImpl(contextID, variableName));\r
+       \r
+       VariableType[] values = VariableType.values();\r
+       if (code < 0 || code >= values.length)\r
+               return VariableType.UNKNOWN;\r
+       \r
+       return values[code];\r
+    }\r
+    \r
+    public String[] getPythonVariableNames() {\r
+       return execute(() -> getPythonVariableNamesImpl(contextID));\r
+    }\r
+     \r
+    private static void checkValidName(String variableName) {\r
+        if (!namePattern.matcher(variableName).matches())\r
+            throw new IllegalArgumentException("Invalid Python variable name " + variableName);\r
+    }\r
+    \r
+    static void execute(Runnable job) {\r
+        try {\r
+            pythonExecutor.submit(job).get();\r
+        } catch (InterruptedException | ExecutionException e) {\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+    \r
+    static <V> V execute(Callable<V> job) {\r
+        try {\r
+            return pythonExecutor.submit(job).get();\r
+        } catch (InterruptedException | ExecutionException e) {\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+    \r
     // Native function declarations\r
     private static native long createContextImpl();\r
     private static native void deleteContextImpl(long contextID);\r
     \r
     private static native int executePythonStatementImpl(long contextID, String statement);\r
     \r
-    private static native void setPythonIntegerVariableImpl(long contextID, String variableName, int value);\r
+    private static native void setPythonBooleanVariableImpl(long contextID, String variableName, boolean value);\r
+    private static native void setPythonLongVariableImpl(long contextID, String variableName, long 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 setPythonBooleanArrayVariableImpl(long contextID, String variableName, boolean[] value);\r
     private static native void setPythonIntegerArrayVariableImpl(long contextID, String variableName, int[] value);\r
+    private static native void setPythonLongArrayVariableImpl(long contextID, String variableName, long[] 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 boolean getPythonBooleanVariableImpl(long contextID, String variableName);\r
+    private static native long getPythonLongVariableImpl(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 boolean[] getPythonBooleanArrayVariableImpl(long contextID, String variableName);\r
+    private static native long[] getPythonLongArrayVariableImpl(long contextID, String variableName);\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
+    private static native void setPythonVariantVariableImpl(long contextID, String variableName, Object value, Binding binding);\r
+    private static native Object getPythonVariantVariableImpl(long contextID, String variableName);\r
+    \r
+    private static native int getPythonVariableTypeImpl(long contextID, String variableName);\r
+    \r
+    private static native String[] getPythonVariableNamesImpl(long contextID);\r
 }\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNode.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNode.java
new file mode 100644 (file)
index 0000000..c7e9df5
--- /dev/null
@@ -0,0 +1,14 @@
+package org.simantics.pythonlink.variable;\r
+\r
+public class PythonNode {\r
+    public PythonNode(String variableName) {\r
+        super();\r
+        this.variableName = variableName;\r
+    }\r
+    \r
+    private String variableName;\r
+    \r
+    public String getName() {\r
+        return variableName;\r
+    }\r
+}\r
diff --git a/org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNodeManager.java b/org.simantics.pythonlink/src/org/simantics/pythonlink/variable/PythonNodeManager.java
new file mode 100644 (file)
index 0000000..b88ebfa
--- /dev/null
@@ -0,0 +1,281 @@
+package org.simantics.pythonlink.variable;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.adapter.AdaptException;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.pythonlink.NDArray;\r
+import org.simantics.pythonlink.PythonContext;\r
+import org.simantics.pythonlink.PythonContext.Listener;\r
+import org.simantics.pythonlink.PythonContext.VariableType;\r
+import org.simantics.simulator.variable.Realm;\r
+import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
+import org.simantics.simulator.variable.impl.AbstractNodeManager;\r
+\r
+public class PythonNodeManager extends AbstractNodeManager<PythonNode> {\r
+    PythonContext context;\r
+    \r
+    static Realm realm = new Realm() {\r
+        public void asyncExec(Runnable runnable) {\r
+            runnable.run();\r
+        };\r
+        \r
+        public void syncExec(Runnable runnable) {\r
+            runnable.run();\r
+        };\r
+    };\r
+    \r
+    Map<String, Set<Runnable>> listeners = new HashMap<>();\r
+    Map<String, PythonNode> nodes = new HashMap<>();\r
+    \r
+    PythonNode root = new PythonNode("/");\r
+    \r
+    static Pattern namePattern = Pattern.compile("/?([a-zA-Z_][a-zA-Z_0-9]*)");\r
+    \r
+    static MapType dictionaryType = new MapType(Datatypes.VARIANT, Datatypes.VARIANT);\r
+    static RecordType ndarrayType = (RecordType)Bindings.getBindingUnchecked(NDArray.class).type();\r
+    \r
+    public PythonNodeManager(PythonContext context) {\r
+        super();\r
+        this.context = context;\r
+        \r
+        context.addListener(new Listener() {\r
+            @Override\r
+            public void updated(String variableName) {\r
+                if (variableName != null) {\r
+                    Set<Runnable> lis = listeners.get(variableName);\r
+                    if (lis != null) {\r
+                        for (Runnable r : lis)\r
+                            r.run();\r
+                    }\r
+                    lis = listeners.get("/");\r
+                    if (lis != null) {\r
+                        for (Runnable r : lis)\r
+                            r.run();\r
+                    }\r
+                }\r
+                else {\r
+                    Set<Runnable> allRunnables = new HashSet<>();\r
+                    for (Collection<Runnable> s : listeners.values())\r
+                        allRunnables.addAll(s);\r
+                    for (Runnable r : allRunnables)\r
+                        r.run();\r
+                }\r
+            }\r
+            \r
+            @Override\r
+            public void closed() {\r
+                nodes.clear();\r
+                Set<Runnable> allRunnables = new HashSet<>();\r
+                for (Collection<Runnable> s : listeners.values())\r
+                    allRunnables.addAll(s);\r
+                for (Runnable r : allRunnables)\r
+                    r.run();\r
+            }\r
+        });\r
+    }\r
+    \r
+    @Override\r
+    public Realm getRealm() {\r
+        return realm;\r
+    }\r
+\r
+    @Override\r
+    public String getName(PythonNode node) {\r
+        return node.getName();\r
+    }\r
+\r
+    @Override\r
+    public void addNodeListener(PythonNode node, Runnable listener) {\r
+        synchronized(listeners) {\r
+            if (!listeners.containsKey(node.getName())) listeners.put(node.getName(), new HashSet<>());\r
+            listeners.get(node.getName()).add(listener);\r
+        }        \r
+    }\r
+\r
+    @Override\r
+    public void removeNodeListener(PythonNode node, Runnable listener) {\r
+        synchronized(listeners) {\r
+            if (!listeners.containsKey(node.getName()))\r
+                listeners.get(node.getName()).remove(listener);\r
+        }        \r
+    }\r
+\r
+    @Override\r
+    public PythonNode getNode(String path) throws NodeManagerException {\r
+        if (!context.isOpen())\r
+            return null;\r
+        \r
+        if ("/".equals(path))\r
+            return root;        \r
+        \r
+        Matcher match = namePattern.matcher(path);\r
+        if (!match.matches())\r
+            return null;\r
+        \r
+        String name = match.group(1);\r
+        \r
+        if (nodes.containsKey(name))\r
+            return nodes.get(name);\r
+        \r
+        VariableType type = context.getPythonVariableType(name);\r
+        if (type == VariableType.NO_VARIABLE)\r
+            return null;\r
+        \r
+        PythonNode node = new PythonNode(name);\r
+        nodes.put(path, node);\r
+        \r
+        return node;\r
+    }\r
+\r
+    @Override\r
+    public PythonNode getChild(PythonNode node, String name) throws NodeManagerException {\r
+        return null;\r
+    }\r
+\r
+    @Override\r
+    public PythonNode getProperty(PythonNode node, String name) throws NodeManagerException {\r
+        if (node != root || !context.isOpen()) return null;\r
+        \r
+        return getNode(name);\r
+    }\r
+    \r
+    @Override\r
+    public List<String> getChildNames(PythonNode node) throws NodeManagerException {\r
+        return Collections.emptyList();\r
+    }\r
+\r
+    @Override\r
+    public List<PythonNode> getChildren(PythonNode node) throws NodeManagerException {\r
+        return Collections.emptyList();\r
+    }\r
+    \r
+    @Override\r
+    public List<String> getPropertyNames(PythonNode node) throws NodeManagerException {\r
+        if (node != root || !context.isOpen()) return Collections.emptyList();        \r
+        return Arrays.asList(context.getPythonVariableNames());\r
+    }\r
+\r
+    @Override\r
+    public List<PythonNode> getProperties(PythonNode node) throws NodeManagerException {\r
+        if (node != root || !context.isOpen()) return Collections.emptyList();\r
+        \r
+        String[] names = context.getPythonVariableNames();\r
+        List<PythonNode> result = new ArrayList<>(names.length);\r
+        \r
+        for (String name : names) {\r
+            result.add(getNode(name));\r
+        }\r
+        \r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public Datatype getDatatype(PythonNode node) throws NodeManagerException {\r
+        String name = node.getName();\r
+        VariableType type;\r
+        try {\r
+            type = context.getPythonVariableType(name);\r
+        } catch (RuntimeException e) {\r
+            throw new NodeManagerException("Failed to get type of variable " + name, e);            \r
+        }\r
+        \r
+        switch (type) {\r
+        case NO_VARIABLE: return Datatypes.VOID;\r
+        case BOOLEAN: return Datatypes.BOOLEAN;\r
+        case LONG: return Datatypes.LONG;\r
+        case FLOAT: return Datatypes.DOUBLE;\r
+        case STRING: return Datatypes.STRING;\r
+        case BYTEARRAY: return Datatypes.BYTE_ARRAY;\r
+        case DICTIONARY: return dictionaryType;\r
+        case NDARRAY: return ndarrayType;\r
+        case SEQUENCE: return Datatypes.VARIANT_ARRAY;\r
+        case UNKNOWN: return Datatypes.VOID;\r
+        default: throw new RuntimeException("Unknown python variable type");\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public Variant getValue(PythonNode node, String propertyName) throws NodeManagerException {\r
+        if (node == root && context.isOpen())\r
+            return context.getPythonVariantVariable(propertyName);\r
+        \r
+        throw new NodeManagerException("No value available for " + node.getName() + "#" + propertyName);\r
+    }\r
+\r
+    @Override\r
+    public Object getValue(PythonNode node, String propertyName, Binding binding)\r
+            throws NodeManagerException, BindingException {\r
+        Variant value = getValue(node, propertyName);\r
+        \r
+        try {\r
+            return value.getValue(binding);\r
+        } catch (AdaptException e) {\r
+            throw new BindingException(e);\r
+        }\r
+    }\r
+        \r
+    @Override\r
+    public Variant getValue(PythonNode node) throws NodeManagerException {\r
+        if (node == root || !context.isOpen())\r
+            throw new NodeManagerException("No value available for " + node.getName());\r
+        \r
+        String name = node.getName();\r
+        \r
+        try {\r
+            return context.getPythonVariantVariable(name);\r
+        } catch (RuntimeException e) {\r
+            throw new NodeManagerException("Failed to get value of variable " + name, e);\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    public Object getValue(PythonNode node, Binding binding) throws NodeManagerException, BindingException {\r
+        Variant value = getValue(node);\r
+        \r
+        try {\r
+            return value.getValue(binding);\r
+        } catch (AdaptException e) {\r
+            throw new BindingException(e);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void setValue(PythonNode node, String propertyName, Object value, Binding binding)\r
+            throws NodeManagerException, BindingException {\r
+        if (node != root || !context.isOpen()) throw new NodeManagerException("No property " + node.getName() + "#" + propertyName);\r
+        \r
+        context.setPythonVariantVariable(propertyName, value, binding);        \r
+    }\r
+    \r
+    @Override\r
+    public void setValue(PythonNode node, Object value, Binding binding) throws NodeManagerException, BindingException {        \r
+        if (node == root || !context.isOpen()) throw new NodeManagerException("No property " + node.getName());\r
+        String name = node.getName();\r
+        \r
+        context.setPythonVariantVariable(name, value, binding);\r
+    }\r
+    \r
+    @Override\r
+    public Set<String> getClassifications(PythonNode node) throws NodeManagerException {\r
+        return Collections.emptySet();\r
+    }\r
+    \r
+}\r
index 3d9bbb26882e43da5712d04a3c2a2dc7a8bdc568..8778150ac4adcc685fc0303270a26f2fe0d8a226 100644 (file)
@@ -5,7 +5,7 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;\r
 \r
 @RunWith( Suite.class )\r
-@SuiteClasses( { ScriptTests.class, TestPythonlink.class } )\r
+@SuiteClasses( { ScriptTests.class, TestPythonlink.class, TestPythonVariable.class } )\r
 public class AllTests {\r
 \r
 }\r
index 6a8bdae4fce3bcd777de556191c8528681a73260..22f81fe2673f0d64078c081d4040d8f258480cb6 100644 (file)
@@ -1,12 +1,37 @@
 package org.simantics.pythonlink.test;
 
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.simantics.PlatformException;
+import org.simantics.Simantics;
+import org.simantics.application.arguments.Arguments;
+import org.simantics.pythonlink.PythonContext;
 
 public class ScriptTests extends ScriptTestBase {
+    static IProgressMonitor progress = new NullProgressMonitor();
     
+    PythonContext python;
+
+    @BeforeClass
+    public static void SetUpClass() throws PlatformException {
+        Simantics.startUpHeadless(Arguments.parse(new String[] {}), progress);
+    }
+
+    @AfterClass
+    public static void TearDownClass() throws PlatformException {
+        Simantics.shutdown(progress);
+    }
+
     public ScriptTests() {
         super("scripts");
     }
 
     @Test public void Python() throws Exception { test(); }
+    @Test public void Matplotlib() throws Exception { test(); }
+    @Test public void NDArray() throws Exception { test(); }
+    @Test public void Variant() throws Exception { test(); }
+    @Test public void Variable() throws Exception { test(); }
 }
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonVariable.java b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/TestPythonVariable.java
new file mode 100644 (file)
index 0000000..56ff8e8
--- /dev/null
@@ -0,0 +1,139 @@
+package org.simantics.pythonlink.test;\r
+\r
+import static org.junit.Assert.assertArrayEquals;\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertNotNull;\r
+import static org.junit.Assert.assertTrue;\r
+\r
+import java.util.Map;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.junit.After;\r
+import org.junit.AfterClass;\r
+import org.junit.Before;\r
+import org.junit.BeforeClass;\r
+import org.junit.Test;\r
+import org.simantics.PlatformException;\r
+import org.simantics.Simantics;\r
+import org.simantics.application.arguments.Arguments;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.Datatypes;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.pythonlink.Python;\r
+import org.simantics.pythonlink.PythonContext;\r
+\r
+public class TestPythonVariable {\r
+    static IProgressMonitor progress = new NullProgressMonitor();\r
+    \r
+    PythonContext python;\r
+\r
+    @BeforeClass\r
+    public static void SetUpClass() throws PlatformException {\r
+        Simantics.startUpHeadless(Arguments.parse(new String[] {}), progress);        \r
+    }\r
+    \r
+    @AfterClass\r
+    public static void TearDownClass() throws PlatformException {\r
+        Simantics.shutdown(progress);        \r
+    }\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 test() throws DatabaseException {\r
+        Simantics.getSession().syncRequest(new Read<Void>() {\r
+            @Override\r
+            public Void perform(ReadGraph graph) throws DatabaseException {\r
+                python.setPythonDoubleArrayVariable("foo", new double[] { 1, 2, 3 });\r
+                \r
+                Variable var = Python.getPythonContextVariable(python);\r
+                \r
+                Object value = var.getPossiblePropertyValue(graph, "foo");\r
+                \r
+                assertNotNull(value);\r
+                assertTrue(value instanceof Object[]);\r
+                assertArrayEquals(new Object[] {1.0, 2.0, 3.0}, (Object[])value);\r
+                \r
+                return null;\r
+            }\r
+        });\r
+    }\r
+    \r
+    @Test\r
+    public void test2() throws DatabaseException {\r
+        Simantics.getSession().syncRequest(new Read<Void>() {\r
+            @Override\r
+            public Void perform(ReadGraph graph) throws DatabaseException {\r
+                python.setPythonDoubleArrayVariable("foo", new double[] { 1, 2, 3 });\r
+                \r
+                Variable var = Python.getPythonContextVariable(python);\r
+                \r
+                Object value = var.getPossiblePropertyValue(graph, "foo", Bindings.DOUBLE_ARRAY);\r
+                \r
+                assertNotNull(value);\r
+                assertTrue(value instanceof double[]);\r
+                assertArrayEquals(new double[] {1.0, 2.0, 3.0}, (double[])value, 0.0);\r
+                \r
+                return null;\r
+            }\r
+        });\r
+    }\r
+    \r
+    @Test\r
+    public void test3() throws DatabaseException {\r
+        Simantics.getSession().syncRequest(new Read<Void>() {\r
+            @Override\r
+            public Void perform(ReadGraph graph) throws DatabaseException {\r
+                python.executePythonStatement("foo = (1, 2, 3)");\r
+                \r
+                Variable var = Python.getPythonContextVariable(python);\r
+                Variable foo = var.browse(graph, "#foo");\r
+        \r
+                Object value = foo.getPossibleValue(graph, Bindings.LONG_ARRAY);\r
+                \r
+                assertNotNull(value);\r
+                assertTrue(value instanceof long[]);\r
+                assertArrayEquals(new long[] {1,2,3}, (long[])value);\r
+                \r
+                return null;\r
+            }\r
+        });\r
+    }\r
+    \r
+    @Test\r
+    public void test4() throws DatabaseException {\r
+        Simantics.getSession().syncRequest(new Read<Void>() {\r
+            @Override\r
+            public Void perform(ReadGraph graph) throws DatabaseException {\r
+                python.executePythonStatement("foo = {1:'foo', 2:'bar'}");\r
+                \r
+                Variable var = Python.getPythonContextVariable(python);\r
+                Variable foo = var.getPossibleProperty(graph, "foo");\r
+                \r
+                Object value = foo.getPossibleValue(graph, Bindings.getBinding(new MapType(Datatypes.LONG, Datatypes.STRING)));\r
+                \r
+                assertNotNull(value);\r
+                assertTrue(value instanceof Map<?,?>);\r
+                assertEquals(2, ((Map<?,?>)value).size());\r
+                assertEquals("foo", ((Map<?,?>)value).get(1L));\r
+                assertEquals("bar", ((Map<?,?>)value).get(2L));\r
+                \r
+                return null;\r
+            }\r
+        });\r
+    }\r
+    \r
+}\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Matplotlib.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Matplotlib.sts
new file mode 100644 (file)
index 0000000..ecff4df
--- /dev/null
@@ -0,0 +1,28 @@
+> import "Python"\r
+> \r
+> code = """\r
+> import matplotlib\r
+> import matplotlib.pyplot as plt\r
+> import numpy as np\r
+> import io\r
+> \r
+> x, y = np.random.randn(2, 100)\r
+> fig = plt.figure()\r
+> ax1 = fig.add_subplot(211)\r
+> ax1.xcorr(x, y, usevlines=True, maxlags=50, normed=True, lw=2)\r
+> ax1.grid(True)\r
+> ax1.axhline(0, color='black', lw=2)\r
+> \r
+> ax2 = fig.add_subplot(212, sharex=ax1)\r
+> ax2.acorr(x, usevlines=True, normed=True, maxlags=50, lw=2)\r
+> ax2.grid(True)\r
+> ax2.axhline(0, color='black', lw=2)\r
+> \r
+> imgdata = io.StringIO()\r
+> fig.savefig(imgdata, format='svg')\r
+> svg_data = imgdata.getvalue()[0:5]\r
+> """\r
+> runPython do\r
+>     executePythonStatement code\r
+>     getPythonStringVariable "svg_data"\r
+"<?xml"\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/NDArray.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/NDArray.sts
new file mode 100644 (file)
index 0000000..84d0ac2
--- /dev/null
@@ -0,0 +1,24 @@
+> import "Python"\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, 11.0, 12.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
+> b = ndarrayFromList ([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]] :: [[[Double]]])\r
+> b\r
+ndarray(2x2x3) [[[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
+> 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
index 50c0423ab0763d465e15c965070179d3773221b0..83b221219291a2c81dea4dc1c4f6986b58b36f88 100644 (file)
@@ -5,6 +5,9 @@
 >     getPythonStringArrayVariable "d"\r
 vector ["__builtins__", "__doc__", "__loader__", "__name__", "__package__", "__spec__", "foo"]\r
 > runPython do\r
+>     getPythonStringVariable "__name__"\r
+"SCL_2"\r
+> runPython do\r
 >     setPythonDoubleVariable "foo" 1\r
 >     executePythonStatement "foo = foo + 1"\r
 >     getPythonDoubleVariable "foo"\r
@@ -25,28 +28,21 @@ vector [1.0, 2.0, 3.0, 4.0]
 >     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, 11.0, 12.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
+> runPython do\r
+>     setPythonBooleanVariable "foo" False\r
+>     executePythonStatement "foo = not(foo)"\r
+>     getPythonBooleanVariable "foo"\r
+True\r
 > runPython do\r
 >     setPythonVariable "foo" ([1.0, 2.0, 3.0, 4.0] :: [Double])\r
 >     executePythonStatement "foo.append(sum(foo))"\r
 >     getPythonVariable "foo" :: [Double]\r
 [1.0, 2.0, 3.0, 4.0, 10.0]\r
+> py = openPythonContext\r
+> runWithPythonContext py $ setPythonIntegerVariable "foo" 4\r
+> runWithPythonContext py $ setPythonDoubleArrayVariable "bar" (vector [1.0, 2.0, 3.0])\r
+> runWithPythonContext py $ executePythonStatement "bar.append(float(foo))"\r
+> bar = runWithPythonContext py $ getPythonDoubleArrayVariable "bar"\r
+> closePythonContext py\r
+> bar\r
+vector [1.0, 2.0, 3.0, 4.0]\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variable.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variable.sts
new file mode 100644 (file)
index 0000000..a735dde
--- /dev/null
@@ -0,0 +1,35 @@
+> import "PythonVariable"\r
+> import "Simantics/DB"\r
+> import "String"\r
+> \r
+> py = openPythonContext\r
+> runWithPythonContext py do\r
+>     setPythonIntegerVariable "foo" 4\r
+>     setPythonDoubleArrayVariable "bar" (vector [1.0, 2.0, 3.0])\r
+> \r
+> var = getPythonContextVariable py\r
+> sort $ map nameOf $ properties var\r
+["__builtins__", "__doc__", "__loader__", "__name__", "__package__", "__spec__", "bar", "foo"]\r
+> foo = property var "foo"\r
+> bar = property var "bar" \r
+> datatype foo\r
+Long\r
+> datatype bar\r
+Variant[]\r
+> value bar :: Variant\r
+[1.0 : Double, 2.0 : Double, 3.0 : Double] : Variant[]\r
+> value bar :: [Double]\r
+[1.0, 2.0, 3.0]\r
+> possibleChild var "foo"\r
+Nothing\r
+> possibleProperty var "dummy"\r
+Nothing \r
+> runWithPythonContext py do\r
+>     executePythonStatement "baz = (1.0, 'string_value', [2.0, 3.0])"\r
+> sort $ map nameOf $ properties var\r
+["__builtins__", "__doc__", "__loader__", "__name__", "__package__", "__spec__", "bar", "baz", "foo"]\r
+> v = propertyValue var "baz" :: Variant\r
+> v\r
+[1.0 : Double, "string_value" : String, [2.0 : Double, 3.0 : Double] : Variant[]] : Variant[]\r
+> variantElement v 1 :: String\r
+"string_value"\r
diff --git a/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variant.sts b/org.simantics.pythonlink/test/org/simantics/pythonlink/test/scripts/Variant.sts
new file mode 100644 (file)
index 0000000..745b3c3
--- /dev/null
@@ -0,0 +1,22 @@
+> import "Python"\r
+> a = variant ([1.0, 2.0, 3.0])\r
+> b = runPython do\r
+>     setPythonVariantVariable "foo" a\r
+>     executePythonStatement "foo.append(4.0)"\r
+>     getPythonVariantVariable "foo"\r
+> b\r
+[1.0 : Double, 2.0 : Double, 3.0 : Double, 4.0 : Double] : Variant[]\r
+> variantValue b :: [Double]\r
+[1.0, 2.0, 3.0, 4.0]\r
+> import "MMap" as MMap\r
+> runPython do\r
+>     foo = MMap.create () :: MMap.T String Dynamic\r
+>     MMap.put foo "c1" (toDynamic (vector [True, True, False, True]))\r
+>     MMap.put foo "c2" (toDynamic ["foo", "bar", "baz"])\r
+>     MMap.put foo "c3" (toDynamic 25.0)\r
+>     setPythonVariantVariable "foo" (variant foo)\r
+>     executePythonStatement "c1 = foo['c1']"\r
+>     executePythonStatement "c2 = foo['c2']"\r
+>     executePythonStatement "c3 = foo['c3']"\r
+>     (getPythonBooleanArrayVariable "c1", getPythonStringArrayVariable "c2", getPythonDoubleVariable "c3")\r
+(vector [True, True, False, True], vector ["foo", "bar", "baz"], 25.0)\r