ninia / jep

Embed Python in Java
Other
1.31k stars 149 forks source link

Running jep on windows fails when importing e.g. numpy #455

Closed injo11 closed 1 year ago

injo11 commented 1 year ago

Describe the problem The following code fails with the exception below

import jep.Interpreter;
import jep.SharedInterpreter;

public class TestJep {

       public static void main(String[] args) {

        try (Interpreter interp = new SharedInterpreter()) {
            interp.exec("import numpy as np");
        }
    }
}

Exception in thread "main" jep.JepException: <class 'ImportError'>: json.loads at C:\WPy64-3980\python-3.9.8.amd64\lib\site-packages\jep\java_import_hook.getattr(java_import_hook.py:57) at C:\WPy64-3980\python-3.9.8.amd64\lib\site-packages\numpy_version.get_versions(_version.py:21) at C:\WPy64-3980\python-3.9.8.amd64\lib\site-packages\numpy__init.(init__.py:139) at .(:1) at jep.Jep.exec(Native Method) at jep.Jep.exec(Jep.java:341) at minerva.fusion.c2w.apps.sampling.TestJep.main(TestJep.java:11) Caused by: java.lang.ClassNotFoundException: json.loads at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ... 3 more

I have tried to set the PYTHONHOME both for the system and using PyConfig:

PyConfig pyConfig = new PyConfig();
pyConfig.setPythonHome("C:/WPy64-3980/python-3.9.8.amd64");
MainInterpreter.setInitParams(pyConfig);

I have tried to set the java.library.path both when executing the class above with -Djava.library.path=C:\WPy64-3980\python-3.9.8.amd64\Lib\site-packages\jep and using MainInterpreter.setJepLibraryPath("C:/WPy64-3980/python-3.9.8.amd64/Lib/site-packages/jep/jep.dll");

..and different combinations of above.

The 'jep' command from powershell works, and can import numpy. If I don't import any external library, everything works fine, only when trying to import numpy, tensorflow etc.

Environment (please complete the following information):

ndjensen commented 1 year ago

Jep uses a ClassEnquirer to determine if it should try to do the import from Java or from Python. Since the underlying cause of your error was ClassNotFoundException, it looks like Jep tried to import json as a Java package when really numpy wanted the Python package json. That would mean ClassEnquirer.isJavaPackage() returned true for "json". The default ClassEnquirer is ClassList so if you're using that that indicates that you have a Java package named "json" on your Java classpath. You will need to either remove the json package from your Java classpath or select a different ClassEnquirer, possibly one you write. You pass the ClassEnquirer in on the JepConfig object you pass to the interpreter constructor. A simple one to implement that has been suggested before is to wrap ClassList and if encountering the offending package, return false, otherwise, delegate to ClassList.

injo11 commented 1 year ago

Thanks, that works!