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] 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;