From 5d7e7a393b49718ffa57aa14c5c26a779cc4642f Mon Sep 17 00:00:00 2001 From: Julien Moura Date: Thu, 2 Oct 2025 18:31:21 +0200 Subject: [PATCH 1/2] improve(qdt): support plugins installed from unofficial repository --- profile_manager/profiles/utils.py | 47 +++++++++++--------- profile_manager/qdt_export/models.py | 41 +++++++++++++++++ profile_manager/qdt_export/profile_export.py | 3 +- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/profile_manager/profiles/utils.py b/profile_manager/profiles/utils.py index a387711..dec6de3 100644 --- a/profile_manager/profiles/utils.py +++ b/profile_manager/profiles/utils.py @@ -1,5 +1,4 @@ from configparser import NoSectionError, RawConfigParser -from dataclasses import dataclass from pathlib import Path from sys import platform from typing import Any, Dict, List, Optional @@ -8,6 +7,8 @@ from qgis.core import QgsUserProfileManager from qgis.utils import iface +from profile_manager.qdt_export.models import QdtPluginInformation + def qgis_profiles_path() -> Path: """Get QGIS profiles paths from current QGIS application @@ -94,9 +95,11 @@ def get_installed_plugin_metadata( """ ini_parser = RawConfigParser() ini_parser.optionxform = str # str = case-sensitive option names - ini_parser.read(get_profile_plugin_metadata_path(profile_name, plugin_slug_name)) + plg_metadata_path = get_profile_plugin_metadata_path(profile_name, plugin_slug_name) + ini_parser.read(plg_metadata_path) try: metadata = dict(ini_parser.items("general")) + metadata["folder_name"] = plg_metadata_path.parent.name except NoSectionError: metadata = {} return metadata @@ -128,15 +131,6 @@ def get_profile_name_list() -> List[str]: return QgsUserProfileManager(qgis_profiles_path()).allProfiles() -@dataclass -class PluginInformation: - name: str - folder_name: str - official_repository: bool - plugin_id: Optional[int] - version: str - - def define_plugin_version_from_metadata( manager_metadata: Dict[str, Any], plugin_metadata: Dict[str, Any] ) -> str: @@ -168,7 +162,7 @@ def define_plugin_version_from_metadata( def get_profile_plugin_information( profile_name: str, plugin_slug_name: str -) -> Optional[PluginInformation]: +) -> Optional[QdtPluginInformation]: """Get plugin information from profile. Only official plugin are supported. Args: @@ -181,18 +175,27 @@ def get_profile_plugin_information( manager_metadata = get_plugin_info_from_qgis_manager( plugin_slug_name=plugin_slug_name ) + plugin_metadata = get_installed_plugin_metadata( profile_name=profile_name, plugin_slug_name=plugin_slug_name ) - # For now we don't support unofficial plugins - if manager_metadata is None: + if not all([manager_metadata, plugin_metadata]): + print(f"Plugin {plugin_slug_name} not found in profile {profile_name}") return None - return PluginInformation( - name=manager_metadata["name"], - folder_name=plugin_slug_name, - official_repository=True, # For now we only support official repository + if manager_metadata is None: + manager_metadata = { + "name": plugin_metadata.get("name", plugin_slug_name), + "download_url": None, + "plugin_id": None, + "folder_name": plugin_metadata.get("folder_name", plugin_slug_name), + } + + return QdtPluginInformation( + name=manager_metadata.get("name", plugin_slug_name), + download_url=manager_metadata.get("download_url"), + folder_name=plugin_metadata.get("folder_name", plugin_slug_name), plugin_id=( int(manager_metadata["plugin_id"]) if manager_metadata["plugin_id"] @@ -207,7 +210,7 @@ def get_profile_plugin_information( def get_profile_plugin_list_information( profile_name: str, only_activated: bool = True -) -> List[PluginInformation]: +) -> List[QdtPluginInformation]: """Get profile plugin information Args: @@ -220,12 +223,14 @@ def get_profile_plugin_list_information( plugin_list: List[str] = get_installed_plugin_list( profile_name=profile_name, only_activated=only_activated ) - # Get information about installed plugin - profile_plugin_list: List[PluginInformation] = [] + # Get information about installed plugin + profile_plugin_list: List[QdtPluginInformation] = [] for plugin_name in plugin_list: plugin_info = get_profile_plugin_information(profile_name, plugin_name) if plugin_info and plugin_info.plugin_id: profile_plugin_list.append(plugin_info) + elif plugin_info and not plugin_info.plugin_id: + profile_plugin_list.append(plugin_info) return profile_plugin_list diff --git a/profile_manager/qdt_export/models.py b/profile_manager/qdt_export/models.py index 196539d..98c729e 100644 --- a/profile_manager/qdt_export/models.py +++ b/profile_manager/qdt_export/models.py @@ -1,4 +1,45 @@ from dataclasses import dataclass +from typing import Any, Dict, Optional + + +@dataclass +class QdtPluginInformation: + """QGIS Plugin representation for QDT profile export.""" + + name: str + folder_name: str + version: str + download_url: Optional[str] = None + plugin_id: Optional[int] = None + + def as_dict(self) -> Dict[str, Any]: + """Custom as_dict method to handle properties and specific vars. + + :return: dict of PluginInformation + :rtype: Dict[str, Any] + """ + out_dict = { + "name": self.name, + "folder_name": self.folder_name, + "official_repository": self.official_repository, + "plugin_id": self.plugin_id, + "version": self.version, + } + if not self.official_repository and self.download_url: + out_dict["url"] = self.download_url + + return out_dict + + @property + def official_repository(self) -> bool: + """Check if plugin is from official QGIS repository. + + :return: True if plugin is from official QGIS repository. + :rtype: bool + """ + if self.download_url is None: + return False + return self.download_url.startswith("https://plugins.qgis.org") @dataclass diff --git a/profile_manager/qdt_export/profile_export.py b/profile_manager/qdt_export/profile_export.py index 74a72a3..d2cb0ab 100644 --- a/profile_manager/qdt_export/profile_export.py +++ b/profile_manager/qdt_export/profile_export.py @@ -1,4 +1,3 @@ -import dataclasses import json from pathlib import Path from shutil import copytree, rmtree @@ -72,7 +71,7 @@ def qdt_profile_dict( "qgisMinimumVersion": qdt_profile_infos.qgis_min_version, "qgisMaximumVersion": qdt_profile_infos.qgis_max_version, "version": qdt_profile_infos.version, - "plugins": [dataclasses.asdict(plugin) for plugin in profile_plugin_list], + "plugins": [plugin.as_dict() for plugin in profile_plugin_list], } From 35ffe5902d526fe5603726ee90232132b10bad75 Mon Sep 17 00:00:00 2001 From: Julien Moura Date: Wed, 22 Oct 2025 10:55:25 +0200 Subject: [PATCH 2/2] update(util): simplify condition --- profile_manager/profiles/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profile_manager/profiles/utils.py b/profile_manager/profiles/utils.py index dec6de3..7a95e51 100644 --- a/profile_manager/profiles/utils.py +++ b/profile_manager/profiles/utils.py @@ -180,7 +180,7 @@ def get_profile_plugin_information( profile_name=profile_name, plugin_slug_name=plugin_slug_name ) - if not all([manager_metadata, plugin_metadata]): + if manager_metadata is None and plugin_metadata is None: print(f"Plugin {plugin_slug_name} not found in profile {profile_name}") return None