Skip to content

Fix jnipython JNI library to support also Python 3.10-3.13

Fix JNI libraries to support also Python 3.10-3.13.

The problem after Python 3.10 is:

> import "Python"
> runPython $ executePythonStatement "print('Hello')"
org.simantics.pythonlink.PythonException: SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "SCL_INPUT", line 1, in <module>
SystemError: <built-in function write> returned a result with an exception set

    at org.simantics.pythonlink.PythonContext.executePythonStatementImpl(Native Method)
    at org.simantics.pythonlink.PythonContext.lambda$3(PythonContext.java:148)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

https://docs.python.org/3/c-api/arg.html#strings-and-buffers

For all # variants of formats (s#, y#, etc.), the macro PY_SSIZE_T_CLEAN must be defined before including Python.h. On Python 3.9 and older, the type of the length argument is Py_ssize_t if the PY_SSIZE_T_CLEAN macro is defined, or int otherwise.

https://docs.python.org/3/c-api/intro.html

The following change in the native JNI code should be enough to fix the problem:

+#define PY_SSIZE_T_CLEAN
 #include <Python.h>

Note that https://docs.python.org/3/c-api/arg.html#strings-and-buffers states:

On Python 3.12 and older, the macro PY_SSIZE_T_CLEAN must be defined before including Python.h to use all # variants of formats (s#, y#, etc.) explained below. This is not necessary on Python 3.13 and later.


Another problem is that:

Changed in version 3.12: u, u#, Z, and Z# are removed because they used a legacy Py_UNICODE* representation.

so we have to change the PyArg_ParseTuple argument "u#" to e.g. UTF-8 "s#" formatting. This means code needs to be added to convert UTF-8 to modified UTF-8 to convert from Python to Java.

Edited by Tuukka Lehtonen