]> gerrit.simantics Code Review - simantics/python.git/blobdiff - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Added support for dynamically typed data access and a Variable interface.
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
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