]> gerrit.simantics Code Review - simantics/python.git/blobdiff - org.simantics.pythonlink.win32.x86_64/src/sclpy.c
Several updates to Pyhthon-link behaviour.
[simantics/python.git] / org.simantics.pythonlink.win32.x86_64 / src / sclpy.c
index 762df28e988aaee4b451efe8dfe5f788ccbf304e..b2308bcdd3b4af57192c0fbd5a3dfa1ad6801e9f 100644 (file)
@@ -1,14 +1,15 @@
-///////////////////////////////////////////////////////
-//                                                   //
-//   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"
 
@@ -49,7 +50,7 @@ static PyObject *
 writeToSCL(PyObject *self, PyObject *args)
 {
     if (currentEnv != NULL && sclWriter != NULL) {
-               Py_UNICODE *what;
+       wchar_t *what;
                Py_ssize_t length;
        JNIEnv *env = currentEnv;
 
@@ -109,7 +110,7 @@ static PyMethodDef sclWriterMethods[] = {
 JNIEXPORT void JNICALL
 Java_org_simantics_pythonlink_PythonContext_initializePython(
         JNIEnv *env, jobject thisObj, jobject writer) {
-    Py_Initialize();
+    Py_InitializeEx(0);
 
     {
        static struct PyModuleDef moduledef = {
@@ -988,9 +989,12 @@ static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exceptio
        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);
@@ -1000,21 +1004,40 @@ static PyObject *getExceptionMessage(PyObject *exceptionType, PyObject *exceptio
                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) {
@@ -1032,7 +1055,9 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
                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) {
@@ -1041,27 +1066,46 @@ Java_org_simantics_pythonlink_PythonContext_executePythonStatementImpl(
 
                                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);