| 154 | int PythonEventsInitialized = 0; |
| 155 | |
| 156 | bool PythonEventsInitialize(const std::string &szUserDataFolder) |
| 157 | { |
| 158 | // Reuse the existing sub-interpreter when restarting (e.g. after |
| 159 | // database restore). Creating a new sub-interpreter with |
| 160 | // Py_NewInterpreter after a previous Py_EndInterpreter triggers a |
| 161 | // write-access violation inside bind_gilstate_tstate on Python 3.13 |
| 162 | // due to stale per-thread GIL state in thread-local storage. |
| 163 | if (m_PyInterpreter) |
| 164 | { |
| 165 | _log.Debug(DEBUG_EVENTSYSTEM, "EventSystem - Python: Reusing existing sub-interpreter (%p)", m_PyInterpreter); |
| 166 | PythonEventsInitialized = 1; |
| 167 | m_ModuleInitialized = true; |
| 168 | return true; |
| 169 | } |
| 170 | |
| 171 | if (!Plugins::Py_LoadLibrary()) |
| 172 | { |
| 173 | _log.Log(LOG_STATUS, "EventSystem - Python: Failed dynamic library load, install the latest libpython3.x library " |
| 174 | "that is available for your platform."); |
| 175 | return false; |
| 176 | } |
| 177 | |
| 178 | if (!Plugins::Py_IsInitialized()) |
| 179 | { |
| 180 | _log.Log(LOG_STATUS, "EventSystem - Python: Python is not initialized."); |
| 181 | return false; |
| 182 | } |
| 183 | |
| 184 | PyThreadState *pMainThread = (PyThreadState *)m_mainworker.m_pluginsystem.PythonThread(); |
| 185 | if (!pMainThread) |
| 186 | { |
| 187 | _log.Log(LOG_ERROR, "EventSystem - Python: Main thread state is not available."); |
| 188 | return false; |
| 189 | } |
| 190 | _log.Debug(DEBUG_EVENTSYSTEM, "EventSystem - Python: Acquiring GIL for event interpreter initialization (thread=%p)", pMainThread); |
| 191 | PyEval_RestoreThread(pMainThread); |
| 192 | _log.Debug(DEBUG_EVENTSYSTEM, "EventSystem - Python: Creating new sub-interpreter"); |
| 193 | m_PyInterpreter = Py_NewInterpreter(); |
| 194 | if (!m_PyInterpreter) |
| 195 | { |
| 196 | _log.Log(LOG_ERROR, "EventSystem - Python: Failed to create interpreter."); |
| 197 | PyEval_SaveThread(); |
| 198 | return false; |
| 199 | } |
| 200 | |
| 201 | std::string ssPath; |
| 202 | #ifdef WIN32 |
| 203 | ssPath = szUserDataFolder + "scripts\\python\\;"; |
| 204 | #else |
| 205 | ssPath = szUserDataFolder + "scripts/python/:"; |
| 206 | #endif |
| 207 | |
| 208 | std::wstring sPath = std::wstring(ssPath.begin(), ssPath.end()); |
| 209 | |
| 210 | sPath += Plugins::Py_GetPath(); |
| 211 | Plugins::PySys_SetPath((wchar_t*)sPath.c_str()); |
| 212 | |
| 213 | PythonEventsInitialized = 1; |
no test coverage detected