From a05006a0b312bc30158d9e2f30b434e89e18e2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Mon, 11 May 2020 23:51:58 +0200 Subject: [PATCH 1/2] Allow implementation of python plugin as whole module. --- src/proxy/proxypython.cpp | 18 +++++++++++++++--- src/runner/pythonrunner.cpp | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/proxy/proxypython.cpp b/src/proxy/proxypython.cpp index 2c931c6..4f4ae88 100644 --- a/src/proxy/proxypython.cpp +++ b/src/proxy/proxypython.cpp @@ -28,7 +28,6 @@ along with python proxy plugin. If not, see . #include #include "resource.h" - using namespace MOBase; @@ -214,11 +213,24 @@ QList ProxyPython::settings() const QStringList ProxyPython::pluginList(const QString &pluginPath) const { - QDirIterator iter(pluginPath, QStringList("*.py")); + QDir dir(pluginPath); + dir.setFilter(dir.filter() | QDir::NoDotAndDotDot); + QDirIterator iter(dir); + // Note: We put python script (.py) and directory names, not the __init__.py + // files in those since it is easier for the runner to import them. QStringList result; while (iter.hasNext()) { - result.append(iter.next()); + QString name = iter.next(); + QFileInfo info = iter.fileInfo(); + + if (info.isFile() && name.endsWith(".py")) { + result.append(name); + } + else if (info.isDir() && QDir(info.absoluteFilePath()).exists("__init__.py")) { + result.append(name); + // result.append(info.baseName()); + } } return result; diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index 8fdd89c..a2eeabd 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -44,6 +44,11 @@ public: private: void initPath(); + + /** + * @brief Ensure that the given folder is in sys.path. + */ + void ensureFolderInPath(QString folder); private: std::map m_PythonObjects; @@ -1340,6 +1345,17 @@ void PythonRunner::initPath() Py_SetPath(paths.join(';').toStdWString().c_str()); } +void PythonRunner::ensureFolderInPath(QString folder) { + bpy::object sys = bpy::import("sys"); + bpy::list sysPath = bpy::extract(sys.attr("path")); + + // Converting to QStringList for Qt::CaseInsensitive and because .index() + // raise an exception: + QStringList currentPath = bpy::extract(sysPath); + if (!currentPath.contains(folder, Qt::CaseInsensitive)) { + sysPath.insert(0, folder); + } +} QList PythonRunner::instantiate(const QString &pluginName) { @@ -1352,12 +1368,22 @@ QList PythonRunner::instantiate(const QString &pluginName) moduleNamespace["sys"] = sys; moduleNamespace["mobase"] = bpy::import("mobase"); - std::string temp = ToString(pluginName); - if (handled_exec_file(temp.c_str(), moduleNamespace)) { - reportPythonError(); - return QList(); + if (pluginName.endsWith(".py")) { + std::string temp = ToString(pluginName); + if (handled_exec_file(temp.c_str(), moduleNamespace)) { + reportPythonError(); + return QList(); + } + m_PythonObjects[pluginName] = moduleNamespace["createPlugin"](); + } + else { + // Retrieve the module name: + QStringList parts = pluginName.split("/"); + std::string moduleName = ToString(parts.takeLast()); + ensureFolderInPath(parts.join("/")); + bpy::object createPlugin = bpy::import(moduleName.c_str()).attr("createPlugin"); + m_PythonObjects[pluginName] = createPlugin(); } - m_PythonObjects[pluginName] = moduleNamespace["createPlugin"](); bpy::object pluginObj = m_PythonObjects[pluginName]; QList interfaceList; From d70942efa1b33b12feefc62ca72858affa6307c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Capelle?= Date: Tue, 19 May 2020 17:58:44 +0200 Subject: [PATCH 2/2] Rollback to setGameName instead of setGamePlugin for mod interface. --- src/runner/pythonrunner.cpp | 2 +- src/runner/uibasewrappers.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index 0d9b6cc..52f4ef5 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -995,7 +995,7 @@ BOOST_PYTHON_MODULE(mobase) .def("addCategory", bpy::pure_virtual(&IModInterface::addCategory)) .def("removeCategory", bpy::pure_virtual(&IModInterface::removeCategory)) .def("categories", bpy::pure_virtual(&IModInterface::categories)) - .def("setGamePlugin", bpy::pure_virtual(&IModInterface::setGamePlugin)) + .def("setGameName", bpy::pure_virtual(&IModInterface::setGameName)) .def("setName", bpy::pure_virtual(&IModInterface::setName)) .def("remove", bpy::pure_virtual(&IModInterface::remove)) ; diff --git a/src/runner/uibasewrappers.h b/src/runner/uibasewrappers.h index bab65bb..d51aa3f 100644 --- a/src/runner/uibasewrappers.h +++ b/src/runner/uibasewrappers.h @@ -445,7 +445,7 @@ struct IModInterfaceWrapper: MOBase::IModInterface, boost::python::wrapperget_override("setNexusID")(nexusID); } virtual void setInstallationFile(const QString &fileName) override { this->get_override("setInstallationFile")(fileName); } virtual void addNexusCategory(int categoryID) override { this->get_override("addNexusCategory")(categoryID); } - virtual void setGamePlugin(const MOBase::IPluginGame *gamePlugin) override { this->get_override("setGamePlugin")(gamePlugin); } + virtual void setGameName(const QString& gameName) override { this->get_override("setGameName")(gameName); } virtual bool setName(const QString &name) override { return this->get_override("setName")(name); } virtual bool remove() override { return this->get_override("remove")(); } virtual void addCategory(const QString &categoryName) override { this->get_override("addCategory")(categoryName); }