From 321663b7fc3c57c05069b11a9299047237d0f734 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Wed, 10 Sep 2025 08:34:49 -0400 Subject: [PATCH 01/13] Sync license tab --- ...ddonmanager_widget_package_details_view.py | 18 +- addonmanager_package_details_controller.py | 24 ++- addonmanager_readme_controller.py | 157 ++++++++++++------ 3 files changed, 141 insertions(+), 58 deletions(-) diff --git a/Widgets/addonmanager_widget_package_details_view.py b/Widgets/addonmanager_widget_package_details_view.py index b45eb6d7..444889f6 100644 --- a/Widgets/addonmanager_widget_package_details_view.py +++ b/Widgets/addonmanager_widget_package_details_view.py @@ -22,11 +22,12 @@ # *************************************************************************** from dataclasses import dataclass +from typing import Optional , Dict from enum import Enum, auto import os -from typing import Optional from addonmanager_freecad_interface import translate +from addonmanager_readme_controller import TabView from PySideWrapper import QtCore, QtWidgets @@ -71,6 +72,7 @@ class PackageDetailsView(QtWidgets.QWidget): def __init__(self, parent: QtWidgets.QWidget = None): super().__init__(parent) self.button_bar = None + self.license_browser = None self.readme_browser = None self.message_label = None self.location_label = None @@ -83,12 +85,24 @@ def __init__(self, parent: QtWidgets.QWidget = None): self.installed_branch = None self.installed_timestamp = None self.can_disable = True + self.tabs : Dict[ TabView , int ] = {} self._setup_ui() def _setup_ui(self): self.vertical_layout = QtWidgets.QVBoxLayout(self) self.button_bar = WidgetAddonButtons(self) + + self.license_browser = WidgetReadmeBrowser(self) self.readme_browser = WidgetReadmeBrowser(self) + + self.tabs_widget = QtWidgets.QTabWidget(self) + + self.tabs[ TabView.Readme ] = self.tabs_widget \ + .addTab(self.readme_browser,translate('AddonsInstaller','README')) + + self.tabs[ TabView.License ] = self.tabs_widget \ + .addTab(self.license_browser,translate('AddonsInstaller','LICENSE')) + self.message_label = QtWidgets.QLabel(self) self.location_label = QtWidgets.QLabel(self) self.url_label = QtWidgets.QLabel(self) @@ -98,7 +112,7 @@ def _setup_ui(self): self.vertical_layout.addWidget(self.message_label) self.vertical_layout.addWidget(self.location_label) self.vertical_layout.addWidget(self.url_label) - self.vertical_layout.addWidget(self.readme_browser) + self.vertical_layout.addWidget(self.tabs_widget) self.button_bar.hide() # Start with no bar def set_location(self, location: Optional[str]): diff --git a/addonmanager_package_details_controller.py b/addonmanager_package_details_controller.py index 0a9eda08..95f59569 100644 --- a/addonmanager_package_details_controller.py +++ b/addonmanager_package_details_controller.py @@ -33,11 +33,11 @@ get_branch_from_metadata, get_repo_url_from_metadata, ) +from Widgets.addonmanager_widget_package_details_view import PackageDetailsView , UpdateInformation , WarningFlags +from addonmanager_readme_controller import ReadmeController , TabView from addonmanager_workers_startup import CheckSingleUpdateWorker from addonmanager_git import GitManager, NoGitFound from Addon import Addon -from addonmanager_readme_controller import ReadmeController -from Widgets.addonmanager_widget_package_details_view import UpdateInformation, WarningFlags translate = fci.translate @@ -52,10 +52,13 @@ class PackageDetailsController(QtCore.QObject): execute = QtCore.Signal(Addon) update_status = QtCore.Signal(Addon) - def __init__(self, widget=None): + def __init__(self, widget : PackageDetailsView ): super().__init__() self.ui = widget + + self.license_controller = ReadmeController(self.ui.license_browser) self.readme_controller = ReadmeController(self.ui.readme_browser) + self.worker = None self.addon = None self.update_check_thread = None @@ -77,11 +80,24 @@ def __init__(self, widget=None): self.ui.button_bar.install_branch.connect(self.install_branch) def show_addon(self, addon: Addon) -> None: + """The main entry point for this class shows the package details and related buttons for the provided repo.""" + self.addon = addon - self.readme_controller.set_addon(addon) + + self.readme_controller.set_addon(addon,TabView.Readme) + + has_license = bool(self.addon.license) + + self.ui.tabs_widget.setTabVisible(self.ui.tabs[ TabView.License ],has_license) + + if has_license: + self.license_controller.set_addon(addon,TabView.License) + + self.original_disabled_state = self.addon.is_disabled() + if addon is not None: self.ui.button_bar.show() if addon.repo_type == Addon.Kind.MACRO: diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 36bc2726..a2eb79d8 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -27,28 +27,35 @@ import addonmanager_utilities as utils import addonmanager_freecad_interface as fci -from enum import IntEnum -from typing import Optional +from requests import get as fetch , ConnectionError +from typing import Optional , cast +from enum import IntEnum , auto import NetworkManager -from addonmanager_metadata import UrlType +from Widgets.addonmanager_widget_readme_browser import WidgetReadmeBrowser +from addonmanager_metadata import UrlType , License translate = fci.translate from PySideWrapper import QtCore, QtGui + class ReadmeDataType(IntEnum): PlainText = 0 Markdown = 1 Html = 2 +class TabView(IntEnum): + License = auto() + Readme = 0 + class ReadmeController(QtCore.QObject): """A class that can provide README data from an Addon, possibly loading external resources such as images""" - def __init__(self, widget): + def __init__(self, widget : WidgetReadmeBrowser ): super().__init__() NetworkManager.InitializeNetworkManager() NetworkManager.AM_NETWORK_MANAGER.completed.connect(self._download_completed) @@ -64,16 +71,16 @@ def __init__(self, widget): self.widget.load_resource.connect(self.loadResource) self.widget.follow_link.connect(self.follow_link) - def set_addon(self, repo: Addon): + def set_addon ( self , addon : Addon , view : TabView ): """Set which Addon's information is displayed""" - self.addon = repo + self.addon = addon self.stop = False self.readme_data = None if self.addon.repo_type == Addon.Kind.MACRO: self._create_wiki_display() else: - self._create_non_wiki_display() + self._create_non_wiki_display(view) def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> None: """Callback for handling a completed README file download.""" @@ -103,7 +110,7 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> else: self.widget.setText(self.readme_data) else: - self.set_addon(self.addon) # Trigger a reload of the page now with resources + self.set_addon(self.addon,TabView.Readme) # Trigger a reload of the page now with resources def _process_package_download(self, data: str): self.readme_data = data @@ -182,47 +189,93 @@ def _create_wiki_display(self): self.readme_data_type = ReadmeDataType.Markdown self.widget.setMarkdown(markdown) - def _create_non_wiki_display(self): - self.url = utils.get_readme_url(self.addon) - if self.addon.metadata and self.addon.metadata.url: - for url in self.addon.metadata.url: - if url.type == UrlType.readme: - if self.url != url.location: - fci.Console.PrintLog("README url does not match expected location\n") - fci.Console.PrintLog(f"Expected: {self.url}\n") - fci.Console.PrintLog(f"package.xml contents: {url.location}\n") - fci.Console.PrintLog( - "Note to addon devs: package.xml now expects a" - " url to the raw MD data, now that Qt can render" - " it without having it transformed to HTML.\n" - ) - self.url = url.location - if "/blob/" in self.url: - fci.Console.PrintLog("Attempting to replace 'blob' with 'raw'...\n") - self.url = self.url.replace("/blob/", "/raw/") - elif "/src/" in self.url and "codeberg" in self.url: - fci.Console.PrintLog( - "Attempting to replace 'src' with 'raw' in codeberg URL..." - ) - self.url = self.url.replace("/src/", "/raw/") - - self.widget.setUrl(self.url) - - self.widget.setText( - translate("AddonsInstaller", "Loading page for {} from {}...").format( - self.addon.display_name, self.url - ) - ) - - if self.url[0] == "/": - if self.url.lower().endswith(".md"): - self.readme_data_type = ReadmeDataType.Markdown - elif self.url.lower().endswith(".html"): - self.readme_data_type = ReadmeDataType.Html - - with open(self.url, "r") as fd: - self._process_package_download("".join(fd.readlines())) - else: - self.readme_request_index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get( - self.url - ) + def _create_non_wiki_display ( self , view : TabView ): + + match view: + case TabView.License: + + addon = cast(Addon,self.addon) + + licenses = addon.license + + match licenses: + case list(): + + text = '' + + licenses = cast(list[License | str],licenses) + + for license in licenses: + if license == str(): + text += license + else: + + name = license.name + + url = utils.construct_git_url(addon,license.file) + + try: + + response = fetch(url) + + if response.ok: + text += response.text + else: + text += name + + except ConnectionError: + + text += name + + self.widget.setText(text) + + case str(): + self.widget.setText(licenses) + + case TabView.Readme: + + self.url = utils.get_readme_url(self.addon) + + if self.addon.metadata and self.addon.metadata.url: + for url in self.addon.metadata.url: + if url.type == UrlType.readme: + if self.url != url.location: + fci.Console.PrintLog("README url does not match expected location\n") + fci.Console.PrintLog(f"Expected: {self.url}\n") + fci.Console.PrintLog(f"package.xml contents: {url.location}\n") + fci.Console.PrintLog( + "Note to addon devs: package.xml now expects a" + " url to the raw MD data, now that Qt can render" + " it without having it transformed to HTML.\n" + ) + self.url = url.location + if "/blob/" in self.url: + fci.Console.PrintLog("Attempting to replace 'blob' with 'raw'...\n") + self.url = self.url.replace("/blob/", "/raw/") + elif "/src/" in self.url and "codeberg" in self.url: + fci.Console.PrintLog( + "Attempting to replace 'src' with 'raw' in codeberg URL..." + ) + self.url = self.url.replace("/src/", "/raw/") + + self.widget.setUrl(self.url) + + self.widget.setText( + translate("AddonsInstaller", "Loading page for {} from {}...").format( + self.addon.display_name, self.url + ) + ) + + if self.url[0] == "/": + if self.url.lower().endswith(".md"): + self.readme_data_type = ReadmeDataType.Markdown + elif self.url.lower().endswith(".html"): + self.readme_data_type = ReadmeDataType.Html + + with open(self.url, "r") as fd: + self._process_package_download("".join(fd.readlines())) + else: + self.readme_request_index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get( + self.url + ) + From 79e07962a7097c05d36b94266ce4dd553c6dd232 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:42:31 +0000 Subject: [PATCH 02/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ...ddonmanager_widget_package_details_view.py | 16 ++++--- addonmanager_package_details_controller.py | 26 +++++------ addonmanager_readme_controller.py | 43 ++++++++++--------- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/Widgets/addonmanager_widget_package_details_view.py b/Widgets/addonmanager_widget_package_details_view.py index 444889f6..ceb88057 100644 --- a/Widgets/addonmanager_widget_package_details_view.py +++ b/Widgets/addonmanager_widget_package_details_view.py @@ -22,7 +22,7 @@ # *************************************************************************** from dataclasses import dataclass -from typing import Optional , Dict +from typing import Optional, Dict from enum import Enum, auto import os @@ -85,7 +85,7 @@ def __init__(self, parent: QtWidgets.QWidget = None): self.installed_branch = None self.installed_timestamp = None self.can_disable = True - self.tabs : Dict[ TabView , int ] = {} + self.tabs: Dict[TabView, int] = {} self._setup_ui() def _setup_ui(self): @@ -94,14 +94,16 @@ def _setup_ui(self): self.license_browser = WidgetReadmeBrowser(self) self.readme_browser = WidgetReadmeBrowser(self) - + self.tabs_widget = QtWidgets.QTabWidget(self) - self.tabs[ TabView.Readme ] = self.tabs_widget \ - .addTab(self.readme_browser,translate('AddonsInstaller','README')) + self.tabs[TabView.Readme] = self.tabs_widget.addTab( + self.readme_browser, translate("AddonsInstaller", "README") + ) - self.tabs[ TabView.License ] = self.tabs_widget \ - .addTab(self.license_browser,translate('AddonsInstaller','LICENSE')) + self.tabs[TabView.License] = self.tabs_widget.addTab( + self.license_browser, translate("AddonsInstaller", "LICENSE") + ) self.message_label = QtWidgets.QLabel(self) self.location_label = QtWidgets.QLabel(self) diff --git a/addonmanager_package_details_controller.py b/addonmanager_package_details_controller.py index 95f59569..15d0cc69 100644 --- a/addonmanager_package_details_controller.py +++ b/addonmanager_package_details_controller.py @@ -33,8 +33,12 @@ get_branch_from_metadata, get_repo_url_from_metadata, ) -from Widgets.addonmanager_widget_package_details_view import PackageDetailsView , UpdateInformation , WarningFlags -from addonmanager_readme_controller import ReadmeController , TabView +from Widgets.addonmanager_widget_package_details_view import ( + PackageDetailsView, + UpdateInformation, + WarningFlags, +) +from addonmanager_readme_controller import ReadmeController, TabView from addonmanager_workers_startup import CheckSingleUpdateWorker from addonmanager_git import GitManager, NoGitFound from Addon import Addon @@ -52,10 +56,10 @@ class PackageDetailsController(QtCore.QObject): execute = QtCore.Signal(Addon) update_status = QtCore.Signal(Addon) - def __init__(self, widget : PackageDetailsView ): + def __init__(self, widget: PackageDetailsView): super().__init__() self.ui = widget - + self.license_controller = ReadmeController(self.ui.license_browser) self.readme_controller = ReadmeController(self.ui.readme_browser) @@ -80,24 +84,22 @@ def __init__(self, widget : PackageDetailsView ): self.ui.button_bar.install_branch.connect(self.install_branch) def show_addon(self, addon: Addon) -> None: - """The main entry point for this class shows the package details and related buttons for the provided repo.""" - + self.addon = addon - - self.readme_controller.set_addon(addon,TabView.Readme) + + self.readme_controller.set_addon(addon, TabView.Readme) has_license = bool(self.addon.license) - self.ui.tabs_widget.setTabVisible(self.ui.tabs[ TabView.License ],has_license) + self.ui.tabs_widget.setTabVisible(self.ui.tabs[TabView.License], has_license) if has_license: - self.license_controller.set_addon(addon,TabView.License) - + self.license_controller.set_addon(addon, TabView.License) self.original_disabled_state = self.addon.is_disabled() - + if addon is not None: self.ui.button_bar.show() if addon.repo_type == Addon.Kind.MACRO: diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index a2eb79d8..30acef43 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -27,25 +27,25 @@ import addonmanager_utilities as utils import addonmanager_freecad_interface as fci -from requests import get as fetch , ConnectionError -from typing import Optional , cast -from enum import IntEnum , auto +from requests import get as fetch, ConnectionError +from typing import Optional, cast +from enum import IntEnum, auto import NetworkManager from Widgets.addonmanager_widget_readme_browser import WidgetReadmeBrowser -from addonmanager_metadata import UrlType , License +from addonmanager_metadata import UrlType, License translate = fci.translate from PySideWrapper import QtCore, QtGui - class ReadmeDataType(IntEnum): PlainText = 0 Markdown = 1 Html = 2 + class TabView(IntEnum): License = auto() Readme = 0 @@ -55,7 +55,7 @@ class ReadmeController(QtCore.QObject): """A class that can provide README data from an Addon, possibly loading external resources such as images""" - def __init__(self, widget : WidgetReadmeBrowser ): + def __init__(self, widget: WidgetReadmeBrowser): super().__init__() NetworkManager.InitializeNetworkManager() NetworkManager.AM_NETWORK_MANAGER.completed.connect(self._download_completed) @@ -71,7 +71,7 @@ def __init__(self, widget : WidgetReadmeBrowser ): self.widget.load_resource.connect(self.loadResource) self.widget.follow_link.connect(self.follow_link) - def set_addon ( self , addon : Addon , view : TabView ): + def set_addon(self, addon: Addon, view: TabView): """Set which Addon's information is displayed""" self.addon = addon @@ -110,7 +110,9 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> else: self.widget.setText(self.readme_data) else: - self.set_addon(self.addon,TabView.Readme) # Trigger a reload of the page now with resources + self.set_addon( + self.addon, TabView.Readme + ) # Trigger a reload of the page now with resources def _process_package_download(self, data: str): self.readme_data = data @@ -189,21 +191,21 @@ def _create_wiki_display(self): self.readme_data_type = ReadmeDataType.Markdown self.widget.setMarkdown(markdown) - def _create_non_wiki_display ( self , view : TabView ): + def _create_non_wiki_display(self, view: TabView): match view: case TabView.License: - addon = cast(Addon,self.addon) + addon = cast(Addon, self.addon) licenses = addon.license match licenses: case list(): - text = '' + text = "" - licenses = cast(list[License | str],licenses) + licenses = cast(list[License | str], licenses) for license in licenses: if license == str(): @@ -212,10 +214,10 @@ def _create_non_wiki_display ( self , view : TabView ): name = license.name - url = utils.construct_git_url(addon,license.file) + url = utils.construct_git_url(addon, license.file) try: - + response = fetch(url) if response.ok: @@ -226,7 +228,7 @@ def _create_non_wiki_display ( self , view : TabView ): except ConnectionError: text += name - + self.widget.setText(text) case str(): @@ -235,12 +237,14 @@ def _create_non_wiki_display ( self , view : TabView ): case TabView.Readme: self.url = utils.get_readme_url(self.addon) - + if self.addon.metadata and self.addon.metadata.url: for url in self.addon.metadata.url: if url.type == UrlType.readme: if self.url != url.location: - fci.Console.PrintLog("README url does not match expected location\n") + fci.Console.PrintLog( + "README url does not match expected location\n" + ) fci.Console.PrintLog(f"Expected: {self.url}\n") fci.Console.PrintLog(f"package.xml contents: {url.location}\n") fci.Console.PrintLog( @@ -275,7 +279,6 @@ def _create_non_wiki_display ( self , view : TabView ): with open(self.url, "r") as fd: self._process_package_download("".join(fd.readlines())) else: - self.readme_request_index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get( - self.url + self.readme_request_index = ( + NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(self.url) ) - From 38e224bd8b76ddb3184d1cfdb5c0f2e0f1167b62 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Wed, 10 Sep 2025 19:20:57 -0400 Subject: [PATCH 03/13] Use if else for legacy support --- addonmanager_readme_controller.py | 149 +++++++++++++++--------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 30acef43..9fd1d6cc 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -193,92 +193,91 @@ def _create_wiki_display(self): def _create_non_wiki_display(self, view: TabView): - match view: - case TabView.License: + if view == TabView.License: - addon = cast(Addon, self.addon) + addon = cast(Addon, self.addon) - licenses = addon.license + licenses = addon.license - match licenses: - case list(): + if type(licenses) is list: - text = "" + text = "" - licenses = cast(list[License | str], licenses) + licenses = cast(list[License | str], licenses) - for license in licenses: - if license == str(): - text += license - else: - - name = license.name - - url = utils.construct_git_url(addon, license.file) - - try: - - response = fetch(url) - - if response.ok: - text += response.text - else: - text += name - - except ConnectionError: - - text += name + for license in licenses: + if type(license) is str: + text += license + elif type(license) is License: - self.widget.setText(text) + name = license.name - case str(): - self.widget.setText(licenses) + url = utils.construct_git_url(addon, license.file) - case TabView.Readme: + try: - self.url = utils.get_readme_url(self.addon) + response = fetch(url) - if self.addon.metadata and self.addon.metadata.url: - for url in self.addon.metadata.url: - if url.type == UrlType.readme: - if self.url != url.location: - fci.Console.PrintLog( - "README url does not match expected location\n" - ) - fci.Console.PrintLog(f"Expected: {self.url}\n") - fci.Console.PrintLog(f"package.xml contents: {url.location}\n") - fci.Console.PrintLog( - "Note to addon devs: package.xml now expects a" - " url to the raw MD data, now that Qt can render" - " it without having it transformed to HTML.\n" - ) - self.url = url.location - if "/blob/" in self.url: - fci.Console.PrintLog("Attempting to replace 'blob' with 'raw'...\n") - self.url = self.url.replace("/blob/", "/raw/") - elif "/src/" in self.url and "codeberg" in self.url: - fci.Console.PrintLog( - "Attempting to replace 'src' with 'raw' in codeberg URL..." - ) - self.url = self.url.replace("/src/", "/raw/") - - self.widget.setUrl(self.url) - - self.widget.setText( - translate("AddonsInstaller", "Loading page for {} from {}...").format( - self.addon.display_name, self.url - ) + if response.ok: + text += response.text + else: + text += name + + except ConnectionError: + + text += name + + self.widget.setText(text) + + elif type(licenses) is str: + + self.widget.setText(licenses) + + elif view == TabView.Readme: + + self.url = utils.get_readme_url(self.addon) + + if self.addon.metadata and self.addon.metadata.url: + for url in self.addon.metadata.url: + if url.type == UrlType.readme: + if self.url != url.location: + fci.Console.PrintLog( + "README url does not match expected location\n" + ) + fci.Console.PrintLog(f"Expected: {self.url}\n") + fci.Console.PrintLog(f"package.xml contents: {url.location}\n") + fci.Console.PrintLog( + "Note to addon devs: package.xml now expects a" + " url to the raw MD data, now that Qt can render" + " it without having it transformed to HTML.\n" + ) + self.url = url.location + if "/blob/" in self.url: + fci.Console.PrintLog("Attempting to replace 'blob' with 'raw'...\n") + self.url = self.url.replace("/blob/", "/raw/") + elif "/src/" in self.url and "codeberg" in self.url: + fci.Console.PrintLog( + "Attempting to replace 'src' with 'raw' in codeberg URL..." + ) + self.url = self.url.replace("/src/", "/raw/") + + self.widget.setUrl(self.url) + + self.widget.setText( + translate("AddonsInstaller", "Loading page for {} from {}...").format( + self.addon.display_name, self.url ) + ) - if self.url[0] == "/": - if self.url.lower().endswith(".md"): - self.readme_data_type = ReadmeDataType.Markdown - elif self.url.lower().endswith(".html"): - self.readme_data_type = ReadmeDataType.Html + if self.url[0] == "/": + if self.url.lower().endswith(".md"): + self.readme_data_type = ReadmeDataType.Markdown + elif self.url.lower().endswith(".html"): + self.readme_data_type = ReadmeDataType.Html - with open(self.url, "r") as fd: - self._process_package_download("".join(fd.readlines())) - else: - self.readme_request_index = ( - NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(self.url) - ) + with open(self.url, "r") as fd: + self._process_package_download("".join(fd.readlines())) + else: + self.readme_request_index = ( + NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(self.url) + ) From 1076c56cf51ffc04d8c1b8cec6d6b5396b06d7b6 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Thu, 11 Sep 2025 19:16:45 -0400 Subject: [PATCH 04/13] Made license loading use network manager --- addonmanager_package_details_controller.py | 5 +- addonmanager_readme_controller.py | 88 ++++++++++++++++------ 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/addonmanager_package_details_controller.py b/addonmanager_package_details_controller.py index 15d0cc69..be8e8c4b 100644 --- a/addonmanager_package_details_controller.py +++ b/addonmanager_package_details_controller.py @@ -89,8 +89,6 @@ def show_addon(self, addon: Addon) -> None: self.addon = addon - self.readme_controller.set_addon(addon, TabView.Readme) - has_license = bool(self.addon.license) self.ui.tabs_widget.setTabVisible(self.ui.tabs[TabView.License], has_license) @@ -98,6 +96,9 @@ def show_addon(self, addon: Addon) -> None: if has_license: self.license_controller.set_addon(addon, TabView.License) + self.readme_controller.set_addon(addon, TabView.Readme) + self.ui.tabs_widget.setCurrentIndex(TabView.Readme) + self.original_disabled_state = self.addon.is_disabled() if addon is not None: diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 9fd1d6cc..d3b13f29 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -27,13 +27,13 @@ import addonmanager_utilities as utils import addonmanager_freecad_interface as fci -from requests import get as fetch, ConnectionError -from typing import Optional, cast +from typing import TypedDict, Optional, Dict ,cast from enum import IntEnum, auto import NetworkManager from Widgets.addonmanager_widget_readme_browser import WidgetReadmeBrowser from addonmanager_metadata import UrlType, License +from PySideWrapper import QtWidgets translate = fci.translate @@ -50,6 +50,9 @@ class TabView(IntEnum): License = auto() Readme = 0 +class LicenseRequest(TypedDict): + license : License + text : QtWidgets.QTextEdit class ReadmeController(QtCore.QObject): """A class that can provide README data from an Addon, possibly loading external resources such @@ -60,8 +63,12 @@ def __init__(self, widget: WidgetReadmeBrowser): NetworkManager.InitializeNetworkManager() NetworkManager.AM_NETWORK_MANAGER.completed.connect(self._download_completed) self.readme_request_index = 0 + self.resource_requests = {} self.resource_failures = [] + + self.license_requests : Dict[ int , LicenseRequest ] = {} + self.url = "" self.readme_data = None self.readme_data_type = None @@ -114,6 +121,24 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> self.addon, TabView.Readme ) # Trigger a reload of the page now with resources + elif index in self.license_requests: + + text = None + + if code == 200: + text = cast(str,data.data().decode('utf-8')) + + entry = self.license_requests.get(index) + + print('License loaded',index,code,entry) + + if not entry: + return + + text = text or entry[ 'license' ].name + + entry[ 'text' ].setText(text) + def _process_package_download(self, data: str): self.readme_data = data self.readme_data_type = ReadmeDataType.Markdown @@ -123,6 +148,19 @@ def _process_resource_download(self, resource_name: str, resource_data: bytes): image = QtGui.QImage.fromData(resource_data) self.widget.set_resource(resource_name, image) + def loadLicense ( self , license : License , text : QtWidgets.QTextEdit ): + + url = utils.construct_git_url(self.addon,license.file) + + manager = NetworkManager.AM_NETWORK_MANAGER + + index = manager.submit_unmonitored_get(url) + + self.license_requests[index] = { + 'license' : license , + 'text' : text + } + def loadResource(self, full_url: str): if full_url not in self.resource_failures: index = NetworkManager.AM_NETWORK_MANAGER.submit_unmonitored_get(full_url) @@ -199,39 +237,47 @@ def _create_non_wiki_display(self, view: TabView): licenses = addon.license - if type(licenses) is list: + layout = self.widget.layout() - text = "" + if not layout: + + layout = QtWidgets.QVBoxLayout() - licenses = cast(list[License | str], licenses) + self.widget.setLayout(layout) - for license in licenses: - if type(license) is str: - text += license - elif type(license) is License: - name = license.name + while layout.count(): + + item = layout.takeAt(0) + widget = item.widget() + widget.setParent(None) - url = utils.construct_git_url(addon, license.file) - try: + if type(licenses) is list: - response = fetch(url) + licenses = cast(list[License | str], licenses) - if response.ok: - text += response.text - else: - text += name + for license in licenses: - except ConnectionError: + text = QtWidgets.QTextEdit() - text += name + text.setText( + translate("AddonsInstaller", "Loading license..") + ) - self.widget.setText(text) + layout.addWidget(text) + + if type(license) is License: + self.loadLicense(license,text) + elif type(license) is str: + text.setText(license) elif type(licenses) is str: - self.widget.setText(licenses) + browser = QtWidgets.QTextBrowser() + browser.setText(licenses) + + layout.addWidget(browser) elif view == TabView.Readme: From b98a47d87d0735dc7cadd665cc87a7d751e74ad2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Sep 2025 23:16:59 +0000 Subject: [PATCH 05/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- addonmanager_readme_controller.py | 49 +++++++++++++------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index d3b13f29..c4666ecd 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -27,7 +27,7 @@ import addonmanager_utilities as utils import addonmanager_freecad_interface as fci -from typing import TypedDict, Optional, Dict ,cast +from typing import TypedDict, Optional, Dict, cast from enum import IntEnum, auto import NetworkManager @@ -50,9 +50,11 @@ class TabView(IntEnum): License = auto() Readme = 0 + class LicenseRequest(TypedDict): - license : License - text : QtWidgets.QTextEdit + license: License + text: QtWidgets.QTextEdit + class ReadmeController(QtCore.QObject): """A class that can provide README data from an Addon, possibly loading external resources such @@ -63,12 +65,12 @@ def __init__(self, widget: WidgetReadmeBrowser): NetworkManager.InitializeNetworkManager() NetworkManager.AM_NETWORK_MANAGER.completed.connect(self._download_completed) self.readme_request_index = 0 - + self.resource_requests = {} self.resource_failures = [] - self.license_requests : Dict[ int , LicenseRequest ] = {} - + self.license_requests: Dict[int, LicenseRequest] = {} + self.url = "" self.readme_data = None self.readme_data_type = None @@ -126,18 +128,18 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> text = None if code == 200: - text = cast(str,data.data().decode('utf-8')) - + text = cast(str, data.data().decode("utf-8")) + entry = self.license_requests.get(index) - print('License loaded',index,code,entry) + print("License loaded", index, code, entry) if not entry: return - text = text or entry[ 'license' ].name + text = text or entry["license"].name - entry[ 'text' ].setText(text) + entry["text"].setText(text) def _process_package_download(self, data: str): self.readme_data = data @@ -148,18 +150,15 @@ def _process_resource_download(self, resource_name: str, resource_data: bytes): image = QtGui.QImage.fromData(resource_data) self.widget.set_resource(resource_name, image) - def loadLicense ( self , license : License , text : QtWidgets.QTextEdit ): + def loadLicense(self, license: License, text: QtWidgets.QTextEdit): - url = utils.construct_git_url(self.addon,license.file) + url = utils.construct_git_url(self.addon, license.file) manager = NetworkManager.AM_NETWORK_MANAGER index = manager.submit_unmonitored_get(url) - self.license_requests[index] = { - 'license' : license , - 'text' : text - } + self.license_requests[index] = {"license": license, "text": text} def loadResource(self, full_url: str): if full_url not in self.resource_failures: @@ -240,19 +239,17 @@ def _create_non_wiki_display(self, view: TabView): layout = self.widget.layout() if not layout: - + layout = QtWidgets.QVBoxLayout() self.widget.setLayout(layout) - while layout.count(): - + item = layout.takeAt(0) widget = item.widget() widget.setParent(None) - if type(licenses) is list: licenses = cast(list[License | str], licenses) @@ -261,14 +258,12 @@ def _create_non_wiki_display(self, view: TabView): text = QtWidgets.QTextEdit() - text.setText( - translate("AddonsInstaller", "Loading license..") - ) + text.setText(translate("AddonsInstaller", "Loading license..")) layout.addWidget(text) if type(license) is License: - self.loadLicense(license,text) + self.loadLicense(license, text) elif type(license) is str: text.setText(license) @@ -287,9 +282,7 @@ def _create_non_wiki_display(self, view: TabView): for url in self.addon.metadata.url: if url.type == UrlType.readme: if self.url != url.location: - fci.Console.PrintLog( - "README url does not match expected location\n" - ) + fci.Console.PrintLog("README url does not match expected location\n") fci.Console.PrintLog(f"Expected: {self.url}\n") fci.Console.PrintLog(f"package.xml contents: {url.location}\n") fci.Console.PrintLog( From 6666bcd4aebda1514e25cbd1c19b9a5f4513ca9f Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Sun, 14 Sep 2025 06:59:33 -0400 Subject: [PATCH 06/13] Removed debug logging --- addonmanager_readme_controller.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index c4666ecd..ce00ed31 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -132,8 +132,6 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> entry = self.license_requests.get(index) - print("License loaded", index, code, entry) - if not entry: return From 1c3b3365cbd87bfb7ad0da8eeafc33ed3d6df132 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Sun, 14 Sep 2025 06:59:59 -0400 Subject: [PATCH 07/13] Added warning when failed to fetch licenses --- addonmanager_readme_controller.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index ce00ed31..ec49bd06 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -125,16 +125,18 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> elif index in self.license_requests: - text = None - - if code == 200: - text = cast(str, data.data().decode("utf-8")) - entry = self.license_requests.get(index) if not entry: return + text = None + + if code == 200: + text = cast(str, data.data().decode("utf-8")) + else: + fci.Console().printLog(f'Failed to fetch license. Name : "{ entry["license"].name }" , File : "{ entry["license"].file }"') + text = text or entry["license"].name entry["text"].setText(text) From c7e7eb529aa6dc105efd9d1fffd588cccc4d8065 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 14 Sep 2025 11:00:13 +0000 Subject: [PATCH 08/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- addonmanager_readme_controller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index ec49bd06..7fd30671 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -135,7 +135,9 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> if code == 200: text = cast(str, data.data().decode("utf-8")) else: - fci.Console().printLog(f'Failed to fetch license. Name : "{ entry["license"].name }" , File : "{ entry["license"].file }"') + fci.Console().printLog( + f'Failed to fetch license. Name : "{ entry["license"].name }" , File : "{ entry["license"].file }"' + ) text = text or entry["license"].name From 4d2478ee58f68dc656ac9eeafe07714ac6924bc6 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Sun, 14 Sep 2025 07:17:48 -0400 Subject: [PATCH 09/13] Update addonmanager_readme_controller.py --- addonmanager_readme_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index ec49bd06..f497ea28 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -135,7 +135,7 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> if code == 200: text = cast(str, data.data().decode("utf-8")) else: - fci.Console().printLog(f'Failed to fetch license. Name : "{ entry["license"].name }" , File : "{ entry["license"].file }"') + fci.Console.PrintLog(f'Failed to fetch license. Name : "{ entry["license"].name }" ,File : "{ entry["license"].file }"') text = text or entry["license"].name From 53c27aea9faf9d147349d527d7ff51fcab7629be Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:42:05 -0400 Subject: [PATCH 10/13] Fixed casting --- Addon.py | 3 ++- addonmanager_readme_controller.py | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Addon.py b/Addon.py index 035a65a0..8e782852 100644 --- a/Addon.py +++ b/Addon.py @@ -47,6 +47,7 @@ from addonmanager_metadata import ( Metadata, MetadataReader, + License, UrlType, Version, DependencyType, @@ -220,7 +221,7 @@ def __init__( self.python_min_version = Version(from_list=[3, 0, 0]) self._icon_file = None - self._cached_license: str = "" + self._cached_license: str | List[License|str] = "" self._cached_update_date = None def __eq__(self, other): diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 4bbf2180..7c5ad859 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -130,10 +130,10 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> if not entry: return - text = None + text : None | str = None if code == 200: - text = cast(str, data.data().decode("utf-8")) + text = data.data().decode("utf-8") else: fci.Console.PrintLog( f'Failed to fetch license. Name : "{ entry["license"].name }" , File : "{ entry["license"].file }"' @@ -234,7 +234,10 @@ def _create_non_wiki_display(self, view: TabView): if view == TabView.License: - addon = cast(Addon, self.addon) + addon = self.addon + + if not addon: + return licenses = addon.license @@ -254,8 +257,6 @@ def _create_non_wiki_display(self, view: TabView): if type(licenses) is list: - licenses = cast(list[License | str], licenses) - for license in licenses: text = QtWidgets.QTextEdit() From ce3f529f65b0986341d2f70cb1e036488394f308 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 02:42:21 +0000 Subject: [PATCH 11/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Addon.py | 2 +- addonmanager_readme_controller.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Addon.py b/Addon.py index 8e782852..9a01741d 100644 --- a/Addon.py +++ b/Addon.py @@ -221,7 +221,7 @@ def __init__( self.python_min_version = Version(from_list=[3, 0, 0]) self._icon_file = None - self._cached_license: str | List[License|str] = "" + self._cached_license: str | List[License | str] = "" self._cached_update_date = None def __eq__(self, other): diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 7c5ad859..40c7d4f2 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -130,7 +130,7 @@ def _download_completed(self, index: int, code: int, data: QtCore.QByteArray) -> if not entry: return - text : None | str = None + text: None | str = None if code == 200: text = data.data().decode("utf-8") @@ -235,7 +235,7 @@ def _create_non_wiki_display(self, view: TabView): if view == TabView.License: addon = self.addon - + if not addon: return From 1ea51a05ed44b719de5e9d9e6a306fecca0e70c3 Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Wed, 24 Sep 2025 05:10:52 -0400 Subject: [PATCH 12/13] Removed unused import --- addonmanager_readme_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addonmanager_readme_controller.py b/addonmanager_readme_controller.py index 40c7d4f2..e32d76e3 100644 --- a/addonmanager_readme_controller.py +++ b/addonmanager_readme_controller.py @@ -27,7 +27,7 @@ import addonmanager_utilities as utils import addonmanager_freecad_interface as fci -from typing import TypedDict, Optional, Dict, cast +from typing import TypedDict, Optional, Dict from enum import IntEnum, auto import NetworkManager From 8b0c958c9979b7720b918392bbfb33bb52156dba Mon Sep 17 00:00:00 2001 From: PhoneDroid <73050054+PhoneDroid@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:18:39 -0400 Subject: [PATCH 13/13] Adjusted tab titles --- Widgets/addonmanager_widget_package_details_view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Widgets/addonmanager_widget_package_details_view.py b/Widgets/addonmanager_widget_package_details_view.py index ceb88057..5eebc520 100644 --- a/Widgets/addonmanager_widget_package_details_view.py +++ b/Widgets/addonmanager_widget_package_details_view.py @@ -98,11 +98,11 @@ def _setup_ui(self): self.tabs_widget = QtWidgets.QTabWidget(self) self.tabs[TabView.Readme] = self.tabs_widget.addTab( - self.readme_browser, translate("AddonsInstaller", "README") + self.readme_browser, translate("AddonsInstaller", "Overview") ) self.tabs[TabView.License] = self.tabs_widget.addTab( - self.license_browser, translate("AddonsInstaller", "LICENSE") + self.license_browser, translate("AddonsInstaller", "License") ) self.message_label = QtWidgets.QLabel(self)