From: Stefan Richthofer <Stefan.R<ichthofer@gm...> - 2013-09-17 13:32:36
Hello Jython developers,
my JyNI development reached a state where I can call an "import numpy" without
getting undefined-symbol-errors (this version is not yet at github).
However it still needs much work to be reallyusable.
I hope someone can give me a hint about the following issue.
The numpy __init__.py script starts with the following lines (initial doc comments collapsed):
# We first need to detect if we're being called as part of the numpy setup
# procedure itself in a reliable manner.
__NUMPY_SETUP__ = False
import sys as _sys
_sys.stderr.write('Running from numpy source directory.\n')
...actual import code...
The code goes fine until it reaches the numpy.core __init__.py script, particularly
the line "import multiarray". However, up to there Jython would have done it also without JyNI anyway.
import multiarray is the first place, where a native file (multiarray.so) must be loaded.
Now JyNI comes in. The code calling the multiarray init method looks like the following:
p = _PyImport_GetDynLoadFunc(name, shortname, pathname, fp);
In CPython everything works fine, PyErr_Occurred() returns NULL.
In JyNI, the code fails because PyErr_Occurred() returns non-NULL.
I found out, this is not due to an actual import error, but that the
Name-error from the beginning, where numpy checks for setup-mode, persists:
__NUMPY_SETUP__ = False
The JyNI implementation of PyErr_Occurred() is as follows:
return JyNI_PyObject_FromJythonPyObject((*env)->CallStaticObjectMethod(env, JyNIClass, JyNIPyErr_Occurred));
JyNI_PyObject_FromJythonPyObject is responsible for converting jobject to PyObject*. To discuss it
here would get far out of scope. However it maps null to NULL and also handles the None singleton correctly.
env is the following macro responsible for retrieving the JNI environment pointer:
(The jvm pointer was previously cached in *java)
#define env(errRet) \
if ((*java)->GetEnv(java, (void **)&env, JNI_VERSION_1_2))\
The backing Java method goes as follows:
public static PyObject PyErr_Occurred()
ThreadState tstate = Py.getThreadState();
return tstate.exception == null ? null : tstate.exception.type;
In comparision to that, take a look at the CPython implementation:
PyThreadState *tstate = PyThreadState_GET();
My JyNI implementation should do exactly the same in my eyes, but behaves subtly different.
While in CPython the Name error from the beginning is cleared somehow
before imports are performed, it persists in Jython/JyNI case.
I read that exceptions are scoped on stackframes and threads. I think there
are no multiple threads involved in CPython case, so is it due to different
stackframes? I could find no call to an active exception-clearing method like
PyErr_Clear or PyErr_Fetch in any CPython code relevant for importing.
Of course I could adjust the JyNI loading-code to clear any previous exceptions
before loading external modules (i.e. I would not just clear them but do PyErr_Fetch
and PyErr_Restore later to restore the previous state after loading is done).
Probably this will be the solution in the end anyway, but I would really like to
understand the cause of this cumbersome behavior so I can fix it "the right way".
Thanks in advance for any help on this problem!