fix issues in teardown.

This commit is contained in:
Michael Zanetti 2020-08-31 19:29:35 +02:00
parent d4889b5b78
commit 16c4fa3345
6 changed files with 30 additions and 13 deletions

View File

@ -21,6 +21,7 @@ typedef struct {
static int PyNymeaLoggingHandler_init(PyNymeaLoggingHandler *self, PyObject *args, PyObject */*kwds*/) static int PyNymeaLoggingHandler_init(PyNymeaLoggingHandler *self, PyObject *args, PyObject */*kwds*/)
{ {
qCDebug(dcPythonIntegrations()) << "+++ PyNymeaLoggingHandler";
char *category = nullptr; char *category = nullptr;
if (!PyArg_ParseTuple(args, "s", &category)) { if (!PyArg_ParseTuple(args, "s", &category)) {
qCWarning(dcPythonIntegrations()) << "PyNymeaLoggingHandler: Error parsing parameters"; qCWarning(dcPythonIntegrations()) << "PyNymeaLoggingHandler: Error parsing parameters";
@ -35,11 +36,11 @@ static int PyNymeaLoggingHandler_init(PyNymeaLoggingHandler *self, PyObject *arg
static void PyNymeaLoggingHandler_dealloc(PyNymeaLoggingHandler * self) static void PyNymeaLoggingHandler_dealloc(PyNymeaLoggingHandler * self)
{ {
qCDebug(dcPythonIntegrations()) << "--- PyNymeaLoggingHandler";
free(self->category); free(self->category);
Py_TYPE(self)->tp_free(self); Py_TYPE(self)->tp_free(self);
} }
static PyObject * PyNymeaLoggingHandler_log(PyNymeaLoggingHandler* self, PyObject* args) static PyObject * PyNymeaLoggingHandler_log(PyNymeaLoggingHandler* self, PyObject* args)
{ {
QStringList strings; QStringList strings;

View File

@ -67,7 +67,6 @@ static PyTypeObject PyParamType = {
sizeof(PyParam), /* tp_basicsize */ sizeof(PyParam), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
(destructor)PyParam_dealloc,/* tp_dealloc */ (destructor)PyParam_dealloc,/* tp_dealloc */
}; };
static PyParam* PyParam_fromParam(const Param &param) static PyParam* PyParam_fromParam(const Param &param)

View File

@ -212,7 +212,6 @@ PythonIntegrationPlugin::~PythonIntegrationPlugin()
s_plugins.take(this); s_plugins.take(this);
Py_XDECREF(m_pluginModule); Py_XDECREF(m_pluginModule);
Py_XDECREF(m_logger);
Py_DECREF(m_nymeaModule); Py_DECREF(m_nymeaModule);
Py_EndInterpreter(m_threadState); Py_EndInterpreter(m_threadState);
@ -223,19 +222,33 @@ PythonIntegrationPlugin::~PythonIntegrationPlugin()
void PythonIntegrationPlugin::initPython() void PythonIntegrationPlugin::initPython()
{ {
Q_ASSERT_X(s_mainThreadState == nullptr, "PythonIntegrationPlugin::initPython()", "initPython() must be called exactly once."); Q_ASSERT_X(s_mainThreadState == nullptr, "PythonIntegrationPlugin::initPython()", "initPython() must be called exactly once before calling deinitPython().");
PyImport_AppendInittab("nymea", PyInit_nymea); // Only modify the init tab once (initPython() might be called again after calling deinitPython())
static bool initTabPrepared = false;
if (!initTabPrepared) {
PyImport_AppendInittab("nymea", PyInit_nymea);
initTabPrepared = true;
}
// Initialize the python engine and fire up threading support
Py_InitializeEx(0); Py_InitializeEx(0);
PyEval_InitThreads(); PyEval_InitThreads();
// Store the main thread state and release the GIL // Store the main thread state and release the GIL
s_mainThreadState = PyEval_SaveThread(); s_mainThreadState = PyEval_SaveThread();
} }
void PythonIntegrationPlugin::deinitPython() void PythonIntegrationPlugin::deinitPython()
{ {
// Restore our main thread state
PyEval_RestoreThread(s_mainThreadState); PyEval_RestoreThread(s_mainThreadState);
Py_Finalize();
// Tear down the python engine
Py_FinalizeEx();
// Our main thread state is destroyed now
s_mainThreadState = nullptr;
} }
bool PythonIntegrationPlugin::loadScript(const QString &scriptFile) bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
@ -244,18 +257,18 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
QFile metaDataFile(fi.absolutePath() + "/" + fi.baseName() + ".json"); QFile metaDataFile(fi.absolutePath() + "/" + fi.baseName() + ".json");
if (!metaDataFile.open(QFile::ReadOnly)) { if (!metaDataFile.open(QFile::ReadOnly)) {
qCWarning(dcThingManager()) << "Error opening metadata file:" << metaDataFile.fileName(); qCWarning(dcPythonIntegrations()) << "Error opening metadata file:" << metaDataFile.fileName();
return false; return false;
} }
QJsonParseError error; QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(metaDataFile.readAll(), &error); QJsonDocument jsonDoc = QJsonDocument::fromJson(metaDataFile.readAll(), &error);
if (error.error != QJsonParseError::NoError) { if (error.error != QJsonParseError::NoError) {
qCWarning(dcThingManager()) << "Error parsing metadata file:" << error.errorString(); qCWarning(dcPythonIntegrations()) << "Error parsing metadata file:" << error.errorString();
return false; return false;
} }
setMetaData(PluginMetadata(jsonDoc.object())); setMetaData(PluginMetadata(jsonDoc.object()));
if (!metadata().isValid()) { if (!metadata().isValid()) {
qCWarning(dcThingManager()) << "Plugin metadata not valid for plugin:" << scriptFile; qCWarning(dcPythonIntegrations()) << "Plugin metadata not valid for plugin:" << scriptFile;
return false; return false;
} }
@ -314,8 +327,11 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile)
PyObject *args = Py_BuildValue("(s)", category.toUtf8().data()); PyObject *args = Py_BuildValue("(s)", category.toUtf8().data());
PyNymeaLoggingHandler *logger = reinterpret_cast<PyNymeaLoggingHandler*>(PyObject_CallObject((PyObject*)&PyNymeaLoggingHandlerType, args)); PyNymeaLoggingHandler *logger = reinterpret_cast<PyNymeaLoggingHandler*>(PyObject_CallObject((PyObject*)&PyNymeaLoggingHandlerType, args));
Py_DECREF(args); Py_DECREF(args);
PyModule_AddObject(m_pluginModule, "logger", reinterpret_cast<PyObject*>(logger)); int loggerAdded = PyModule_AddObject(m_pluginModule, "logger", reinterpret_cast<PyObject*>(logger));
m_logger = (PyObject*)logger; if (loggerAdded != 0) {
qCWarning(dcPythonIntegrations()) << "Failed to add the logger object";
Py_DECREF(logger);
}
// Export metadata ids into module // Export metadata ids into module
exportIds(); exportIds();

View File

@ -76,8 +76,6 @@ private:
// The imported plugin module (the plugin.py) // The imported plugin module (the plugin.py)
PyObject *m_pluginModule = nullptr; PyObject *m_pluginModule = nullptr;
PyObject *m_logger = nullptr;
// A map of plugin instances to plugin python scripts/modules // A map of plugin instances to plugin python scripts/modules
// Make sure to hold the GIL when accessing this. // Make sure to hold the GIL when accessing this.
static QHash<PythonIntegrationPlugin*, PyObject*> s_plugins; static QHash<PythonIntegrationPlugin*, PyObject*> s_plugins;

View File

@ -161,6 +161,7 @@ void TestIntegrations::initTestCase()
"Tests.debug=true\n" "Tests.debug=true\n"
"Mock.debug=true\n" "Mock.debug=true\n"
"Translations.debug=true\n" "Translations.debug=true\n"
"PythonIntegrations.debug=true\n"
); );
// Adding an async mock to be used in tests below // Adding an async mock to be used in tests below

View File

@ -414,7 +414,9 @@ void NymeaTestBase::waitForDBSync()
void NymeaTestBase::restartServer() void NymeaTestBase::restartServer()
{ {
// Destroy and recreate the core instance... // Destroy and recreate the core instance...
qCDebug(dcTests()) << "Tearing down server instance";
NymeaCore::instance()->destroy(); NymeaCore::instance()->destroy();
qCDebug(dcTests()) << "Restarting server instance";
NymeaCore::instance()->init(); NymeaCore::instance()->init();
QSignalSpy coreSpy(NymeaCore::instance(), SIGNAL(initialized())); QSignalSpy coreSpy(NymeaCore::instance(), SIGNAL(initialized()));
coreSpy.wait(); coreSpy.wait();