diff --git a/src/main/c/jni/org_jpy_PyLib.c b/src/main/c/jni/org_jpy_PyLib.c index fa1832ac56..53cd7ef72d 100644 --- a/src/main/c/jni/org_jpy_PyLib.c +++ b/src/main/c/jni/org_jpy_PyLib.c @@ -125,6 +125,73 @@ 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) && !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; + #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_35P) + 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_35P) + PyMem_RawFree(pythonHome); + #endif + } + + (*jenv)->ReleaseStringUTFChars(jenv, jPythonHome, nonWidePythonHome); + } + + return result; +#endif +} + /* * 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/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/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/main/java/org/jpy/PyLib.java b/src/main/java/org/jpy/PyLib.java index 903e268cc6..7c1509c42a 100644 --- a/src/main/java/org/jpy/PyLib.java +++ b/src/main/java/org/jpy/PyLib.java @@ -209,6 +209,15 @@ 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()}. + * 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 + */ + public static native boolean setPythonHome(String pythonHome); /** * @return The Python interpreter version string. 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