From 4b4e4130c5ddfcde2dedcdee3324e56d23bf1780 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Fri, 6 Feb 2026 04:04:17 +0100 Subject: [PATCH 1/8] Plugin installation --- oqtopus/gui/plugin_widget.py | 150 ++++++++++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 10 deletions(-) diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index 8ae5b16..778c55b 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -1,7 +1,9 @@ import os import shutil +import tempfile +import zipfile -from qgis.PyQt.QtCore import QUrl +from qgis.PyQt.QtCore import QDir, QStandardPaths, QUrl from qgis.PyQt.QtGui import QDesktopServices from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox, QWidget @@ -13,7 +15,6 @@ class PluginWidget(QWidget, DIALOG_UI): - def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) @@ -83,14 +84,143 @@ def __installClicked(self): QtUtils.setFontItalic(self.info_label, True) return - QMessageBox.warning( - self, - self.tr("Not implemented"), - self.tr( - 'Installation is not implemented yet.\nAt the moment, you can only copy the plugin zip file to a directory and use "Install from ZIP" in QGIS.' - ), - ) - return + # Determine QGIS user plugins directory (profile/python/plugins) + try: + from qgis.core import QgsApplication + + qgis_settings_dir = QgsApplication.qgisSettingsDirPath() + except Exception: + qgis_settings_dir = None + + if not qgis_settings_dir: + answer = QMessageBox.question( + self, + self.tr("Error"), + self.tr( + "Can't determine QGIS profile directory automatically. Please open the profile folder or cancel." + ), + QMessageBox.StandardButton.Open | QMessageBox.StandardButton.Cancel, + ) + if answer == QMessageBox.StandardButton.Cancel: + return + + # No qgis classes available: look into usual Qt settings folder + qgis_app_dir = QStandardPaths.locate( + QStandardPaths.StandardLocation.GenericDataLocation, + "QGIS/QGIS3/profiles", + QStandardPaths.LocateOption.LocateDirectory, + ) + + qgis_settings_dir = QFileDialog.getExistingDirectory( + self, + self.tr("Open QGIS Profile Folder"), + qgis_app_dir, + ) + if not qgis_settings_dir: + return + + plugins_dir = os.path.join(qgis_settings_dir, "python", "plugins") + + # Ensure plugins directory exists (create if necessary) + try: + os.makedirs(plugins_dir, exist_ok=True) + except Exception as e: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Can't create plugins directory '{plugins_dir}': {e}"), + ) + return + + # Extract zip to a temporary directory and move to plugins folder + try: + with tempfile.TemporaryDirectory() as tmpdir: + with zipfile.ZipFile(asset_plugin.package_zip, "r") as zf: + zf.extractall(tmpdir) + + # Inspect top-level entries + qdir = QDir(tmpdir) + entries_info = qdir.entryInfoList(QDir.Filter.NoDotAndDotDot | QDir.Filter.Dirs) + # Require exactly one top-level directory (well-formed plugin zip) + if len(entries_info) != 1: + QMessageBox.critical( + self, + self.tr("Invalid plugin package"), + self.tr( + "The plugin zip must contain exactly one top-level directory. " + "Please provide a properly packaged plugin." + ), + ) + return + + dest_name = entries_info[0].fileName() + src_path = os.path.join(tmpdir, dest_name) + dest_path = os.path.join(plugins_dir, dest_name) + + # If destination exists, ask user whether to overwrite + if os.path.exists(dest_path): + res = QMessageBox.question( + self, + self.tr("Overwrite plugin"), + self.tr( + f"The plugin '{dest_name}' already exists in the QGIS plugins folder. Overwrite?" + ), + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + ) + if res != QMessageBox.StandardButton.Yes: + return + # Remove existing plugin directory + try: + if os.path.islink(dest_path) or os.path.isfile(dest_path): + os.remove(dest_path) + else: + shutil.rmtree(dest_path) + except Exception as e: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Failed to remove existing plugin '{dest_path}': {e}"), + ) + return + + # Move the extracted plugin into plugins directory + try: + shutil.move(src_path, dest_path) + except Exception: + # If move fails (cross-device), fallback to copytree + try: + shutil.copytree(src_path, dest_path) + except Exception as e2: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Failed to install plugin to '{dest_path}': {e2}"), + ) + return + + QMessageBox.information( + self, + self.tr("Plugin installed"), + self.tr( + f"Plugin '{dest_name}' installed to QGIS profile plugins folder:\n{dest_path}\n\nYou may need to restart QGIS or enable the plugin from the Plugin Manager." + ), + ) + + except zipfile.BadZipFile: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr("The plugin package is not a valid zip archive."), + ) + return + except Exception as e: + logger.exception("Unexpected error during plugin installation") + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Failed to install plugin: {e}"), + ) + return def __seeChangelogClicked(self): if self.__current_module_package is None: From d7a3ba1e27d1b49268c6c3f8e1b879f137139885 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Fri, 6 Feb 2026 09:14:26 +0100 Subject: [PATCH 2/8] Update docs --- docs/docs/getting_started.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/docs/getting_started.md b/docs/docs/getting_started.md index 21b86d3..b4aeef7 100644 --- a/docs/docs/getting_started.md +++ b/docs/docs/getting_started.md @@ -84,10 +84,14 @@ In the `Project` tab: ## Install the module plugin -In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). Direct install using the `Install` button is currently not implemented. - -* Click `Copy ZIP to directory` -* In QGIS > Extension > Install and manage extension > Install from ZIP +In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). There are two ways to install the plugin: + +1. Click `Install` + * If running oQtopus from QGIS, the plugin is installed in the current QGIS profile. + * If running oQtopus standalone, you get asked to select the QGIS profile directory. +2. Click `Copy ZIP to directory`: + * You can copy the plugin zip file to a directory of your choice. + * Then in QGIS > Extension > Install and manage extension > Install from ZIP ## oQtopus as a standalone python executable From 63cda6f7bd55d30fe4d30991b0901a4cceea6e39 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Fri, 6 Feb 2026 15:39:11 +0100 Subject: [PATCH 3/8] Use pyplugin_installer --- docs/docs/getting_started.md | 8 +-- oqtopus/gui/plugin_widget.py | 136 +++-------------------------------- 2 files changed, 13 insertions(+), 131 deletions(-) diff --git a/docs/docs/getting_started.md b/docs/docs/getting_started.md index b4aeef7..ff5f3ce 100644 --- a/docs/docs/getting_started.md +++ b/docs/docs/getting_started.md @@ -84,14 +84,12 @@ In the `Project` tab: ## Install the module plugin -In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). There are two ways to install the plugin: +In the `Plugin` tab, you can install the module plugin (ie. TWW plugin). There are two possibilities: -1. Click `Install` - * If running oQtopus from QGIS, the plugin is installed in the current QGIS profile. - * If running oQtopus standalone, you get asked to select the QGIS profile directory. +1. Click `Install` and it will be installed in the current QGIS profile. Note: this is possible only if running oQtopus from QGIS. 2. Click `Copy ZIP to directory`: * You can copy the plugin zip file to a directory of your choice. - * Then in QGIS > Extension > Install and manage extension > Install from ZIP + * Then in QGIS > Extension > Install and manage extension > Install from ZIP. ## oQtopus as a standalone python executable diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index 778c55b..6e31001 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -1,9 +1,7 @@ import os import shutil -import tempfile -import zipfile -from qgis.PyQt.QtCore import QDir, QStandardPaths, QUrl +from qgis.PyQt.QtCore import QUrl from qgis.PyQt.QtGui import QDesktopServices from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox, QWidget @@ -84,141 +82,27 @@ def __installClicked(self): QtUtils.setFontItalic(self.info_label, True) return - # Determine QGIS user plugins directory (profile/python/plugins) try: - from qgis.core import QgsApplication + from pyplugin_installer import instance as plugin_installer_instance - qgis_settings_dir = QgsApplication.qgisSettingsDirPath() - except Exception: - qgis_settings_dir = None + installer = plugin_installer_instance() + installer.installFromZipFile(asset_plugin.package_zip) - if not qgis_settings_dir: - answer = QMessageBox.question( - self, - self.tr("Error"), - self.tr( - "Can't determine QGIS profile directory automatically. Please open the profile folder or cancel." - ), - QMessageBox.StandardButton.Open | QMessageBox.StandardButton.Cancel, - ) - if answer == QMessageBox.StandardButton.Cancel: - return - - # No qgis classes available: look into usual Qt settings folder - qgis_app_dir = QStandardPaths.locate( - QStandardPaths.StandardLocation.GenericDataLocation, - "QGIS/QGIS3/profiles", - QStandardPaths.LocateOption.LocateDirectory, - ) - - qgis_settings_dir = QFileDialog.getExistingDirectory( - self, - self.tr("Open QGIS Profile Folder"), - qgis_app_dir, - ) - if not qgis_settings_dir: - return - - plugins_dir = os.path.join(qgis_settings_dir, "python", "plugins") - - # Ensure plugins directory exists (create if necessary) - try: - os.makedirs(plugins_dir, exist_ok=True) - except Exception as e: - QMessageBox.critical( - self, - self.tr("Error"), - self.tr(f"Can't create plugins directory '{plugins_dir}': {e}"), - ) return - # Extract zip to a temporary directory and move to plugins folder - try: - with tempfile.TemporaryDirectory() as tmpdir: - with zipfile.ZipFile(asset_plugin.package_zip, "r") as zf: - zf.extractall(tmpdir) - - # Inspect top-level entries - qdir = QDir(tmpdir) - entries_info = qdir.entryInfoList(QDir.Filter.NoDotAndDotDot | QDir.Filter.Dirs) - # Require exactly one top-level directory (well-formed plugin zip) - if len(entries_info) != 1: - QMessageBox.critical( - self, - self.tr("Invalid plugin package"), - self.tr( - "The plugin zip must contain exactly one top-level directory. " - "Please provide a properly packaged plugin." - ), - ) - return - - dest_name = entries_info[0].fileName() - src_path = os.path.join(tmpdir, dest_name) - dest_path = os.path.join(plugins_dir, dest_name) - - # If destination exists, ask user whether to overwrite - if os.path.exists(dest_path): - res = QMessageBox.question( - self, - self.tr("Overwrite plugin"), - self.tr( - f"The plugin '{dest_name}' already exists in the QGIS plugins folder. Overwrite?" - ), - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - ) - if res != QMessageBox.StandardButton.Yes: - return - # Remove existing plugin directory - try: - if os.path.islink(dest_path) or os.path.isfile(dest_path): - os.remove(dest_path) - else: - shutil.rmtree(dest_path) - except Exception as e: - QMessageBox.critical( - self, - self.tr("Error"), - self.tr(f"Failed to remove existing plugin '{dest_path}': {e}"), - ) - return - - # Move the extracted plugin into plugins directory - try: - shutil.move(src_path, dest_path) - except Exception: - # If move fails (cross-device), fallback to copytree - try: - shutil.copytree(src_path, dest_path) - except Exception as e2: - QMessageBox.critical( - self, - self.tr("Error"), - self.tr(f"Failed to install plugin to '{dest_path}': {e2}"), - ) - return - - QMessageBox.information( - self, - self.tr("Plugin installed"), - self.tr( - f"Plugin '{dest_name}' installed to QGIS profile plugins folder:\n{dest_path}\n\nYou may need to restart QGIS or enable the plugin from the Plugin Manager." - ), - ) - - except zipfile.BadZipFile: - QMessageBox.critical( + except ImportError: + QMessageBox.warning( self, self.tr("Error"), - self.tr("The plugin package is not a valid zip archive."), + self.tr("Plugin installation is not possible when oQtopus is running standalone."), ) return + except Exception as e: - logger.exception("Unexpected error during plugin installation") - QMessageBox.critical( + QMessageBox.warning( self, self.tr("Error"), - self.tr(f"Failed to install plugin: {e}"), + self.tr("Plugin installation failed with an exception: {0}").format(str(e)), ) return From a25401e4f5a36654c5b21d6f8951b9c8967278e4 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Fri, 6 Feb 2026 16:25:10 +0100 Subject: [PATCH 4/8] Check installation success --- oqtopus/gui/plugin_widget.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index 6e31001..d0f8b5e 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -75,19 +75,34 @@ def __installClicked(self): # Check if the package exists asset_plugin = self.__current_module_package.asset_plugin if not os.path.exists(asset_plugin.package_zip): - self.info_label.setText( - self.tr(f"Plugin zip file '{asset_plugin.package_zip}' does not exist.") + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Plugin zip file '{asset_plugin.package_zip}' does not exist."), ) - QtUtils.setForegroundColor(self.info_label, PluginUtils.COLOR_WARNING) - QtUtils.setFontItalic(self.info_label, True) return try: from pyplugin_installer import instance as plugin_installer_instance + from qgis.core import Qgis installer = plugin_installer_instance() - installer.installFromZipFile(asset_plugin.package_zip) + success = installer.installFromZipFile(asset_plugin.package_zip) + + # installFromZipFile return success from QGIS 3.44.08 + if not success and Qgis.QGIS_VERSION_INT > 34407: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr(f"Plugin '{asset_plugin.name}' installation failed."), + ) + return + QMessageBox.information( + self, + self.tr("Success"), + self.tr(f"Plugin '{asset_plugin.name}' installed successfully."), + ) return except ImportError: From 2701bcfb3f93080fb2eb69cff118f3a3cb868983 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Tue, 10 Feb 2026 08:53:50 +0100 Subject: [PATCH 5/8] Warning for qgis < 3.44.8 --- oqtopus/gui/plugin_widget.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index d0f8b5e..f7eaf89 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -85,12 +85,31 @@ def __installClicked(self): try: from pyplugin_installer import instance as plugin_installer_instance from qgis.core import Qgis + except ImportError: + QMessageBox.critical( + self, + self.tr("Error"), + self.tr("Plugin installation is not possible when oQtopus is running standalone."), + ) + return + try: installer = plugin_installer_instance() success = installer.installFromZipFile(asset_plugin.package_zip) # installFromZipFile return success from QGIS 3.44.08 - if not success and Qgis.QGIS_VERSION_INT > 34407: + if Qgis.QGIS_VERSION_INT < 34408: + QMessageBox.warning( + self, + self.tr("Installation finished"), + self.tr( + "Since your QGIS version is older than 3.44.8, we cannot determine if the installation was successful.\n" + "Please check the installation status in the plugin manager." + ), + ) + return + + if not success: QMessageBox.critical( self, self.tr("Error"), @@ -105,16 +124,8 @@ def __installClicked(self): ) return - except ImportError: - QMessageBox.warning( - self, - self.tr("Error"), - self.tr("Plugin installation is not possible when oQtopus is running standalone."), - ) - return - except Exception as e: - QMessageBox.warning( + QMessageBox.critical( self, self.tr("Error"), self.tr("Plugin installation failed with an exception: {0}").format(str(e)), From 0e470749a2b0b6c9c2cfe8d4c85fe6bd91a2dcf5 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Tue, 10 Feb 2026 14:55:44 +0100 Subject: [PATCH 6/8] Add infos for profile and installed plugin version --- oqtopus/gui/main_dialog.py | 5 ++- oqtopus/gui/plugin_widget.py | 60 ++++++++++++++++++++++++++++++------ oqtopus/oqtopus_plugin.py | 4 ++- oqtopus/ui/plugin_widget.ui | 8 ++++- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/oqtopus/gui/main_dialog.py b/oqtopus/gui/main_dialog.py index 5f58f29..31ae3ae 100644 --- a/oqtopus/gui/main_dialog.py +++ b/oqtopus/gui/main_dialog.py @@ -55,8 +55,7 @@ class MainDialog(QDialog, DIALOG_UI): - - def __init__(self, modules_config_path, about_dialog_cls=None, parent=None): + def __init__(self, modules_config_path, about_dialog_cls=None, parent=None, qgis_iface=None): QDialog.__init__(self, parent) self.setupUi(self) @@ -82,7 +81,7 @@ def __init__(self, modules_config_path, about_dialog_cls=None, parent=None): self.project_tab.layout().addWidget(self.__projectWidget) # Init GUI Plugin - self.__pluginWidget = PluginWidget(self) + self.__pluginWidget = PluginWidget(self, qgis_iface=qgis_iface) self.plugin_tab.layout().addWidget(self.__pluginWidget) # Init GUI Logs diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index f7eaf89..0e1ff5a 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -1,5 +1,6 @@ import os import shutil +from zipfile import ZipFile from qgis.PyQt.QtCore import QUrl from qgis.PyQt.QtGui import QDesktopServices @@ -13,7 +14,7 @@ class PluginWidget(QWidget, DIALOG_UI): - def __init__(self, parent=None): + def __init__(self, parent=None, qgis_iface=None): QWidget.__init__(self, parent) self.setupUi(self) @@ -22,9 +23,17 @@ def __init__(self, parent=None): self.copyZipToDirectory_pushButton.clicked.connect(self.__copyZipToDirectoryClicked) self.__current_module_package = None + self.__plugin_name = None + self.__iface = qgis_iface + + if self.__iface: + self.qgisProfile_label.setText(self.__iface.userProfileManager().userProfile().name()) + else: + self.qgisProfile_label.setText("Unknown") def setModulePackage(self, module_package: ModulePackage): self.__current_module_package = module_package + self.__plugin_name = None self.__packagePrepareGetPluginFilename() def clearModulePackage(self): @@ -57,6 +66,20 @@ def __packagePrepareGetPluginFilename(self): QtUtils.setFontItalic(self.info_label, True) return + # Get the plugin name + self.__plugin_name = self.__extractPluginName(asset_plugin.package_zip) + if not self.__plugin_name: + self.info_label.setText( + self.tr(f"Couldn't determinate the plugin name for '{asset_plugin.package_zip}'.") + ) + QtUtils.setForegroundColor(self.info_label, PluginUtils.COLOR_WARNING) + QtUtils.setFontItalic(self.info_label, True) + return + + # Get the installed plugin current version + version = self.__getInstalledPluginVersion(self.__plugin_name) + self.currentVersion_label.setText(version) + QtUtils.resetForegroundColor(self.info_label) QtUtils.setFontItalic(self.info_label, False) self.info_label.setText( @@ -99,30 +122,29 @@ def __installClicked(self): # installFromZipFile return success from QGIS 3.44.08 if Qgis.QGIS_VERSION_INT < 34408: - QMessageBox.warning( + version = self.__getInstalledPluginVersion(self.__plugin_name) + QMessageBox.information( self, self.tr("Installation finished"), - self.tr( - "Since your QGIS version is older than 3.44.8, we cannot determine if the installation was successful.\n" - "Please check the installation status in the plugin manager." - ), + self.tr(f"Current '{self.__plugin_name}' plugin version is {version}"), ) + self.__packagePrepareGetPluginFilename() return if not success: QMessageBox.critical( self, self.tr("Error"), - self.tr(f"Plugin '{asset_plugin.name}' installation failed."), + self.tr(f"Plugin '{self.__plugin_name}' installation failed."), ) return QMessageBox.information( self, self.tr("Success"), - self.tr(f"Plugin '{asset_plugin.name}' installed successfully."), + self.tr(f"Plugin '{self.__plugin_name}' installed successfully."), ) - return + self.__packagePrepareGetPluginFilename() except Exception as e: QMessageBox.critical( @@ -208,3 +230,23 @@ def __copyZipToDirectoryClicked(self): self.tr(f"Failed to copy plugin package: {e}"), ) return + + def __extractPluginName(self, package_zip: str) -> str: + with ZipFile(package_zip, "r") as zip_ref: + for name in zip_ref.namelist(): + print(f"name: {name}") + if name.endswith("/metadata.txt"): + return name.split("/")[0] + return "" + + def __getInstalledPluginVersion(self, plugin_name: str): + if not self.__iface: + return self.tr("Unknown") + + import qgis + + version = qgis.utils.pluginMetadata(plugin_name, "version") + if version == "__error__": + return self.tr("Not installed") + + return version diff --git a/oqtopus/oqtopus_plugin.py b/oqtopus/oqtopus_plugin.py index 6d12598..2952367 100644 --- a/oqtopus/oqtopus_plugin.py +++ b/oqtopus/oqtopus_plugin.py @@ -169,7 +169,9 @@ def unload(self): def show_main_dialog(self): conf_path = Path(__file__).parent / "default_config.yaml" - main_dialog = MainDialog(modules_config_path=conf_path, parent=self.iface.mainWindow()) + main_dialog = MainDialog( + modules_config_path=conf_path, parent=self.iface.mainWindow(), qgis_iface=self.iface + ) main_dialog.exec() def show_logs_folder(self): diff --git a/oqtopus/ui/plugin_widget.ui b/oqtopus/ui/plugin_widget.ui index 85162f1..e3a39b3 100644 --- a/oqtopus/ui/plugin_widget.ui +++ b/oqtopus/ui/plugin_widget.ui @@ -33,12 +33,18 @@ - + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + - no current version + Unknown + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse From 917bb47933234b162620472af997516592731dd3 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Tue, 10 Feb 2026 16:46:53 +0100 Subject: [PATCH 7/8] Apply suggestions from code review --- oqtopus/gui/main_dialog.py | 4 ++-- oqtopus/gui/plugin_widget.py | 5 +++-- oqtopus/oqtopus_plugin.py | 4 +--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/oqtopus/gui/main_dialog.py b/oqtopus/gui/main_dialog.py index 31ae3ae..df5228d 100644 --- a/oqtopus/gui/main_dialog.py +++ b/oqtopus/gui/main_dialog.py @@ -55,7 +55,7 @@ class MainDialog(QDialog, DIALOG_UI): - def __init__(self, modules_config_path, about_dialog_cls=None, parent=None, qgis_iface=None): + def __init__(self, modules_config_path, about_dialog_cls=None, parent=None): QDialog.__init__(self, parent) self.setupUi(self) @@ -81,7 +81,7 @@ def __init__(self, modules_config_path, about_dialog_cls=None, parent=None, qgis self.project_tab.layout().addWidget(self.__projectWidget) # Init GUI Plugin - self.__pluginWidget = PluginWidget(self, qgis_iface=qgis_iface) + self.__pluginWidget = PluginWidget(self) self.plugin_tab.layout().addWidget(self.__pluginWidget) # Init GUI Logs diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index 0e1ff5a..4d52bda 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -26,9 +26,10 @@ def __init__(self, parent=None, qgis_iface=None): self.__plugin_name = None self.__iface = qgis_iface - if self.__iface: + try: + from qgis.utils import iface self.qgisProfile_label.setText(self.__iface.userProfileManager().userProfile().name()) - else: + except ImportError: self.qgisProfile_label.setText("Unknown") def setModulePackage(self, module_package: ModulePackage): diff --git a/oqtopus/oqtopus_plugin.py b/oqtopus/oqtopus_plugin.py index 2952367..6d12598 100644 --- a/oqtopus/oqtopus_plugin.py +++ b/oqtopus/oqtopus_plugin.py @@ -169,9 +169,7 @@ def unload(self): def show_main_dialog(self): conf_path = Path(__file__).parent / "default_config.yaml" - main_dialog = MainDialog( - modules_config_path=conf_path, parent=self.iface.mainWindow(), qgis_iface=self.iface - ) + main_dialog = MainDialog(modules_config_path=conf_path, parent=self.iface.mainWindow()) main_dialog.exec() def show_logs_folder(self): From 037dc757733d8a2ff92b39f85f467c6da737d357 Mon Sep 17 00:00:00 2001 From: Damiano Lombardi Date: Tue, 10 Feb 2026 16:50:31 +0100 Subject: [PATCH 8/8] Don't pass iface all along the plugin --- oqtopus/gui/plugin_widget.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/oqtopus/gui/plugin_widget.py b/oqtopus/gui/plugin_widget.py index 4d52bda..7b83740 100644 --- a/oqtopus/gui/plugin_widget.py +++ b/oqtopus/gui/plugin_widget.py @@ -14,7 +14,7 @@ class PluginWidget(QWidget, DIALOG_UI): - def __init__(self, parent=None, qgis_iface=None): + def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) @@ -24,11 +24,11 @@ def __init__(self, parent=None, qgis_iface=None): self.__current_module_package = None self.__plugin_name = None - self.__iface = qgis_iface try: from qgis.utils import iface - self.qgisProfile_label.setText(self.__iface.userProfileManager().userProfile().name()) + + self.qgisProfile_label.setText(iface.userProfileManager().userProfile().name()) except ImportError: self.qgisProfile_label.setText("Unknown") @@ -241,12 +241,12 @@ def __extractPluginName(self, package_zip: str) -> str: return "" def __getInstalledPluginVersion(self, plugin_name: str): - if not self.__iface: + try: + from qgis.utils import pluginMetadata + except ImportError: return self.tr("Unknown") - import qgis - - version = qgis.utils.pluginMetadata(plugin_name, "version") + version = pluginMetadata(plugin_name, "version") if version == "__error__": return self.tr("Not installed")