From cd89e937e9c4ee28b3d575a75a19ab2d75a1ed20 Mon Sep 17 00:00:00 2001 From: bdieterm <119257544+bdieterm@users.noreply.github.com> Date: Sun, 2 Jun 2024 11:19:45 +0200 Subject: [PATCH] Core: fix import of FreeCAD in a Python 3.12 interpreter Importing FreeCAD as a module in a normal Python interpreter (e.g. /usr/bin/python3) stopped working with Python 3.12 (but works normally with Python 3.11). When executing "import FreeCAD as App", the interpreter crashes with "Fatal Python error: PyImport_AppendInittab: PyImport_AppendInittab() may not be called after Py_Initialize()". The check that causes the error message and abortion was introduced in Python 3.12 via https://github.com/python/cpython/commit/7f3a4b967cfb1596a3fda6c34f900f8586b16700 (and a typo in the error message fixed via) https://github.com/python/cpython/commit/35dd55005ee9aea2843eff7f514ee689a0995df8 --- src/App/Application.cpp | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 73c9165534..292ad972dc 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2554,9 +2554,34 @@ void Application::initConfig(int argc, char ** argv) mConfig["Debug"] = "0"; # endif - // init python - PyImport_AppendInittab ("FreeCAD", init_freecad_module); - PyImport_AppendInittab ("__FreeCADBase__", init_freecad_base_module); + if (!Py_IsInitialized()) { + // init python + PyImport_AppendInittab ("FreeCAD", init_freecad_module); + PyImport_AppendInittab ("__FreeCADBase__", init_freecad_base_module); + } + else { + // "import FreeCAD" in a normal Python 3.12 interpreter would raise + // Fatal Python error: PyImport_AppendInittab: + // PyImport_AppendInittab() may not be called after Py_Initialize() + // because the (external) interpreter is already initialized. + // Therefore we use a workaround as described in https://stackoverflow.com/a/57019607 + + PyObject *sysModules = PyImport_GetModuleDict(); + + const char *moduleName = "FreeCAD"; + PyImport_AddModule(moduleName); + ApplicationMethods = Application::Methods; + PyObject *pyModule = init_freecad_module(); + PyDict_SetItemString(sysModules, moduleName, pyModule); + Py_DECREF(pyModule); + + moduleName = "__FreeCADBase__"; + PyImport_AddModule(moduleName); + pyModule = init_freecad_base_module(); + PyDict_SetItemString(sysModules, moduleName, pyModule); + Py_DECREF(pyModule); + } + const char* pythonpath = Base::Interpreter().init(argc,argv); if (pythonpath) mConfig["PythonSearchPath"] = pythonpath;