diff --git a/doc/install.rst b/doc/install.rst index d84382c589..44642ad2f5 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -84,6 +84,10 @@ Another optional parameter * ``jpy.debug`` - which is either ``true`` or ``false`` can be used to output extra debugging information. +The optional parameter + +* ``jpy.pythonPrefix`` - points to the location of the PYTHONHOME. If set, then jpy will call ``PyLib.setPythonHome()`` with the value of this parameter. + All the parameters can be passed directly to the JVM either as Java system properties or by using the single system property * ``jpy.config`` - which is a path to a Java properties files containing the definitions of the two parameters named above. @@ -96,7 +100,7 @@ Setting PYTHONHOME If the environment variable ``PYTHONHOME`` is not set when you call Python from Java, you may get an error about file system encodings not being found. It is possible to set the location of Python from your Java program. Use ``PyLib.setPythonHome(pathToPythonHome)`` to do that, where ``pathToPythonHome`` is a ``String`` that -contains the location of the Python installation. +contains the location of the Python installation, or as described above, use the parameter ``jpy.pytyhonPrefix``. ======================== Build for Linux / Darwin diff --git a/jpyutil.py b/jpyutil.py index 5ab2463f5b..7d080c89d2 100644 --- a/jpyutil.py +++ b/jpyutil.py @@ -35,7 +35,7 @@ __author__ = "Norman Fomferra (Brockmann Consult GmbH) and contributors" __copyright__ = "Copyright 2015-2018 Brockmann Consult GmbH and contributors" __license__ = "Apache 2.0" -__version__ = "0.10.0.dev1" +__version__ = "0.9.1.dev1" # Uncomment for debugging diff --git a/pom.xml b/pom.xml index c3f6fcff30..c587e9d8c8 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.jpy jpy - 0.10.0-SNAPSHOT + 0.9.1-SNAPSHOT jar Java-Python Bridge @@ -188,4 +188,4 @@ - \ No newline at end of file + diff --git a/src/main/java/org/jpy/PyLib.java b/src/main/java/org/jpy/PyLib.java index 7c1509c42a..4b3e3ffada 100644 --- a/src/main/java/org/jpy/PyLib.java +++ b/src/main/java/org/jpy/PyLib.java @@ -22,7 +22,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; -import java.util.Map; import static org.jpy.PyLibConfig.JPY_LIB_KEY; import static org.jpy.PyLibConfig.OS; @@ -204,6 +203,11 @@ public static void startPython(String... extraPaths) { } Diag.setFlags(Diag.F_EXEC); } + + String pythonHome = getProperty(PyLibConfig.JPY_CONFIG_PREFIX, false); + if (pythonHome != null) { + setPythonHome(pythonHome); + } startPython0(extraPaths); } diff --git a/src/main/java/org/jpy/PyLibConfig.java b/src/main/java/org/jpy/PyLibConfig.java index 3e16e62047..4a82342cec 100644 --- a/src/main/java/org/jpy/PyLibConfig.java +++ b/src/main/java/org/jpy/PyLibConfig.java @@ -38,6 +38,7 @@ class PyLibConfig { public static final String JPY_LIB_KEY = "jpy.jpyLib"; public static final String JPY_CONFIG_KEY = "jpy.config"; public static final String JPY_CONFIG_RESOURCE = "jpyconfig.properties"; + public static final String JPY_CONFIG_PREFIX = "jpy.pythonPrefix"; public enum OS { WINDOWS, diff --git a/src/main/java/org/jpy/PyProxyHandler.java b/src/main/java/org/jpy/PyProxyHandler.java index 37ee54579e..dbb3f5ced9 100644 --- a/src/main/java/org/jpy/PyProxyHandler.java +++ b/src/main/java/org/jpy/PyProxyHandler.java @@ -100,9 +100,36 @@ public Object invoke(Object proxyObject, Method method, Object[] args) throws Th } else if (method.equals(toStringMethod)) { methodName = "__str__"; } + Class[] parameterTypes = method.getParameterTypes(); - return PyLib.callAndReturnValue(this.pyObject.getPointer(), callableKind == PyLib.CallableKind.METHOD, - methodName, args != null ? args.length : 0, args, method.getParameterTypes(), returnType); + if (args != null) { + for (int i = 0; i < args.length; i++) { + Object oneArg = args[i]; + if (oneArg instanceof Proxy) { + PyObject possiblePyObject = proxyGetOtherPyObject(proxyObject, oneArg); + if (possiblePyObject != null) { + args[i] = possiblePyObject; + parameterTypes[i] = Object.class; + } + } + } + } + boolean returnTypeIsInterface = returnType.isInterface(); + Class originalReturnType = returnType; + if (returnTypeIsInterface) { + returnType = PyObject.class; + } + Object result = PyLib.callAndReturnValue(this.pyObject.getPointer(), + callableKind == PyLib.CallableKind.METHOD, + methodName, + args != null ? args.length : 0, + args, + parameterTypes, + returnType); + if (returnTypeIsInterface) { + result = ((PyObject)result).createProxy(originalReturnType); + } + return result; } /** diff --git a/src/test/java/org/jpy/PyObjectTest.java b/src/test/java/org/jpy/PyObjectTest.java index fac8db41fa..07fccf88db 100644 --- a/src/test/java/org/jpy/PyObjectTest.java +++ b/src/test/java/org/jpy/PyObjectTest.java @@ -8,10 +8,10 @@ * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * This file was modified by Illumon. * @@ -128,7 +128,6 @@ public void testExecuteCode_Script() throws Exception { PyInputMode.SCRIPT, null, localMap); assertNotNull(pyVoid); assertEquals(null, pyVoid.getObjectValue()); - assertNotNull(localMap.get("jpy")); assertNotNull(localMap.get("File")); assertNotNull(localMap.get("f")); @@ -138,29 +137,33 @@ public void testExecuteCode_Script() throws Exception { assertEquals(new File("test.txt"), localMap.get("f")); } - + @Test public void testLocals() throws Exception { HashMap localMap = new HashMap<>(); localMap.put("x", 7); localMap.put("y", 6); - PyObject pyVoid = PyObject.executeCode("z = x + y", PyInputMode.STATEMENT, null, localMap); + PyObject pyVoid = PyObject.executeCode("z = x + y", + PyInputMode.STATEMENT, + null, + localMap); assertEquals(null, pyVoid.getObjectValue()); - + System.out.println("LocalMap size = " + localMap.size()); for (Map.Entry entry : localMap.entrySet()) { System.out.println("LocalMap[" + entry.getKey() + "]: " + entry.getValue()); } - + assertNotNull(localMap.get("x")); assertNotNull(localMap.get("y")); assertNotNull(localMap.get("z")); - + assertEquals(7, localMap.get("x")); assertEquals(6, localMap.get("y")); assertEquals(13, localMap.get("z")); + } - + @Test public void testExecuteScript_ErrorExpr() throws Exception { try { @@ -209,7 +212,7 @@ public void testGetSetAttributes() throws Exception { PyObject a = myobj.getAttribute("a"); Assert.assertEquals("Tut tut!", a.getStringValue()); } - + private boolean hasKey(Map dict, String key) { for (Map.Entry entry : dict.entrySet()) { if (entry.getKey().isString()) { @@ -220,22 +223,22 @@ private boolean hasKey(Map dict, String key) { } return false; } - + @Test public void testDictCopy() throws Exception { PyObject globals = PyLib.getMainGlobals(); PyDictWrapper dict = globals.asDict(); PyDictWrapper dictCopy = dict.copy(); - + PyObject.executeCode("x = 42", PyInputMode.STATEMENT, globals, dictCopy.unwrap()); - + boolean copyHasX = hasKey(dictCopy, "x"); boolean origHasX = hasKey(dict, "x"); - + assertTrue(copyHasX); assertFalse(origHasX); } - + @Test public void testCreateProxyAndCallSingleThreaded() throws Exception { // addTestDirToPythonSysPath(); @@ -349,6 +352,7 @@ public String call() throws Exception { private static interface ISimple { public int getValue(); + public ISimple add(ISimple other); } private static ISimple newTestObj(PyModule pyModule, String pythonClass, int value) { @@ -375,5 +379,10 @@ private static void testOneClass(PyModule pyModule, String pythonClass, boolean assertEquals(eqRes, eqResExpected); assertEquals(simple.hashCode() == simple2.hashCode(), eqResExpected); assertEquals(simple.equals(simple), true); + ISimple sum = simple.add(simple2); + assertEquals(sum.getValue(), 2468); + ISimple simple3 = newTestObj(pyModule, pythonClass, 5678); + sum = simple.add(simple3); + assertEquals(sum.getValue(), 1234 + 5678); } } diff --git a/src/test/python/fixtures/hasheqstr.py b/src/test/python/fixtures/hasheqstr.py index 59ef87da25..afa857818d 100644 --- a/src/test/python/fixtures/hasheqstr.py +++ b/src/test/python/fixtures/hasheqstr.py @@ -7,7 +7,13 @@ def __str__(self): def getValue(self): return self._v - + + def add(self, other): + if isinstance(other, self.__class__): + return Simple(self._v + other._v) + else: + return self + class HashSimple(object): def __init__(self, v): self._v = v @@ -27,3 +33,8 @@ def __eq__(self, other): else: return False # Java can't support NotImplemented + def add(self, other): + if isinstance(other, self.__class__): + return HashSimple(self._v + other._v) + else: + return self \ No newline at end of file