Properly load plugins.

This commit is contained in:
Mikaël Capelle
2024-08-09 22:06:06 +02:00
parent 8fa0d0ade8
commit c658b396bc
4 changed files with 30 additions and 29 deletions
+11 -10
View File
@@ -120,17 +120,18 @@ QList<QList<QObject*>> ProxyPython::load(const PluginExtension& extension)
return {};
}
// currently, only handle __init__.py directly in the folder
const auto pyIniFile = extension.directory() / "__init__.py";
if (!exists(pyIniFile)) {
if (extension.autodetect()) {
log::error("{}: automatic plugin detection is not supported for Python plugins",
extension.metadata().name());
return {};
}
m_ExtensionModules[&extension] = {pyIniFile};
m_ExtensionModules[&extension] = {};
QList<QList<QObject*>> plugins;
for (auto&& pythonModule : m_ExtensionModules[&extension]) {
plugins.append(m_Runner->load(pythonModule));
for (auto& [moduleName, modulePath] : extension.plugins()) {
m_ExtensionModules[&extension].push_back({moduleName, modulePath});
plugins.append(m_Runner->load(moduleName, modulePath));
}
return plugins;
@@ -143,8 +144,8 @@ void ProxyPython::unload(const PluginExtension& extension)
}
if (auto it = m_ExtensionModules.find(&extension); it != m_ExtensionModules.end()) {
for (auto&& pythonModule : it->second) {
m_Runner->unload(pythonModule);
for (auto& [moduleName, modulePath] : it->second) {
m_Runner->unload(moduleName, modulePath);
}
m_ExtensionModules.erase(it);
}
@@ -154,8 +155,8 @@ void ProxyPython::unloadAll()
{
if (m_Runner) {
for (auto& [ext, modules] : m_ExtensionModules) {
for (auto& pythonModule : modules) {
m_Runner->unload(pythonModule);
for (auto& [moduleName, modulePath] : modules) {
m_Runner->unload(moduleName, modulePath);
}
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ private:
HMODULE m_RunnerLib;
std::unique_ptr<mo2::python::IPythonRunner> m_Runner;
std::unordered_map<const MOBase::PluginExtension*,
std::vector<std::filesystem::path>>
std::vector<std::pair<std::string, std::filesystem::path>>>
m_ExtensionModules;
};
+15 -16
View File
@@ -36,8 +36,10 @@ namespace mo2::python {
PythonRunner() = default;
~PythonRunner() = default;
QList<QList<QObject*>> load(std::filesystem::path const& pythonModule) override;
void unload(std::filesystem::path const& pythonModule) override;
QList<QList<QObject*>> load(std::string_view moduleName,
std::filesystem::path const& modulePath) override;
void unload(std::string_view moduleName,
std::filesystem::path const& modulePath) override;
bool initialize(std::vector<std::filesystem::path> const& pythonPaths) override;
void addDllSearchPath(std::filesystem::path const& dllPath) override;
@@ -150,7 +152,8 @@ namespace mo2::python {
py::module_::import("os").attr("add_dll_directory")(absolute(dllPath));
}
QList<QList<QObject*>> PythonRunner::load(const std::filesystem::path& pythonModule)
QList<QList<QObject*>> PythonRunner::load(std::string_view name,
const std::filesystem::path& pythonModule)
{
py::gil_scoped_acquire lock;
@@ -160,24 +163,19 @@ namespace mo2::python {
auto sys = py::module_::import("sys");
auto importlib_util = py::module_::import("importlib.util");
// check the file type
const auto moduleName =
pythonModule.filename() == "__init__.py"
? pythonModule.parent_path().filename().u8string()
: pythonModule.filename().u8string();
// check if the module is already loaded
py::dict modules = sys.attr("modules");
py::module_ pymodule;
if (modules.contains(moduleName)) {
pymodule = modules[py::str(moduleName)];
if (modules.contains(name)) {
pymodule = modules[py::str(name)];
pymodule.reload();
}
else {
// load the module
auto spec = importlib_util.attr("find_spec")(moduleName, pythonModule);
pymodule = importlib_util.attr("module_from_spec")(spec);
sys.attr("modules")[py::str(moduleName)] = pymodule;
auto spec =
importlib_util.attr("spec_from_file_location")(name, pythonModule);
pymodule = importlib_util.attr("module_from_spec")(spec);
sys.attr("modules")[py::str(name)] = pymodule;
spec.attr("loader").attr("exec_module")(pymodule);
}
@@ -243,12 +241,13 @@ namespace mo2::python {
}
}
void PythonRunner::unload(const std::filesystem::path& pythonModule)
void PythonRunner::unload(std::string_view moduleName,
std::filesystem::path const& modulePath)
{
py::gil_scoped_acquire lock;
// At this point, the identifier is the full path to the module.
QDir folder(pythonModule);
QDir folder(modulePath);
// we want to "unload" (remove from sys.modules) modules that come
// from this plugin (whose __path__ points under this module,
+3 -2
View File
@@ -24,8 +24,9 @@ namespace mo2::python {
class IPythonRunner {
public:
virtual QList<QList<QObject*>>
load(std::filesystem::path const& pythonModule) = 0;
virtual void unload(std::filesystem::path const& pythonModule) = 0;
load(std::string_view moduleName, std::filesystem::path const& modulePath) = 0;
virtual void unload(std::string_view moduleName,
std::filesystem::path const& modulePath) = 0;
// initialize Python
//