From c658b396bc200a67af965bcc34848033c222dd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Thu, 26 May 2022 19:39:28 +0200 Subject: [PATCH] Properly load plugins. --- src/proxy/proxypython.cpp | 21 +++++++++++---------- src/proxy/proxypython.h | 2 +- src/runner/pythonrunner.cpp | 31 +++++++++++++++---------------- src/runner/pythonrunner.h | 5 +++-- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/proxy/proxypython.cpp b/src/proxy/proxypython.cpp index 8cfc3e3..f8d244e 100644 --- a/src/proxy/proxypython.cpp +++ b/src/proxy/proxypython.cpp @@ -120,17 +120,18 @@ QList> 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> 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); } } } diff --git a/src/proxy/proxypython.h b/src/proxy/proxypython.h index a6f239a..ffb088c 100644 --- a/src/proxy/proxypython.h +++ b/src/proxy/proxypython.h @@ -58,7 +58,7 @@ private: HMODULE m_RunnerLib; std::unique_ptr m_Runner; std::unordered_map> + std::vector>> m_ExtensionModules; }; diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index 3fb87ae..59a6be7 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -36,8 +36,10 @@ namespace mo2::python { PythonRunner() = default; ~PythonRunner() = default; - QList> load(std::filesystem::path const& pythonModule) override; - void unload(std::filesystem::path const& pythonModule) override; + QList> 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 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> PythonRunner::load(const std::filesystem::path& pythonModule) + QList> 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, diff --git a/src/runner/pythonrunner.h b/src/runner/pythonrunner.h index 0664bef..0d1c049 100644 --- a/src/runner/pythonrunner.h +++ b/src/runner/pythonrunner.h @@ -24,8 +24,9 @@ namespace mo2::python { class IPythonRunner { public: virtual QList> - 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 //