Blob Blame History Raw
From 1ae55905ba7e89278bf656ebcc57ea1088e8fa44 Mon Sep 17 00:00:00 2001
From: wmayer <wmayer@users.sourceforge.net>
Date: Fri, 1 Jul 2022 17:54:50 +0200
Subject: [PATCH] Py: make FreeCAD to compile with Py3.11

---
 src/Base/ConsoleObserver.cpp |  6 ++++
 src/Base/Interpreter.cpp     | 56 ++++++++++++++++++++++++++++++++++++
 src/Base/PyObjectBase.cpp    |  4 +++
 src/Base/PyTools.c           | 10 ++++++-
 src/Gui/Command.cpp          |  7 +++++
 src/Gui/PythonDebugger.cpp   | 17 +++++++++--
 6 files changed, 97 insertions(+), 3 deletions(-)

diff --git a/src/Base/ConsoleObserver.cpp b/src/Base/ConsoleObserver.cpp
index c6428a7f18be..ab3b3e9157b1 100644
--- a/src/Base/ConsoleObserver.cpp
+++ b/src/Base/ConsoleObserver.cpp
@@ -266,7 +266,13 @@ std::stringstream &LogLevel::prefix(std::stringstream &str, const char *src, int
         PyFrameObject* frame = PyEval_GetFrame();
         if (frame) {
             line = PyFrame_GetLineNumber(frame);
+#if PY_VERSION_HEX < 0x030b0000
             src = PyUnicode_AsUTF8(frame->f_code->co_filename);
+#else
+            PyCodeObject* code = PyFrame_GetCode(frame);
+            src = PyUnicode_AsUTF8(code->co_filename);
+            Py_DECREF(code);
+#endif
         }
     }
     if (print_src && src && src[0]) {
diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp
index 2bacea30cbb7..5a476094b749 100644
--- a/src/Base/Interpreter.cpp
+++ b/src/Base/Interpreter.cpp
@@ -523,6 +523,7 @@ void InterpreterSingleton::addPythonPath(const char* Path)
     list.append(Py::String(Path));
 }
 
+#if PY_VERSION_HEX < 0x030b0000
 const char* InterpreterSingleton::init(int argc,char *argv[])
 {
     if (!Py_IsInitialized()) {
@@ -565,6 +566,61 @@ const char* InterpreterSingleton::init(int argc,char *argv[])
     PyGILStateLocker lock;
     return Py_EncodeLocale(Py_GetPath(),nullptr);
 }
+#else
+namespace {
+void initInterpreter(int argc,char *argv[])
+{
+    PyStatus status;
+    PyConfig config;
+    PyConfig_InitPythonConfig(&config);
+
+    status = PyConfig_SetBytesArgv(&config, argc, argv);
+    if (PyStatus_Exception(status)) {
+        throw Base::RuntimeError("Failed to set config");
+    }
+
+    status = Py_InitializeFromConfig(&config);
+    if (PyStatus_Exception(status)) {
+        throw Base::RuntimeError("Failed to init from config");
+    }
+
+    PyConfig_Clear(&config);
+
+    Py_Initialize();
+    const char* virtualenv = getenv("VIRTUAL_ENV");
+    if (virtualenv) {
+        PyRun_SimpleString(
+            "# Check for virtualenv, and activate if present.\n"
+            "# See https://virtualenv.pypa.io/en/latest/userguide/#using-virtualenv-without-bin-python\n"
+            "import os\n"
+            "import sys\n"
+            "base_path = os.getenv(\"VIRTUAL_ENV\")\n"
+            "if not base_path is None:\n"
+            "    activate_this = os.path.join(base_path, \"bin\", \"activate_this.py\")\n"
+            "    exec(open(activate_this).read(), {'__file__':activate_this})\n"
+        );
+    }
+}
+}
+const char* InterpreterSingleton::init(int argc,char *argv[])
+{
+    try {
+        if (!Py_IsInitialized()) {
+            initInterpreter(argc, argv);
+
+            PythonStdOutput::init_type();
+            this->_global = PyEval_SaveThread();
+        }
+
+        PyGILStateLocker lock;
+        return Py_EncodeLocale(Py_GetPath(),nullptr);
+    }
+    catch (const Base::Exception& e) {
+        e.ReportException();
+        throw;
+    }
+}
+#endif
 
 void InterpreterSingleton::replaceStdOutput()
 {
diff --git a/src/Base/PyObjectBase.cpp b/src/Base/PyObjectBase.cpp
index 773a61b259b3..343ab26999f6 100644
--- a/src/Base/PyObjectBase.cpp
+++ b/src/Base/PyObjectBase.cpp
@@ -60,7 +60,11 @@ PyObjectBase::PyObjectBase(void* p,PyTypeObject *T)
   , baseProxy(nullptr)
   , attrDict(nullptr)
 {
+#if PY_VERSION_HEX < 0x030b0000
     Py_TYPE(this) = T;
+#else
+    Py_SET_TYPE(this, T);
+#endif
     _Py_NewReference(this);
 #ifdef FC_LOGPYOBJECTS
     Base::Console().Log("PyO+: %s (%p)\n",T->tp_name, this);
diff --git a/src/Base/PyTools.c b/src/Base/PyTools.c
index 71569e26a200..492d0c8563a4 100644
--- a/src/Base/PyTools.c
+++ b/src/Base/PyTools.c
@@ -15,8 +15,10 @@ is provided on an as is basis, without warranties of any kind.
 #include <string.h>
 #include <assert.h>
 #include <compile.h>
-#include <eval.h>
 #include <frameobject.h>
+#if PY_VERSION_HEX < 0x030b0000
+#include <eval.h>
+#endif
 
 
 /*****************************************************************************
@@ -310,7 +312,13 @@ void PP_Fetch_Error_Text()
         if(!frame) 
             return;
         int line = PyFrame_GetLineNumber(frame);
+#if PY_VERSION_HEX < 0x030b0000
         const char *file = PyUnicode_AsUTF8(frame->f_code->co_filename);
+#else
+        PyCodeObject* code = PyFrame_GetCode(frame);
+        const char *file = PyUnicode_AsUTF8(code->co_filename);
+        Py_DECREF(code);
+#endif
 #ifdef FC_OS_WIN32
         const char *_f = strstr(file, "\\src\\");
 #else
diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp
index c9568e8f0e69..cf555439fcd2 100644
--- a/src/Gui/Command.cpp
+++ b/src/Gui/Command.cpp
@@ -657,8 +657,15 @@ void Command::printPyCaller() {
     if(!frame)
         return;
     int line = PyFrame_GetLineNumber(frame);
+#if PY_VERSION_HEX < 0x030b0000
     const char *file = PyUnicode_AsUTF8(frame->f_code->co_filename);
     printCaller(file?file:"<no file>",line);
+#else
+    PyCodeObject* code = PyFrame_GetCode(frame);
+    const char* file = PyUnicode_AsUTF8(code->co_filename);
+    printCaller(file?file:"<no file>",line);
+    Py_DECREF(code);
+#endif
 }
 
 void Command::printCaller(const char *file, int line) {
diff --git a/src/Gui/PythonDebugger.cpp b/src/Gui/PythonDebugger.cpp
index 7e731a9dd6af..cd44e9b1c233 100644
--- a/src/Gui/PythonDebugger.cpp
+++ b/src/Gui/PythonDebugger.cpp
@@ -563,6 +563,14 @@ void PythonDebugger::hideDebugMarker(const QString& fn)
     }
 }
 
+#if PY_VERSION_HEX < 0x030900B1
+static PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
+{
+    Py_INCREF(frame->f_code);
+    return frame->f_code;
+}
+#endif
+
 // http://www.koders.com/cpp/fidBA6CD8A0FE5F41F1464D74733D9A711DA257D20B.aspx?s=PyEval_SetTrace
 // http://code.google.com/p/idapython/source/browse/trunk/python.cpp
 // http://www.koders.com/cpp/fid191F7B13CF73133935A7A2E18B7BF43ACC6D1784.aspx?s=PyEval_SetTrace
@@ -578,7 +586,9 @@ int PythonDebugger::tracer_callback(PyObject *obj, PyFrameObject *frame, int wha
 
     //no = frame->f_tstate->recursion_depth;
     //std::string funcname = PyString_AsString(frame->f_code->co_name);
-    QString file = QString::fromUtf8(PyUnicode_AsUTF8(frame->f_code->co_filename));
+    PyCodeObject* code = PyFrame_GetCode(frame);
+    QString file = QString::fromUtf8(PyUnicode_AsUTF8(code->co_filename));
+    Py_DECREF(code);
     switch (what) {
     case PyTrace_CALL:
         self->depth++;
@@ -592,7 +602,10 @@ int PythonDebugger::tracer_callback(PyObject *obj, PyFrameObject *frame, int wha
             //PyObject *str;
             //str = PyObject_Str(frame->f_code->co_filename);
             //no = frame->f_lineno;
-            int line = PyCode_Addr2Line(frame->f_code, frame->f_lasti);
+            PyCodeObject* f_code = PyFrame_GetCode(frame);
+            int f_lasti = PyFrame_GetLineNumber(frame);
+            int line = PyCode_Addr2Line(f_code, f_lasti);
+            Py_DECREF(f_code);
             //if (str) {
             //    Base::Console().Message("PROFILING: %s:%d\n", PyString_AsString(str), frame->f_lineno);
             //    Py_DECREF(str);