X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.pythonlink.win32.x86_64%2Fsrc%2Fsclpy.c;h=b10b36f5d3c1103aeda3c6e7582ff44bdb6670b5;hb=c09eb1d21fa19556b14301ca70b622b8a2e1d080;hp=4f5da9b5d5fb2daf5a53c9cc7cb884295ae0e273;hpb=7a0336fbf77a80fb8ca53dc9df3e76985c7b2860;p=simantics%2Fpython.git diff --git a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c index 4f5da9b..b10b36f 100644 --- a/org.simantics.pythonlink.win32.x86_64/src/sclpy.c +++ b/org.simantics.pythonlink.win32.x86_64/src/sclpy.c @@ -10,33 +10,10 @@ // // /////////////////////////////////////////////////////// -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#ifdef _DEBUG - #undef _DEBUG - #include //header for system python import; add include paths - #include - #define _DEBUG 1 -#else - #include //header for system python import; add include paths - #include -#endif - #include "sclpy.h" -#include //java connection header - #include -#define JAVA_MAXINT (0x7fffffff) - -#define RUNTIME_EXCEPTION "java/lang/RuntimeException" -#define ILLEGAL_ARGUMENT_EXCEPTION "java/lang/IllegalArgumentException" -#define STRING_CLASS "java/lang/String" - -#define PACKAGE_PREFIX "org/simantics/pythonlink/" - -#define NDARRAY_CLASS (PACKAGE_PREFIX "NDArray") - jint throwException( JNIEnv *env, char *className, char *message ) { jclass exClass = (*env)->FindClass( env, className); @@ -47,14 +24,29 @@ jint throwException( JNIEnv *env, char *className, char *message ) return (*env)->ThrowNew( env, exClass, message ); } +jint throwPythonException( JNIEnv *env, char *message ) { + return throwException( env, PYTHON_EXCEPTION, message ); +} + jint throwIllegalArgumentException( JNIEnv *env, char *message ) { return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message ); } int moduleCount = 0; +int initCalled = 0; +int hasNumpy = 0; JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContextImpl(JNIEnv *env, jobject thisObj) { char name[16]; + + if (!initCalled) { + Py_Initialize(); + initCalled = 1; + + hasNumpy = _import_array(); + hasNumpy = hasNumpy != -1; + } + sprintf(name, "SCL_%d", ++moduleCount); { @@ -62,6 +54,7 @@ JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_createContex PyObject *main = PyImport_AddModule("__main__"); PyDict_Merge(PyModule_GetDict(module), PyModule_GetDict(main), 0); + return (jlong)module; } } @@ -71,6 +64,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContext Py_XDECREF(module); } +PyObject *getPythonBool(jboolean value) { + if (value) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + PyObject *getPythonString(JNIEnv *env, jstring string) { jsize len = (*env)->GetStringLength(env, string); const jchar *chars = (*env)->GetStringChars(env, string, NULL); @@ -102,6 +104,30 @@ PyObject *getPythonStringList(JNIEnv *env, jobjectArray value) { return result; } +PyObject *getPythonBooleanList(JNIEnv *env, jbooleanArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jboolean *values = (*env)->GetBooleanArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, getPythonBool(values[i])); + } + + (*env)->ReleaseBooleanArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonByteArray(JNIEnv *env, jbyteArray value) { + jint len = (*env)->GetArrayLength(env, value); + jbyte *values = (*env)->GetByteArrayElements(env, value, NULL); + + PyObject *result = PyByteArray_FromStringAndSize(values, len); + + (*env)->ReleaseByteArrayElements(env, value, values, JNI_ABORT); + return result; +} + PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) { jsize nitems = (*env)->GetArrayLength(env, value); jint *values = (*env)->GetIntArrayElements(env, value, NULL); @@ -116,6 +142,34 @@ PyObject *getPythonIntegerList(JNIEnv *env, jintArray value) { return result; } +PyObject *getPythonLongList(JNIEnv *env, jlongArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + jlong *values = (*env)->GetLongArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyLong_FromLongLong(values[i])); + } + + (*env)->ReleaseLongArrayElements(env, value, values, JNI_ABORT); + return result; +} + +PyObject *getPythonFloatList(JNIEnv *env, jfloatArray value) { + jsize nitems = (*env)->GetArrayLength(env, value); + float *values = (*env)->GetFloatArrayElements(env, value, NULL); + jint i; + + PyObject *result = PyList_New(nitems); + for (i = 0; i < nitems; i++) { + PyList_SetItem(result, i, PyFloat_FromDouble((double)values[i])); + } + + (*env)->ReleaseFloatArrayElements(env, value, values, JNI_ABORT); + return result; +} + PyObject *getPythonDoubleList(JNIEnv *env, jdoubleArray value) { jsize nitems = (*env)->GetArrayLength(env, value); double *values = (*env)->GetDoubleArrayElements(env, value, NULL); @@ -168,6 +222,277 @@ PyObject *getPythonNDArray(JNIEnv *env, jobject value) { } } +PyObject *getPythonBooleanObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, BOOLEANBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)Z"); + + jboolean bvalue = (*env)->CallBooleanMethod(env, binding, getValueMethod, object); + return getPythonBool(bvalue); +} + +PyObject *getPythonByteObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, BYTEBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)B"); + + jbyte v = (*env)->CallByteMethod(env, binding, getValueMethod, object); + return PyLong_FromLong(v); +} + +PyObject *getPythonIntegerObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, INTEGERBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)I"); + + jint v = (*env)->CallIntMethod(env, binding, getValueMethod, object); + return PyLong_FromLong(v); +} + +PyObject *getPythonLongObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, LONGBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)J"); + + jlong v = (*env)->CallLongMethod(env, binding, getValueMethod, object); + return PyLong_FromLongLong(v); +} + +PyObject *getPythonFloatObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, FLOATBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)F"); + + jfloat v = (*env)->CallFloatMethod(env, binding, getValueMethod, object); + return PyFloat_FromDouble(v); +} + +PyObject *getPythonDoubleObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, DOUBLEBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue_", "(L" OBJECT_CLASS ";)D"); + + jdouble v = (*env)->CallDoubleMethod(env, binding, getValueMethod, object); + return PyFloat_FromDouble(v); +} + +PyObject *getPythonStringObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, STRINGBINDING_CLASS); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" STRING_CLASS ";"); + + jobject string = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + jsize len = (*env)->GetStringLength(env, string); + const jchar *chars = (*env)->GetStringChars(env, string, NULL); + + PyObject *value = PyUnicode_DecodeUTF16((char*)chars, 2*len, NULL, NULL); + + (*env)->ReleaseStringChars(env, string, chars); + return value; +} + +PyObject *getPythonRecordObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, RECORDBINDING_CLASS); + jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); + jmethodID getComponent = (*env)->GetMethodID(env, bindingClass, "getComponent", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); + jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); + + jclass recordType = (*env)->FindClass(env, RECORDTYPE_CLASS); + jmethodID getTypeComponent = (*env)->GetMethodID(env, recordType, "getComponent", "(I)L" COMPONENT_CLASS ";"); + jmethodID getComponentCount = (*env)->GetMethodID(env, recordType, "getComponentCount", "()I"); + + jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); + jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); + + jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); + jint n = (*env)->CallIntMethod(env, type, getComponentCount); + jint i; + + PyObject *result = PyDict_New(); + for (i = 0; i < n; i++) { + jobject recordTypeComponent = (*env)->CallObjectMethod(env, type, getComponent, i); + jstring fieldName = (jstring)(*env)->GetObjectField(env, recordTypeComponent, nameField); + jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i); + jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i); + + PyObject *item = getPythonObject(env, componentObject, componentBinding); + PyDict_SetItem(result, getPythonString(env, fieldName), item); + } + + return result; +} + +PyObject *getPythonArrayObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, ARRAYBINDING_CLASS); + jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); + jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); + jmethodID getMethod = (*env)->GetMethodID(env, bindingClass, "get", "(L" OBJECT_CLASS ";I)L" OBJECT_CLASS ";"); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); + + jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); + + PyObject *result = PyList_New(size); + + jint i; + for (i = 0; i < size; i++) { + jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i); + if (item != NULL) + PyList_SetItem(result, i, getPythonObject(env, item, componentBinding)); + else + PyList_SetItem(result, i, Py_None); + } + + return result; +} + +PyObject *getPythonMapObject(JNIEnv *env, jobject object, jobject binding) { + jclass objectClass = (*env)->FindClass(env, OBJECT_CLASS); + jclass bindingClass = (*env)->FindClass(env, MAPBINDING_CLASS); + jmethodID getKeyBindingMethod = (*env)->GetMethodID(env, bindingClass, "getKeyBinding", "()L" BINDING_CLASS ";"); + jmethodID getValueBindingMethod = (*env)->GetMethodID(env, bindingClass, "getValueBinding", "()L" BINDING_CLASS ";"); + jmethodID sizeMethod = (*env)->GetMethodID(env, bindingClass, "size", "(L" OBJECT_CLASS ";)I"); + jmethodID getAllMethod = (*env)->GetMethodID(env, bindingClass, "getAll", "(L" OBJECT_CLASS ";[L" OBJECT_CLASS ";[L" OBJECT_CLASS ";)V"); + + jobject keyBinding = (*env)->CallObjectMethod(env, binding, getKeyBindingMethod); + jobject valueBinding = (*env)->CallObjectMethod(env, binding, getValueBindingMethod); + + jint size = (*env)->CallIntMethod(env, binding, sizeMethod, object); + jobjectArray keys = (*env)->NewObjectArray(env, size, objectClass, NULL); + jobjectArray values = (*env)->NewObjectArray(env, size, objectClass, NULL); + + PyObject *result = PyDict_New(); + jint i; + + (*env)->CallVoidMethod(env, binding, getAllMethod, object, keys, values); + + for (i = 0; i < size; i++) { + jobject key = (*env)->GetObjectArrayElement(env, keys, i); + jobject item = (*env)->GetObjectArrayElement(env, values, i); + PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding)); + } + + (*env)->DeleteLocalRef(env, keys); + (*env)->DeleteLocalRef(env, values); + + return result; +} + +PyObject *getPythonOptionalObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, OPTIONALBINDING_CLASS); + jmethodID hasValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)Z"); + + jboolean hasValue = (*env)->CallBooleanMethod(env, binding, hasValueMethod, object); + + if (hasValue) { + jmethodID componentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "()L" BINDING_CLASS ";"); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "hasValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, componentBindingMethod); + jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + + return getPythonObject(env, value, componentBinding); + } + else { + return Py_None; + } +} + +PyObject *getPythonUnionObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, UNIONBINDING_CLASS); + jmethodID typeMethod = (*env)->GetMethodID(env, bindingClass, "type", "()L" RECORDTYPE_CLASS ";"); + jmethodID getTagMethod = (*env)->GetMethodID(env, bindingClass, "getTag", "(L" OBJECT_CLASS ";)I"); + jmethodID getValueMethod = (*env)->GetMethodID(env, bindingClass, "getValue", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + jmethodID getComponentBinding = (*env)->GetMethodID(env, bindingClass, "getComponentBinding", "(I)L" BINDING_CLASS ";"); + + jclass unionType = (*env)->FindClass(env, UNIONTYPE_CLASS); + jmethodID getTypeComponent = (*env)->GetMethodID(env, unionType, "getComponent", "(I)L" COMPONENT_CLASS ";"); + + jclass componentClass = (*env)->FindClass(env, COMPONENT_CLASS); + jfieldID nameField = (*env)->GetFieldID(env, componentClass, "name", "L" STRING_CLASS ";"); + + jint tag = (*env)->CallIntMethod(env, binding, getTagMethod, object); + jobject value = (*env)->CallObjectMethod(env, binding, getValueMethod, object); + + jobject type = (*env)->CallObjectMethod(env, binding, typeMethod); + jobject typeComponent = (*env)->CallObjectMethod(env, type, getTypeComponent, tag); + jstring compName = (*env)->GetObjectField(env, typeComponent, nameField); + + jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, tag); + + PyObject *result = PyTuple_New(2); + PyTuple_SetItem(result, 0, getPythonString(env, compName)); + PyTuple_SetItem(result, 1, getPythonObject(env, value, componentBinding)); + + return result; +} + +PyObject *getPythonVariantObject(JNIEnv *env, jobject object, jobject binding) { + jclass bindingClass = (*env)->FindClass(env, VARIANTBINDING_CLASS); + jmethodID getContentMethod = (*env)->GetMethodID(env, bindingClass, "getContent", "(L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); + jmethodID getContentBindingMethod = (*env)->GetMethodID(env, bindingClass, "getContentBinding", "(L" OBJECT_CLASS ";)L" BINDING_CLASS ";"); + + jobject content = (*env)->CallObjectMethod(env, binding, getContentMethod, object); + jobject contentBinding = (*env)->CallObjectMethod(env, binding, getContentBindingMethod, object); + + return getPythonObject(env, content, contentBinding); +} + +PyObject *getPythonObject(JNIEnv *env, jobject value, jobject binding) { + jclass booleanBinding = (*env)->FindClass(env, BOOLEANBINDING_CLASS); + jclass byteBinding = (*env)->FindClass(env, BYTEBINDING_CLASS); + jclass integerBinding = (*env)->FindClass(env, INTEGERBINDING_CLASS); + jclass longBinding = (*env)->FindClass(env, LONGBINDING_CLASS); + jclass floatBinding = (*env)->FindClass(env, FLOATBINDING_CLASS); + jclass doubleBinding = (*env)->FindClass(env, DOUBLEBINDING_CLASS); + jclass stringBinding = (*env)->FindClass(env, STRINGBINDING_CLASS); + jclass recordBinding = (*env)->FindClass(env, RECORDBINDING_CLASS); + jclass arrayBinding = (*env)->FindClass(env, ARRAYBINDING_CLASS); + jclass mapBinding = (*env)->FindClass(env, MAPBINDING_CLASS); + jclass optionalBinding = (*env)->FindClass(env, OPTIONALBINDING_CLASS); + jclass untionBinding = (*env)->FindClass(env, UNIONBINDING_CLASS); + jclass variantBinding = (*env)->FindClass(env, VARIANTBINDING_CLASS); + + if (value == NULL) + return Py_None; + + if ((*env)->IsInstanceOf(env, binding, booleanBinding)) { + return getPythonBooleanObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, byteBinding)) { + return getPythonByteObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, integerBinding)) { + return getPythonIntegerObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, longBinding)) { + return getPythonLongObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, floatBinding)) { + return getPythonFloatObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, doubleBinding)) { + return getPythonDoubleObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, stringBinding)) { + return getPythonStringObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, recordBinding)) { + return getPythonRecordObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, arrayBinding)) { + return getPythonArrayObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, mapBinding)) { + return getPythonMapObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, optionalBinding)) { + return getPythonOptionalObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, untionBinding)) { + return getPythonUnionObject(env, value, binding); + } + else if ((*env)->IsInstanceOf(env, binding, variantBinding)) { + return getPythonVariantObject(env, value, binding); + } + else { + return Py_None; + } +} + void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) { if (name && value) { PyDict_SetItem(PyModule_GetDict(module), name, value); @@ -177,6 +502,62 @@ void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) { Py_XDECREF(value); } +static npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { + if (d == nd) { + ncont[d] = 1; + return 1; + } + else { + npy_intp n = nContiguous(d+1, nd, strides, dims, ncont); + ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0; + return ncont[d]; + } +} + +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) { + if (ncont[d] > 0) { + (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data); + *offset += ncont[d]; + } + else { + int i; + for (i = 0; i < dims[d]; i++) { + copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont); + } + } +} + +jobject pythonBoolAsBooleanObject(JNIEnv *env, PyObject *value) { + jclass booleanClass = (*env)->FindClass(env, "java/lang/Boolean"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;"); + + return (*env)->CallStaticObjectMethod(env, booleanClass, valueOfMethod, (jboolean)(value == Py_True)); +} + +jobject pythonLongAsLongObject(JNIEnv *env, PyObject *value) { + jclass longClass = (*env)->FindClass(env, "java/lang/Long"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, longClass, "valueOf", "(J)Ljava/lang/Long;"); + + return (*env)->CallStaticObjectMethod(env, longClass, valueOfMethod, PyLong_AsLongLong(value)); +} + +jobject pythonFloatAsDoubleObject(JNIEnv *env, PyObject *value) { + jclass doubleClass = (*env)->FindClass(env, "java/lang/Double"); + jmethodID valueOfMethod = (*env)->GetStaticMethodID(env, doubleClass, "valueOf", "(D)Ljava/lang/Double;"); + + return (*env)->CallStaticObjectMethod(env, doubleClass, valueOfMethod, PyFloat_AsDouble(value)); +} + +jobject pythonByteArrayAsByteArray(JNIEnv *env, PyObject *value) { + Py_ssize_t size = PyByteArray_Size(value); + jbyteArray result = (*env)->NewByteArray(env, (jsize)size); + char *bytes = PyByteArray_AsString(value); + + (*env)->SetByteArrayRegion(env, result, 0, size, bytes); + + return result; +} + jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) { PyObject *utf16Value = PyUnicode_AsUTF16String(string); Py_ssize_t len = PyBytes_Size(utf16Value) / 2; @@ -190,21 +571,21 @@ jstring pythonStringAsJavaString(JNIEnv *env, PyObject *string) { return result; } -jobjectArray pythonStringListAsJavaArray(JNIEnv *env, PyObject *list) { - Py_ssize_t len = PyList_Size(list); +jobjectArray pythonSequenceAsStringArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); jsize jlen = (jsize)min(len, JAVA_MAXINT); jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, STRING_CLASS), NULL); jint i; for (i = 0; i < jlen; i++) { - PyObject *item = PyList_GetItem(list, i); + PyObject *item = PySequence_GetItem(seq, i); if (PyUnicode_Check(item)) { jstring value = pythonStringAsJavaString(env, item); (*env)->SetObjectArrayElement(env, array, i, value); } else { - throwException(env, RUNTIME_EXCEPTION, "List item not a string"); + throwPythonException(env, "List item not a string"); return NULL; } } @@ -212,21 +593,21 @@ jobjectArray pythonStringListAsJavaArray(JNIEnv *env, PyObject *list) { return array; } -jdoubleArray pythonListAsDoubleArray(JNIEnv *env, PyObject *list) { - Py_ssize_t len = PyList_Size(list); +jdoubleArray pythonSequenceAsDoubleArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); jsize jlen = (jsize)min(len, JAVA_MAXINT); jdoubleArray array = (*env)->NewDoubleArray(env, jlen); jint i; for (i = 0; i < jlen; i++) { - PyObject *item = PyList_GetItem(list, i); + PyObject *item = PySequence_GetItem(seq, i); if (PyFloat_Check(item)) { double value = PyFloat_AsDouble(item); (*env)->SetDoubleArrayRegion(env, array, i, 1, &value); } else { - throwException(env, RUNTIME_EXCEPTION, "List item not a floating point value"); + throwPythonException(env, "List item not a floating point value"); return NULL; } } @@ -234,29 +615,107 @@ jdoubleArray pythonListAsDoubleArray(JNIEnv *env, PyObject *list) { return array; } -npy_intp nContiguous(int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { - if (d == nd) { - ncont[d] = 1; - return 1; +jobject pythonObjectAsObject(JNIEnv *env, PyObject *value) { + if (PyBool_Check(value)) + return pythonBoolAsBooleanObject(env, value); + else if (PyLong_Check(value)) + return pythonLongAsLongObject(env, value); + else if (PyFloat_Check(value)) + return pythonFloatAsDoubleObject(env, value); + else if (PyUnicode_Check(value)) + return pythonStringAsJavaString(env, value); + else if (PyByteArray_Check(value)) + return pythonByteArrayAsByteArray(env, value); + else if (PyDict_Check(value)) + return pythonDictionaryAsMap(env, value); + else if (hasNumpy && PyArray_Check(value)) + return pythonArrayAsNDArray(env, (PyArrayObject *)value); + else if (PySequence_Check(value)) + return pythonSequenceAsObjectArray(env, value); + else + return NULL; +} + +jobjectArray pythonSequenceAsObjectArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jobjectArray array = (*env)->NewObjectArray(env, jlen, (*env)->FindClass(env, OBJECT_CLASS), NULL); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + jobject object = pythonObjectAsObject(env, item); + (*env)->SetObjectArrayElement(env, array, i, object); } - else { - npy_intp n = nContiguous(d+1, nd, strides, dims, ncont); - ncont[d] = n > 0 && strides[d] == sizeof(double) * n ? dims[d] * n : 0; - return ncont[d]; + + return array; +} + +jbooleanArray pythonSequenceAsBooleanArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jbooleanArray array = (*env)->NewBooleanArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyBool_Check(item)) { + jboolean value = item == Py_True; + (*env)->SetBooleanArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not a boolean"); + return NULL; + } } + + return array; } -void copyDoubleArrayValues(JNIEnv *env, jdoubleArray array, double *data, npy_intp *offset, int d, int nd, npy_intp *strides, npy_intp *dims, npy_intp *ncont) { - if (ncont[d] > 0) { - (*env)->SetDoubleArrayRegion(env, array, (jint)*offset, (jint)ncont[d], data); - *offset += ncont[d]; +jintArray pythonSequenceAsIntegerArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jintArray array = (*env)->NewIntArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyLong_Check(item)) { + jint value = PyLong_AsLong(item); + (*env)->SetIntArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not an integer"); + return NULL; + } } - else { - int i; - for (i = 0; i < dims[d]; i++) { - copyDoubleArrayValues(env, array, (double*)((char*)data + strides[d] * i), offset, d+1, nd, strides, dims, ncont); + + return array; +} + +jlongArray pythonSequenceAsLongArray(JNIEnv *env, PyObject *seq) { + Py_ssize_t len = PySequence_Size(seq); + jsize jlen = (jsize)min(len, JAVA_MAXINT); + jlongArray array = (*env)->NewLongArray(env, jlen); + + jint i; + + for (i = 0; i < jlen; i++) { + PyObject *item = PySequence_GetItem(seq, i); + if (PyLong_Check(item)) { + jlong value = PyLong_AsLongLong(item); + (*env)->SetLongArrayRegion(env, array, i, 1, &value); + } + else { + throwPythonException(env, "List item not an integer"); + return NULL; } } + + return array; } jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) { @@ -274,7 +733,7 @@ jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) { int i; if (len > JAVA_MAXINT) { - throwException(env, RUNTIME_EXCEPTION, "Array too large"); + throwPythonException(env, "Array too large"); return NULL; } @@ -303,33 +762,49 @@ jobject pythonArrayAsNDArray(JNIEnv *env, PyArrayObject *array) { } } -jintArray pythonListAsIntegerArray(JNIEnv *env, PyObject *list) { - Py_ssize_t len = PyList_Size(list); - jsize jlen = (jsize)min(len, JAVA_MAXINT); - jdoubleArray array = (*env)->NewIntArray(env, jlen); +jobject pythonDictionaryAsMap(JNIEnv *env, PyObject *dict) { + jclass hashmapClass = (*env)->FindClass(env, "java/util/HashMap"); + jmethodID constructor = (*env)->GetMethodID(env, hashmapClass, "", "(I)V"); + jmethodID putMethod = (*env)->GetMethodID(env, hashmapClass, "put", "(L" OBJECT_CLASS ";L" OBJECT_CLASS ";)L" OBJECT_CLASS ";"); - jint i; + Py_ssize_t size = PyDict_Size(dict); + jobject map = (*env)->NewObject(env, hashmapClass, constructor, (jint)size); - for (i = 0; i < jlen; i++) { - PyObject *item = PyList_GetItem(list, i); - if (PyLong_Check(item)) { - jint value = PyLong_AsLong(item); - (*env)->SetIntArrayRegion(env, array, i, 1, &value); - } - else { - throwException(env, RUNTIME_EXCEPTION, "List item not an integer"); - return NULL; - } + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next(dict, &pos, &key, &value)) { + jobject keyObject = pythonObjectAsObject(env, key); + jobject valueObject = pythonObjectAsObject(env, value); + (*env)->CallObjectMethod(env, map, putMethod, keyObject, valueObject); } - return array; + return map; +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jboolean value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonBool(value); + + setPythonVariable(module, pythonName, val); } -JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonIntegerVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jint value) { +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jbooleanArray value) { PyObject *module = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); - PyObject *val = PyLong_FromLong(value); + PyObject *val = getPythonBooleanList(env, value); + + setPythonVariable(module, pythonName, val); +} + +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlong value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = PyLong_FromLongLong(value); setPythonVariable(module, pythonName, val); } @@ -343,6 +818,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonInte setPythonVariable(module, pythonName, val); } +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jlongArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonLongList(env, value); + + setPythonVariable(module, pythonName, val); +} + JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdouble value) { PyObject *module = (PyObject*)contextID; @@ -352,6 +836,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoub setPythonVariable(module, pythonName, val); } +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonFloatArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jfloatArray value) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonFloatList(env, value); + + setPythonVariable(module, pythonName, val); +} + JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jdoubleArray value) { PyObject *module = (PyObject*)contextID; @@ -382,8 +875,8 @@ 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) { PyObject *module = (PyObject*)contextID; - if (_import_array() < 0) { - throwException(env, RUNTIME_EXCEPTION, "Importing numpy failed"); + if (!hasNumpy) { + throwPythonException(env, "Importing numpy failed"); return; } @@ -395,6 +888,15 @@ JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonNDAr } } +JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_setPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName, jobject value, jobject binding) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + PyObject *val = getPythonObject(env, value, binding); + + setPythonVariable(module, pythonName, val); +} + JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) { PyObject *module = (PyObject*)contextID; @@ -411,15 +913,42 @@ JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_executePython PyObject *exceptionType = PyErr_Occurred(); if (exceptionType != NULL) { - PyObject *exception, *stackTrace; - char *message; - PyErr_Fetch(&exceptionType, &exception, &stackTrace); - message = PyUnicode_AsUTF8(exception); - throwException(env, RUNTIME_EXCEPTION, message); + PyObject *exception, *traceback; + PyErr_Fetch(&exceptionType, &exception, &traceback); + + { + PyObject *tracebackModule = PyImport_ImportModule("traceback"); + if (tracebackModule != NULL) { + PyObject *formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception"); + if (formatExc != NULL) { + PyObject *args = PyTuple_Pack(3, exceptionType, exception, traceback); + PyObject *message = PyObject_CallObject(formatExc, args); + if (message != NULL) { + PyObject *emptyStr = PyUnicode_FromString(""); + PyObject *joined = PyUnicode_Join(emptyStr, message); + char *messageStr = PyUnicode_AsUTF8(joined); + throwPythonException(env, messageStr); + Py_DECREF(joined); + Py_DECREF(emptyStr); + Py_DECREF(message); + } + else { + throwPythonException(env, "Internal error, no message"); + } + Py_DECREF(args); + Py_DECREF(formatExc); + } + else { + throwPythonException(env, "Internal error, no format_exc function"); + } + Py_DECREF(tracebackModule); + } + else { + throwPythonException(env, "Internal error, no traceback module"); + } + } } - // Py_XDECREF(globals); - (*env)->ReleaseStringUTFChars(env, statement, utfchars); return result != NULL ? 0 : 1; @@ -434,16 +963,19 @@ JNIEXPORT jstring JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonS PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); return 0; } if (!PyUnicode_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not a string"); + throwPythonException(env, "Python variable not a string"); return 0; } - return pythonStringAsJavaString(env, value); + { + jstring result = pythonStringAsJavaString(env, value); + return result; + } } JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonStringArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { @@ -453,35 +985,82 @@ JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPy PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return 0; + } + + { + jobjectArray result = pythonSequenceAsStringArray(env, value); + return result; + } +} + +JNIEXPORT jboolean JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return 0; + } + + if (!PyBool_Check(value)) { + throwPythonException(env, "Python variable not a boolean"); + return 0; + } + + return value == Py_True; +} + +JNIEXPORT jbooleanArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonBooleanArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); return 0; } - if (!PyList_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not a list"); + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); return 0; } - return pythonStringListAsJavaArray(env, value); + { + jbooleanArray result = pythonSequenceAsBooleanArray(env, value); + return result; + } } -JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { +JNIEXPORT jlong JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { PyObject *module = (PyObject*)contextID; PyObject *pythonName = getPythonString(env, variableName); PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); return 0; } if (!PyLong_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not an integer"); + throwPythonException(env, "Python variable not an integer"); return 0; } - return PyLong_AsLong(value); + { + jlong result = PyLong_AsLongLong(value); + return result; + } } JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonIntegerArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { @@ -491,16 +1070,41 @@ JNIEXPORT jintArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPytho PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); + return NULL; + } + + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); + return NULL; + } + + { + jintArray result = pythonSequenceAsIntegerArray(env, value); + return result; + } +} + +JNIEXPORT jlongArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonLongArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); return NULL; } - if (!PyList_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not a list"); + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); return NULL; } - return pythonListAsIntegerArray(env, value); + { + jlongArray result = pythonSequenceAsLongArray(env, value); + return result; + } } JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { @@ -510,16 +1114,19 @@ JNIEXPORT jdouble JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonD PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); return 0.0; } if (!PyFloat_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not a float"); + throwPythonException(env, "Python variable not a float"); return 0.0; } - return PyFloat_AsDouble(value); + { + jdouble result = PyFloat_AsDouble(value); + return result; + } } JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonDoubleArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { @@ -529,23 +1136,26 @@ JNIEXPORT jdoubleArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPy PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); return NULL; } - if (!PyList_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not a list"); + if (!PySequence_Check(value)) { + throwPythonException(env, "Python variable not a sequence"); return NULL; } - return pythonListAsDoubleArray(env, value); + { + jdoubleArray result = pythonSequenceAsDoubleArray(env, value); + return result; + } } JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonNDArrayVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { PyObject *module = (PyObject*)contextID; - if (_import_array() < 0) { - throwException(env, RUNTIME_EXCEPTION, "Importing numpy failed"); + if (!hasNumpy) { + throwPythonException(env, "Importing numpy failed"); return NULL; } @@ -554,22 +1164,102 @@ JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonN PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); if (value == NULL) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not found"); + throwPythonException(env, "Python variable not found"); return NULL; } if (!PyArray_Check(value)) { - throwException(env, RUNTIME_EXCEPTION, "Python variable not an ndarray"); + throwPythonException(env, "Python variable not an ndarray"); return NULL; } if (PyArray_TYPE((PyArrayObject*)value) != NPY_DOUBLE) { - throwException(env, RUNTIME_EXCEPTION, "Only ndarrays of type double are supported"); + throwPythonException(env, "Only ndarrays of type double are supported"); return NULL; } - return pythonArrayAsNDArray(env, (PyArrayObject *)value); + { + jobject result = pythonArrayAsNDArray(env, (PyArrayObject *)value); + return result; + } + } +} + +JNIEXPORT jobject JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariantVariableImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + + PyObject *pythonName = getPythonString(env, variableName); + + PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName); + if (value == NULL) { + throwPythonException(env, "Python variable not found"); + return NULL; } + + hasNumpy = _import_array() != -1; + + { + jobject result = pythonObjectAsObject(env, value); + return result; + } +} + +JNIEXPORT jint JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableTypeImpl(JNIEnv *env, jobject thisObj, jlong contextID, jstring variableName) { + PyObject *module = (PyObject*)contextID; + PyObject *dict = PyModule_GetDict(module); + + PyObject *pythonName = getPythonString(env, variableName); + + if (!PyDict_Contains(dict, pythonName)) { + return 0; + } + + { + PyObject *value = PyDict_GetItem(dict, pythonName); + + jint result; + + if (PyBool_Check(value)) + result = 1; + else if (PyLong_Check(value)) + result = 2; + else if (PyFloat_Check(value)) + result = 3; + else if (PyUnicode_Check(value)) + result = 4; + else if (PyByteArray_Check(value)) + result = 5; + else if (PyDict_Check(value)) + result = 6; + else if (hasNumpy && PyArray_Check(value)) + result = 7; + else if (PySequence_Check(value)) + result = 8; + else + result = -1; + + return result; + } +} + +JNIEXPORT jobjectArray JNICALL Java_org_simantics_pythonlink_PythonContext_getPythonVariableNamesImpl(JNIEnv *env, jobject thisObj, jlong contextID) { + PyObject *module = (PyObject*)contextID; + PyObject *dict = PyModule_GetDict(module); + + PyObject *keys = PyDict_Keys(dict); + Py_ssize_t size = PyList_Size(keys); + + jobjectArray result = (*env)->NewObjectArray(env, (jsize)size, (*env)->FindClass(env, STRING_CLASS), NULL); + + Py_ssize_t i; + for (i = 0; i < size; i++) { + jstring javaName = pythonStringAsJavaString(env, PyList_GetItem(keys, i)); + (*env)->SetObjectArrayElement(env, result, (jint)i, javaName); + } + + Py_XDECREF(keys); + + return result; } BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -580,12 +1270,10 @@ BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: // attach to process // return FALSE to fail DLL load - Py_Initialize(); break; case DLL_PROCESS_DETACH: // detach from process - Py_Finalize(); break; case DLL_THREAD_ATTACH: