From b7adfb7b98a13d5315716803df46176418b8f032 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 13 Jun 2018 18:03:31 -0400 Subject: [PATCH 1/4] make constants get into Python correctly --- src/main/c/jpy_jtype.c | 10 +++++----- src/main/java/org/jpy/PyDictWrapper.java | 3 ++- src/test/java/org/jpy/PyObjectTest.java | 4 ++++ src/test/java/org/jpy/fixtures/Processor.java | 6 ++++++ src/test/python/fixtures/proc_class.py | 11 +++++++++-- src/test/python/fixtures/proc_module.py | 15 ++++++++++++--- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/main/c/jpy_jtype.c b/src/main/c/jpy_jtype.c index 79d4ee45aa..78f5e27208 100644 --- a/src/main/c/jpy_jtype.c +++ b/src/main/c/jpy_jtype.c @@ -284,23 +284,23 @@ PyObject* JType_ConvertJavaToPythonObject(JNIEnv* jenv, JPy_JType* type, jobject if (type->componentType == NULL) { // Scalar type, not an array, try to convert to Python equivalent - if (type == JPy_JBooleanObj) { + if (type == JPy_JBooleanObj || type == JPy_JBoolean) { jboolean value = (*jenv)->CallBooleanMethod(jenv, objectRef, JPy_Boolean_BooleanValue_MID); JPy_ON_JAVA_EXCEPTION_RETURN(NULL); return JPy_FROM_JBOOLEAN(value); - } else if (type == JPy_JCharacterObj) { + } else if (type == JPy_JCharacterObj || type == JPy_JChar) { jchar value = (*jenv)->CallCharMethod(jenv, objectRef, JPy_Character_CharValue_MID); JPy_ON_JAVA_EXCEPTION_RETURN(NULL); return JPy_FROM_JCHAR(value); - } else if (type == JPy_JByteObj || type == JPy_JShortObj || type == JPy_JIntegerObj) { + } else if (type == JPy_JByteObj || type == JPy_JShortObj || type == JPy_JIntegerObj || type == JPy_JShort || type == JPy_JInt) { jint value = (*jenv)->CallIntMethod(jenv, objectRef, JPy_Number_IntValue_MID); JPy_ON_JAVA_EXCEPTION_RETURN(NULL); return JPy_FROM_JINT(value); - } else if (type == JPy_JLongObj) { + } else if (type == JPy_JLongObj || type == JPy_JLong) { jlong value = (*jenv)->CallLongMethod(jenv, objectRef, JPy_Number_LongValue_MID); JPy_ON_JAVA_EXCEPTION_RETURN(NULL); return JPy_FROM_JLONG(value); - } else if (type == JPy_JFloatObj || type == JPy_JDoubleObj) { + } else if (type == JPy_JFloatObj || type == JPy_JDoubleObj || type == JPy_JFloat || type == JPy_JDouble) { jdouble value = (*jenv)->CallDoubleMethod(jenv, objectRef, JPy_Number_DoubleValue_MID); JPy_ON_JAVA_EXCEPTION_RETURN(NULL); return JPy_FROM_JDOUBLE(value); diff --git a/src/main/java/org/jpy/PyDictWrapper.java b/src/main/java/org/jpy/PyDictWrapper.java index b2be9247af..7bf97d0406 100644 --- a/src/main/java/org/jpy/PyDictWrapper.java +++ b/src/main/java/org/jpy/PyDictWrapper.java @@ -168,12 +168,13 @@ public boolean contains(Object o) { @Override public Iterator> iterator() { return new Iterator>() { + PyModule builtins = PyModule.getBuiltins(); PyObject it = pyObject.callMethod("__iter__"); PyObject next = prepareNext(); private PyObject prepareNext() { try { - return next = it.callMethod("next"); + return next = builtins.call("next", it); } catch (StopIteration e) { return next = null; } diff --git a/src/test/java/org/jpy/PyObjectTest.java b/src/test/java/org/jpy/PyObjectTest.java index c355c8a7ab..8d2d530756 100644 --- a/src/test/java/org/jpy/PyObjectTest.java +++ b/src/test/java/org/jpy/PyObjectTest.java @@ -279,6 +279,10 @@ static void testCallProxySingleThreaded(PyObject procObject) { assertEquals("computeTile-100,200", result); result = processor.computeTile(200, 200, new float[100 * 100]); assertEquals("computeTile-200,200", result); + processor.setVal(1234); + int val = processor.getVal(); + assertEquals(val, 1234); + assertEquals(true, processor.check1234()); result = processor.dispose(); assertEquals("dispose", result); } diff --git a/src/test/java/org/jpy/fixtures/Processor.java b/src/test/java/org/jpy/fixtures/Processor.java index 29332fc372..08835f88d8 100644 --- a/src/test/java/org/jpy/fixtures/Processor.java +++ b/src/test/java/org/jpy/fixtures/Processor.java @@ -27,4 +27,10 @@ public interface Processor { String computeTile(int w, int h, float[] data); String dispose(); + + void setVal(int n); + + int getVal(); + + boolean check1234(); } diff --git a/src/test/python/fixtures/proc_class.py b/src/test/python/fixtures/proc_class.py index ce61510d8c..8e4e20df68 100644 --- a/src/test/python/fixtures/proc_class.py +++ b/src/test/python/fixtures/proc_class.py @@ -19,5 +19,12 @@ def spend_some_time(self): for i in range(10000): l.reverse() - - + def setVal(self, val): + self._val = val + + def getVal(self): + return self._val + + def check1234(self): + return self._val == 1234 + \ No newline at end of file diff --git a/src/test/python/fixtures/proc_module.py b/src/test/python/fixtures/proc_module.py index 63e633c4af..01f75e6b12 100644 --- a/src/test/python/fixtures/proc_module.py +++ b/src/test/python/fixtures/proc_module.py @@ -15,6 +15,15 @@ def spend_some_time(): for i in range(10000): l.reverse() - - - +_module_val = None +def setVal(val): + global _module_val + _module_val = val + +def getVal(): + global _module_val + return _module_val + +def check1234(): + global _module_val + return _module_val == 1234 From aca1e1e95170f3e637c1eb43aa0e719e88756064 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 20 Jun 2018 16:41:13 -0400 Subject: [PATCH 2/4] Support setting PYTHONHOME --- src/main/c/jni/org_jpy_PyLib.c | 62 ++++++++++++++++++++++++++++++++ src/main/c/jni/org_jpy_PyLib.h | 8 +++++ src/main/java/org/jpy/PyLib.java | 8 +++++ 3 files changed, 78 insertions(+) diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index fa1832ac56..97a34109f5 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -125,6 +125,68 @@ JNIEXPORT jboolean JNICALL Java_org_jpy_PyLib_isPythonRunning return init && JPy_Module != NULL; } +#define MAX_PYTHON_HOME 256 +#if defined(JPY_COMPAT_33P) +wchar_t staticPythonHome[MAX_PYTHON_HOME]; +#elif defined(JPY_COMPAT_27) +char staticPythonHome[MAX_PYTHON_HOME]; +#endif + +/* + * Class: org_jpy_PyLib + * Method: setPythonHome + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome + (JNIEnv* jenv, jclass jLibClass, jstring jPythonHome) +{ + #if defined(JPY_COMPAT_33P) + const wchar_t* pythonHome = NULL; + #elif defined(JPY_COMPAT_27) + const char* pythonHome = NULL; + #endif + + const char *nonWidePythonHome = NULL; + jboolean result = 0; + nonWidePythonHome = (*jenv)->GetStringUTFChars(jenv, jPythonHome, NULL); + + if (nonWidePythonHome != NULL) { + + #if defined(JPY_COMPAT_33P) + pythonHome = Py_DecodeLocale(nonWidePythonHome, NULL); + if (pythonHome != NULL) { + if (wcslen(pythonHome) < MAX_PYTHON_HOME) { + wcscpy(staticPythonHome, pythonHome); + result = 1; + } + else { + PyMem_RawFree(pythonHome); + } + + } + + #elif defined(JPY_COMPAT_27) + pythonHome = nonWidePythonHome; + if (strlen(pythonHome) < MAX_PYTHON_HOME) { + strcpy(staticPythonHome, pythonHome); + result = 1; + } + #endif + + if (result) { + Py_SetPythonHome(staticPythonHome); + + #if defined(JPY_COMPAT_33P) + PyMem_RawFree(pythonHome); + #endif + } + + (*jenv)->ReleaseStringUTFChars(jenv, jPythonHome, nonWidePythonHome); + } + + return result; +} + /* * Class: org_jpy_PyLib * Method: startPython0 diff --git a/src/main/c/jni/org_jpy_PyLib.h b/src/main/c/jni/org_jpy_PyLib.h index e4b2a3dfb0..6d870fd15f 100644 --- a/src/main/c/jni/org_jpy_PyLib.h +++ b/src/main/c/jni/org_jpy_PyLib.h @@ -15,6 +15,14 @@ extern "C" { JNIEXPORT jboolean JNICALL Java_org_jpy_PyLib_isPythonRunning (JNIEnv *, jclass); +/* + * Class: org_jpy_PyLib + * Method: setPythonHome + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome + (JNIEnv* jenv, jclass jLibClass, jstring jPythonHome); + /* * Class: org_jpy_PyLib * Method: startPython0 diff --git a/src/main/java/org/jpy/PyLib.java b/src/main/java/org/jpy/PyLib.java index 903e268cc6..c0302c2615 100644 --- a/src/main/java/org/jpy/PyLib.java +++ b/src/main/java/org/jpy/PyLib.java @@ -209,6 +209,14 @@ public static void startPython(String... extraPaths) { } static native boolean startPython0(String... paths); + + /** + * Does the equivalent of setting the PYTHONHOME environment variable. If used, + * this must be called prior to calling {@code startPython()}. + * @param pythonHome Path to Python Home (must be less than 256 characters!) + * @return true if successful, false if it fails + */ + public static native boolean setPythonHome(String pythonHome); /** * @return The Python interpreter version string. From 378c59de7112b076045cf5f8cf8dd918ddfa6b34 Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Wed, 20 Jun 2018 18:19:29 -0400 Subject: [PATCH 3/4] Fix Python 3.4 issue --- src/main/c/jni/org_jpy_PyLib.c | 10 +++++++--- src/main/c/jpy_compat.h | 5 ++++- src/main/java/org/jpy/PyLib.java | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index 97a34109f5..3e255d565d 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -140,7 +140,11 @@ char staticPythonHome[MAX_PYTHON_HOME]; JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome (JNIEnv* jenv, jclass jLibClass, jstring jPythonHome) { - #if defined(JPY_COMPAT_33P) + #if defined(JPY_COMPAT_33P) && !defined(JPY_COMPAT_35P) + return 0; // Not supported because DecodeLocale didn't exist in 3.4 + #endif + + #if defined(JPY_COMPAT_35P) const wchar_t* pythonHome = NULL; #elif defined(JPY_COMPAT_27) const char* pythonHome = NULL; @@ -152,7 +156,7 @@ JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome if (nonWidePythonHome != NULL) { - #if defined(JPY_COMPAT_33P) + #if defined(JPY_COMPAT_35P) pythonHome = Py_DecodeLocale(nonWidePythonHome, NULL); if (pythonHome != NULL) { if (wcslen(pythonHome) < MAX_PYTHON_HOME) { @@ -176,7 +180,7 @@ JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome if (result) { Py_SetPythonHome(staticPythonHome); - #if defined(JPY_COMPAT_33P) + #if defined(JPY_COMPAT_35P) PyMem_RawFree(pythonHome); #endif } diff --git a/src/main/c/jpy_compat.h b/src/main/c/jpy_compat.h index 818fb21447..62f969bc88 100644 --- a/src/main/c/jpy_compat.h +++ b/src/main/c/jpy_compat.h @@ -30,6 +30,9 @@ extern "C" { #undef JPY_COMPAT_33P #elif PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 3 #define JPY_COMPAT_33P 1 +#if PY_MINOR_VERSION >= 5 +#define JPY_COMPAT_35P 1 +#endif #undef JPY_COMPAT_27 #else #error JPY_VERSION_ERROR @@ -79,4 +82,4 @@ wchar_t* JPy_AsWideCharString_PriorToPy33(PyObject *unicode, Py_ssize_t *size); #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* !JPY_COMPAT_H */ \ No newline at end of file +#endif /* !JPY_COMPAT_H */ diff --git a/src/main/java/org/jpy/PyLib.java b/src/main/java/org/jpy/PyLib.java index c0302c2615..7c1509c42a 100644 --- a/src/main/java/org/jpy/PyLib.java +++ b/src/main/java/org/jpy/PyLib.java @@ -213,6 +213,7 @@ public static void startPython(String... extraPaths) { /** * Does the equivalent of setting the PYTHONHOME environment variable. If used, * this must be called prior to calling {@code startPython()}. + * Supported for Python 2.7, and Python 3.5 or higher * @param pythonHome Path to Python Home (must be less than 256 characters!) * @return true if successful, false if it fails */ From faab8f47b266220c0854cb6e8f80df8db2b936ca Mon Sep 17 00:00:00 2001 From: Dr-Irv Date: Thu, 21 Jun 2018 13:27:45 -0400 Subject: [PATCH 4/4] Fix Py3.4 and x86 --- src/main/c/jni/org_jpy_PyLib.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index 3e255d565d..53cd7ef72d 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -140,9 +140,9 @@ char staticPythonHome[MAX_PYTHON_HOME]; JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome (JNIEnv* jenv, jclass jLibClass, jstring jPythonHome) { - #if defined(JPY_COMPAT_33P) && !defined(JPY_COMPAT_35P) - return 0; // Not supported because DecodeLocale didn't exist in 3.4 - #endif +#if defined(JPY_COMPAT_33P) && !defined(JPY_COMPAT_35P) + return 0; // Not supported because DecodeLocale didn't exist in 3.4 +#else #if defined(JPY_COMPAT_35P) const wchar_t* pythonHome = NULL; @@ -189,6 +189,7 @@ JNIEXPORT jint JNICALL Java_org_jpy_PyLib_setPythonHome } return result; +#endif } /*