Fix issue with unloading single .py file and fix tests.

This commit is contained in:
Mikaël Capelle
2024-08-09 22:06:12 +02:00
parent c658b396bc
commit 9b1793c726
7 changed files with 59 additions and 39 deletions
+10 -1
View File
@@ -246,12 +246,13 @@ namespace mo2::python {
{
py::gil_scoped_acquire lock;
// At this point, the identifier is the full path to the module.
// at this point, the identifier is the full path to the module.
QDir folder(modulePath);
// we want to "unload" (remove from sys.modules) modules that come
// from this plugin (whose __path__ points under this module,
// including the module of the plugin itself)
//
py::object sys = py::module_::import("sys");
py::dict modules = sys.attr("modules");
py::list keys = modules.attr("keys")();
@@ -269,6 +270,14 @@ namespace mo2::python {
}
}
}
// for simple Python file - not really used anymore, but actually used in
// testing - we need to remove using the module name
//
py::str pyModuleName(moduleName);
if (modules.contains(pyModuleName)) {
PyDict_DelItem(modules.ptr(), pyModuleName.ptr());
}
}
bool PythonRunner::isInitialized() const
+10 -9
View File
@@ -16,19 +16,20 @@ using ::testing::ElementsAre;
TEST(IPluginDiagnose, Simple)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
// load objects
const auto objects = runner->load(plugins_folder + "/dummy-diagnose.py");
EXPECT_EQ(objects.size(), 3);
const auto objects =
runner->load("dummy_diagnose", plugins_folder / "dummy-diagnose.py");
ASSERT_EQ(objects.size(), 2);
// load the first IPluginDiagnose
{
IPluginDiagnose* plugin = qobject_cast<IPluginDiagnose*>(objects[0]);
EXPECT_NE(plugin, nullptr);
IPluginDiagnose* plugin = qobject_cast<IPluginDiagnose*>(objects[0][0]);
ASSERT_NE(plugin, nullptr);
ASSERT_THAT(plugin->activeProblems(), ElementsAre(1, 2));
EXPECT_EQ(plugin->shortDescription(1), "short-1");
@@ -41,8 +42,8 @@ TEST(IPluginDiagnose, Simple)
// load the second one (this is cast before IPluginGame so should be before)
{
IPluginDiagnose* plugin = qobject_cast<IPluginDiagnose*>(objects[1]);
EXPECT_NE(plugin, nullptr);
IPluginDiagnose* plugin = qobject_cast<IPluginDiagnose*>(objects[1][0]);
ASSERT_NE(plugin, nullptr);
ASSERT_THAT(plugin->activeProblems(), ElementsAre(5, 7));
EXPECT_EQ(plugin->shortDescription(5), "short-5");
@@ -55,7 +56,7 @@ TEST(IPluginDiagnose, Simple)
// load the game plugin
{
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[2]);
EXPECT_NE(plugin, nullptr);
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[1][1]);
ASSERT_NE(plugin, nullptr);
}
}
+14 -11
View File
@@ -14,22 +14,24 @@ using namespace MOBase;
TEST(IPluginFileMapper, Simple)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
// load objects
const auto objects = runner->load(plugins_folder + "/dummy-filemapper.py");
EXPECT_EQ(objects.size(), 3);
const auto objects =
runner->load("dummy_filemapper", plugins_folder / "dummy-filemapper.py");
EXPECT_EQ(objects.size(), 2);
// load the first IPluginFileMapper
{
IPluginFileMapper* plugin = qobject_cast<IPluginFileMapper*>(objects[0]);
EXPECT_NE(plugin, nullptr);
ASSERT_EQ(objects[0].size(), 1);
IPluginFileMapper* plugin = qobject_cast<IPluginFileMapper*>(objects[0][0]);
ASSERT_NE(plugin, nullptr);
const auto m = plugin->mappings();
EXPECT_EQ(m.size(), 2);
ASSERT_EQ(m.size(), 2);
EXPECT_EQ(m[0].source, "the source");
EXPECT_EQ(m[0].destination, "the destination");
@@ -44,11 +46,12 @@ TEST(IPluginFileMapper, Simple)
// load the second one (this is cast before IPluginGame so should be before)
{
IPluginFileMapper* plugin = qobject_cast<IPluginFileMapper*>(objects[1]);
EXPECT_NE(plugin, nullptr);
ASSERT_EQ(objects[1].size(), 2);
IPluginFileMapper* plugin = qobject_cast<IPluginFileMapper*>(objects[1][0]);
ASSERT_NE(plugin, nullptr);
const auto m = plugin->mappings();
EXPECT_EQ(m.size(), 1);
ASSERT_EQ(m.size(), 1);
EXPECT_EQ(m[0].source, "the source");
EXPECT_EQ(m[0].destination, "the destination");
@@ -58,7 +61,7 @@ TEST(IPluginFileMapper, Simple)
// load the game plugin
{
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[2]);
EXPECT_NE(plugin, nullptr);
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[1][1]);
ASSERT_NE(plugin, nullptr);
}
}
+3 -3
View File
@@ -13,16 +13,16 @@ using namespace MOBase;
TEST(IPluginGame, Simple)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
// load objects
const auto objects = runner->load(plugins_folder + "/dummy-game.py");
const auto objects = runner->load("dummy_game", plugins_folder / "dummy-game.py");
EXPECT_EQ(objects.size(), 1);
// load the IPlugin
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[0]);
IPluginGame* plugin = qobject_cast<IPluginGame*>(objects[0][0]);
EXPECT_NE(plugin, nullptr);
}
+5 -3
View File
@@ -14,17 +14,19 @@ using namespace MOBase;
TEST(IPluginInstaller, Simple)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
// load objects
const auto objects = runner->load(plugins_folder + "/dummy-installer.py");
const auto objects =
runner->load("dummy_installer", plugins_folder / "dummy-installer.py");
EXPECT_EQ(objects.size(), 1);
// load the IPlugin
IPluginInstallerSimple* plugin = qobject_cast<IPluginInstallerSimple*>(objects[0]);
IPluginInstallerSimple* plugin =
qobject_cast<IPluginInstallerSimple*>(objects[0][0]);
EXPECT_NE(plugin, nullptr);
// basic tests
+4 -3
View File
@@ -12,17 +12,18 @@ using namespace MOBase;
TEST(IPlugin, Basic)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
// load objects
const auto objects = runner->load(plugins_folder + "/dummy-iplugin.py");
const auto objects =
runner->load("dummy_iplugin", plugins_folder / "dummy-iplugin.py");
EXPECT_EQ(objects.size(), 1);
// load the IPlugin
const IPlugin* plugin = qobject_cast<IPlugin*>(objects[0]);
const IPlugin* plugin = qobject_cast<IPlugin*>(objects[0][0]);
EXPECT_NE(plugin, nullptr);
EXPECT_EQ(plugin->author(), "The Author");
+13 -9
View File
@@ -7,38 +7,42 @@
TEST(Lifetime, Plugins)
{
const auto plugins_folder = QString(std::getenv("PLUGIN_DIR"));
const auto plugins_folder = std::filesystem::path(std::getenv("PLUGIN_DIR"));
auto runner = mo2::python::createPythonRunner();
runner->initialize();
{
const auto objects = runner->load(plugins_folder + "/dummy-iplugin.py");
const auto objects =
runner->load("dummy_iplugin", plugins_folder / "dummy-iplugin.py");
// we found one plugin
EXPECT_EQ(objects.size(), 1);
ASSERT_EQ(objects.size(), 1);
// check that deleting the object actually destroys it
bool destroyed = false;
QObject::connect(objects[0], &QObject::destroyed, [&destroyed]() {
QObject::connect(objects[0][0], &QObject::destroyed, [&destroyed]() {
destroyed = true;
});
delete objects[0];
delete objects[0][0];
EXPECT_EQ(destroyed, true);
runner->unload("dummy_iplugin", plugins_folder / "dummy-iplugin.py");
}
// same things but with a parent
{
QObject* dummy_parent = new QObject();
const auto objects = runner->load(plugins_folder + "/dummy-iplugin.py");
const auto objects =
runner->load("dummy_iplugin", plugins_folder / "dummy-iplugin.py");
// we found one plugin
EXPECT_EQ(objects.size(), 1);
objects[0]->setParent(dummy_parent);
ASSERT_EQ(objects.size(), 1);
objects[0][0]->setParent(dummy_parent);
// check that deleting the object actually destroys it
bool destroyed = false;
QObject::connect(objects[0], &QObject::destroyed, [&destroyed]() {
QObject::connect(objects[0][0], &QObject::destroyed, [&destroyed]() {
destroyed = true;
});
delete dummy_parent;