-///////////////////////////////////////////////////////
-// //
-// VTT Technical Research Centre of Finland LTD //
-// For internal use only. Do not redistribute. //
-// //
-// Authors: //
-// Antton Tapani ext-antton.tapani@vtt.fi //
-// //
-// Last modified by Antton Tapani 9.2016 //
-// //
-///////////////////////////////////////////////////////
+/*******************************************************************************
+ * Copyright (c) 2017-2019 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre - Initial API and implementation
+ * Semantum Oy - Improvements
+ *******************************************************************************/
#include "sclpy.h"
return throwException( env, ILLEGAL_ARGUMENT_EXCEPTION, message );
}
+// Returns a borrowed reference.
PyObject* getModule(jlong contextID) {
return PyState_FindModule((PyModuleDef*) contextID);
// return PyImport_AddModule("__main__");
writeToSCL(PyObject *self, PyObject *args)
{
if (currentEnv != NULL && sclWriter != NULL) {
- Py_UNICODE *what;
+ wchar_t *what;
Py_ssize_t length;
JNIEnv *env = currentEnv;
{NULL, NULL, 0, NULL}
};
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_initializePython(JNIEnv *env, jobject thisObj, jobject writer) {
- Py_Initialize();
+JNIEXPORT void JNICALL
+Java_org_simantics_pythonlink_PythonContext_initializePython(
+ JNIEnv *env, jobject thisObj, jobject writer) {
+ Py_InitializeEx(0);
{
- static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods, };
- PyObject *m = PyModule_Create(&moduledef);
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT, "sclwriter", NULL, -1, sclWriterMethods
+ };
+ PyObject *m = PyModule_Create(&moduledef);
sclWriter = (*env)->NewGlobalRef(env, writer);
- if (m == NULL) throwException(env, PYTHON_EXCEPTION, "Failed to create SCL writer module");
-
- PySys_SetObject("stdout", m);
- PySys_SetObject("stderr", m);
+ if (m == NULL) {
+ throwException(env, PYTHON_EXCEPTION,
+ "Failed to create SCL writer module");
+ } else {
+ PySys_SetObject("stdout", m);
+ PySys_SetObject("stderr", m);
+ Py_DECREF(m);
+ }
}
hasNumpy = _import_array();
modDef->m_size = -1;
module = PyModule_Create(modDef);
- Py_INCREF(module);
PyState_AddModule(module, modDef);
-
{
PyObject *builtin = PyImport_AddModule("builtins");
PyObject *dict = PyModule_GetDict(module);
+ Py_DECREF(module);
PyDict_SetItemString(dict, "__builtin__", builtin);
PyDict_SetItemString(dict, "__builtins__", builtin);
}
}
-JNIEXPORT void JNICALL Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(JNIEnv *env, jobject thisObj, jlong contextID) {
+JNIEXPORT void JNICALL
+Java_org_simantics_pythonlink_PythonContext_deleteContextImpl(
+ JNIEnv *env, jobject thisObj, jlong contextID) {
PyModuleDef *modDef = (PyModuleDef*)contextID;
- PyObject *module;
PyEval_RestoreThread(main_ts);
- module = PyState_FindModule(modDef);
- Py_XDECREF(module);
PyState_RemoveModule(modDef);
free((char*)modDef->m_name);
free(modDef);
PyList_SetItem(result, i, getPythonString(env, (jstring)item));
}
else {
+ Py_INCREF(Py_None);
PyList_SetItem(result, i, Py_None);
}
}
jobject componentObject = (*env)->CallObjectMethod(env, binding, getComponent, object, i);
jobject componentBinding = (*env)->CallObjectMethod(env, binding, getComponentBinding, i);
- PyObject *item = getPythonObject(env, componentObject, componentBinding);
- PyDict_SetItem(result, getPythonString(env, fieldName), item);
+ PyObject
+ *key = getPythonString(env, fieldName),
+ *item = getPythonObject(env, componentObject, componentBinding);
+ PyDict_SetItem(result, key, item);
+ Py_DECREF(key);
+ Py_DECREF(item);
}
return result;
jobject item = (*env)->CallObjectMethod(env, binding, getMethod, object, i);
if (item != NULL)
PyList_SetItem(result, i, getPythonObject(env, item, componentBinding));
- else
+ else {
+ Py_INCREF(Py_None);
PyList_SetItem(result, i, Py_None);
+ }
}
return result;
for (i = 0; i < size; i++) {
jobject key = (*env)->GetObjectArrayElement(env, keys, i);
jobject item = (*env)->GetObjectArrayElement(env, values, i);
- PyDict_SetItem(result, getPythonObject(env, key, keyBinding), getPythonObject(env, item, valueBinding));
+ PyObject
+ *pkey = getPythonObject(env, key, keyBinding),
+ *pitem = getPythonObject(env, item, valueBinding);
+ PyDict_SetItem(result, pkey, pitem);
+ Py_DECREF(pkey);
+ Py_DECREF(pitem);
}
(*env)->DeleteLocalRef(env, keys);
}
}
+// Steals refs to name & value.
void setPythonVariable(PyObject *module, PyObject *name, PyObject *value) {
if (name && value) {
PyDict_SetItem(PyModule_GetDict(module), name, value);
PyObject *item = PySequence_GetItem(seq, i);
if (PyUnicode_Check(item)) {
jstring value = pythonStringAsJavaString(env, item);
+ Py_DECREF(item);
(*env)->SetObjectArrayElement(env, array, i, value);
}
else {
+ Py_DECREF(item);
throwPythonException(env, "List item not a string");
return NULL;
}
for (i = 0; i < jlen; i++) {
PyObject *item = PySequence_GetItem(seq, i);
if (PyFloat_Check(item)) {
- double value = PyFloat_AsDouble(item);
+ jdouble value = PyFloat_AsDouble(item);
+ Py_DECREF(item);
(*env)->SetDoubleArrayRegion(env, array, i, 1, &value);
}
else {
+ Py_DECREF(item);
throwPythonException(env, "List item not a floating point value");
return NULL;
}
for (i = 0; i < jlen; i++) {
PyObject *item = PySequence_GetItem(seq, i);
jobject object = pythonObjectAsObject(env, item);
+ Py_DECREF(item);
(*env)->SetObjectArrayElement(env, array, i, object);
}
PyObject *item = PySequence_GetItem(seq, i);
if (PyBool_Check(item)) {
jboolean value = item == Py_True;
+ Py_DECREF(item);
(*env)->SetBooleanArrayRegion(env, array, i, 1, &value);
}
else {
+ Py_DECREF(item);
throwPythonException(env, "List item not a boolean");
return NULL;
}
PyObject *item = PySequence_GetItem(seq, i);
if (PyLong_Check(item)) {
jint value = PyLong_AsLong(item);
+ Py_DECREF(item);
(*env)->SetIntArrayRegion(env, array, i, 1, &value);
}
else {
+ Py_DECREF(item);
throwPythonException(env, "List item not an integer");
return NULL;
}
PyObject *item = PySequence_GetItem(seq, i);
if (PyLong_Check(item)) {
jlong value = PyLong_AsLongLong(item);
+ Py_DECREF(item);
(*env)->SetLongArrayRegion(env, array, i, 1, &value);
}
else {
+ Py_DECREF(item);
throwPythonException(env, "List item not an integer");
return NULL;
}
PyObject *formatExc = NULL, *args = NULL;
PyObject *tracebackModule = PyImport_ImportModule("traceback");
if (!tracebackModule) {
+ fputs("Python: No traceback module\n", stderr);
return NULL;
}
+ PyErr_NormalizeException(&exceptionType, &exception, &traceback);
+
if (exception && traceback) {
formatExc = PyDict_GetItemString(PyModule_GetDict(tracebackModule), "format_exception");
args = PyTuple_Pack(3, exceptionType, exception, traceback);
args = PyTuple_Pack(2, exceptionType, exception);
}
- Py_DECREF(tracebackModule);
-
if (formatExc != NULL && args != NULL) {
PyObject *result = PyObject_CallObject(formatExc, args);
+ if (!result) {
+ fputs("Python: No result from format_exception\n", stderr);
+ // Fallback to a direct string representation of the exception object
+ result = PyObject_Str(exception);
+ }
Py_XDECREF(args);
- Py_XDECREF(formatExc);
+ // Py_XDECREF(formatExc) - Borrowed reference
+ Py_DECREF(tracebackModule);
+
return result;
}
else {
+ if (!formatExc) fputs("Python: No format_exception\n", stderr);
+
Py_XDECREF(args);
- Py_XDECREF(formatExc);
+ // Py_XDECREF(formatExc) - Borrowed reference
+ Py_DECREF(tracebackModule);
+
return NULL;
}
}
+static void throwExceptionType(JNIEnv *env, PyObject *exceptionType) {
+ PyObject *ty_name = exceptionType ? PyObject_GetAttrString(exceptionType, "__name__") : NULL;
+ PyObject *str = ty_name ? PyUnicode_AsEncodedString(ty_name, "utf-8", "ignore") : NULL;
+
+ throwPythonException(env, str ? PyBytes_AsString(str) : "Internal error - no exception type");
+
+ Py_XDECREF(str);
+ Py_XDECREF(ty_name);
+}
+
JNIEXPORT jint JNICALL
Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
JNIEnv *env, jobject thisObj, jlong contextID, jstring statement) {
currentEnv = env;
{
- PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals);
-
+ // PyObject *result = PyRun_String(utfchars, Py_file_input, globals, globals); - Not available in Py_LIMITED_API
+ PyObject *code = Py_CompileString(utfchars, "SCL_INPUT", Py_file_input);
+ PyObject *result = code ? PyEval_EvalCode(code,globals, globals) : NULL;
PyObject *exceptionType = PyErr_Occurred();
+
if (exceptionType != NULL) {
PyObject *exception, *traceback, *message;
PyErr_Fetch(&exceptionType, &exception, &traceback);
message = getExceptionMessage(exceptionType, exception, traceback);
if (message != NULL) {
- PyObject *emptyStr = PyUnicode_FromString("");
- PyObject *joined = PyUnicode_Join(emptyStr, message);
- char *messageStr = PyUnicode_AsUTF8(joined);
- throwPythonException(env, messageStr);
- Py_DECREF(joined);
- Py_DECREF(emptyStr);
+ if (PyList_Check(message)) {
+ PyObject *emptyStr = PyUnicode_FromString("");
+ PyObject *temp = PyUnicode_Join(emptyStr, message);
+ if (temp) {
+ Py_DECREF(message);
+ message = temp;
+ }
+
+ Py_DECREF(emptyStr);
+ }
+
+ if (!PyUnicode_Check(message)) {
+ PyObject *temp = PyObject_Str(message);
+ if (temp) {
+ Py_DECREF(message);
+ message = temp;
+ }
+ }
+
+ PyObject* str = PyUnicode_AsEncodedString(message, "utf-8", "ignore");
Py_DECREF(message);
+
+ if (str != NULL) {
+ throwPythonException(env, PyBytes_AsString(str));
+ Py_DECREF(str);
+ }
+ else {
+ fputs("Python: Encoding message string failed\n", stderr);
+ throwExceptionType(env, exceptionType);
+ }
}
else {
- PyTypeObject
- *ty = (PyTypeObject *)exceptionType;
- throwPythonException(
- env, ty ? ty->tp_name
- : "Internal error, null exception type");
+ fputs("Python: No exception message\n", stderr);
+ throwExceptionType(env, exceptionType);
}
-
- Py_XDECREF(exceptionType);
- Py_XDECREF(exception);
- Py_XDECREF(traceback);
}
+ Py_XDECREF(result);
+ Py_XDECREF(code);
+
PyEval_SaveThread();
(*env)->ReleaseStringUTFChars(env, statement, utfchars);
// Returns a borrowed reference.
static PyObject *getPythonValue(
JNIEnv *env, jlong contextID, jstring variableName) {
- PyObject *module = getModule(contextID);
+ PyObject *module = getModule(contextID);
PyObject *pythonName = getPythonString(env, variableName);
PyObject *value = PyDict_GetItem(PyModule_GetDict(module), pythonName);