package dependency updates
This commit is contained in:
@@ -1184,6 +1184,7 @@ class MainApplication(QMainWindow):
|
|||||||
# for stat in stats[:10]:
|
# for stat in stats[:10]:
|
||||||
# print(stat)
|
# print(stat)
|
||||||
# print("Top 10 growing object types in RAM:")
|
# print("Top 10 growing object types in RAM:")
|
||||||
|
# objgraph has been removed so it will need to be reinstalled for this to work
|
||||||
# objgraph.show_most_common_types(limit=10)
|
# objgraph.show_most_common_types(limit=10)
|
||||||
|
|
||||||
def check_if_app_is_dirty(self):
|
def check_if_app_is_dirty(self):
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
Package Version Latest Type
|
||||||
|
------------------------- -------- ------------ -----
|
||||||
|
certifi 2026.1.4 2026.7.22 wheel
|
||||||
|
charset-normalizer 3.4.4 3.5.1 wheel
|
||||||
|
decorator 5.2.1 5.3.1 wheel
|
||||||
|
fonttools 4.61.1 4.64.0 wheel
|
||||||
|
h5py 3.15.1 3.16.0 wheel
|
||||||
|
idna 3.11 3.19 wheel
|
||||||
|
joblib 1.5.3 1.6.0 wheel
|
||||||
|
kiwisolver 1.4.9 1.5.1 wheel
|
||||||
|
lazy_loader 0.4 0.5 wheel
|
||||||
|
lxml 6.0.2 6.1.2 wheel
|
||||||
|
matplotlib 3.10.8 3.11.1 wheel
|
||||||
|
mne 1.11.0 1.12.1 wheel
|
||||||
|
mne-connectivity 0.7.0 0.9.0 wheel
|
||||||
|
neurokit2 0.2.12 0.2.13 wheel
|
||||||
|
nibabel 5.3.3 5.4.2 wheel
|
||||||
|
nilearn 0.13.0 0.14.0 wheel
|
||||||
|
numpy 2.4.1 2.5.2 wheel
|
||||||
|
packaging 25.0 26.3 wheel
|
||||||
|
pandas 2.3.3 3.0.5 wheel
|
||||||
|
patsy 1.0.2 1.0.3 wheel
|
||||||
|
pillow 12.1.0 12.3.0 wheel
|
||||||
|
pip 25.3 26.2.1 wheel
|
||||||
|
platformdirs 4.5.1 4.11.7 wheel
|
||||||
|
pooch 1.8.2 1.9.0 wheel
|
||||||
|
psutil 7.2.1 7.2.2 wheel
|
||||||
|
pyinstaller 6.19.0 6.22.2 wheel
|
||||||
|
pyinstaller-hooks-contrib 2026.3 2026.7 wheel
|
||||||
|
pyparsing 3.3.1 3.3.2 wheel
|
||||||
|
PySide6 6.10.1 6.11.2 wheel
|
||||||
|
PySide6_Addons 6.10.1 6.11.2 wheel
|
||||||
|
PySide6_Essentials 6.10.1 6.11.2 wheel
|
||||||
|
pytz 2025.2 2026.3.post1 wheel
|
||||||
|
pyvista 0.46.5 0.48.4 wheel
|
||||||
|
pyvistaqt 0.11.3 0.12.0 wheel
|
||||||
|
requests 2.32.5 2.34.2 wheel
|
||||||
|
scikit-learn 1.8.0 1.9.0 wheel
|
||||||
|
scipy 1.17.0 1.18.1 wheel
|
||||||
|
scooby 0.11.0 0.11.2 wheel
|
||||||
|
setuptools 82.0.1 84.0.0 wheel
|
||||||
|
shiboken6 6.10.1 6.11.2 wheel
|
||||||
|
statsmodels 0.14.6 0.15.0 wheel
|
||||||
|
tqdm 4.67.1 4.70.0 wheel
|
||||||
|
typing_extensions 4.15.0 4.16.0 wheel
|
||||||
|
tzdata 2025.3 2026.3 wheel
|
||||||
|
urllib3 2.6.3 2.7.0 wheel
|
||||||
|
vtk 9.5.2 9.7.0 wheel
|
||||||
|
xarray 2026.1.0 2026.7.0 wheel
|
||||||
Binary file not shown.
+73
-11
@@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Filename: plugins.py
|
Filename: plugins.py
|
||||||
Description: Plugins window
|
Description: Plugins window with deferred remote fetching and installation state checks.
|
||||||
|
|
||||||
Author: Tyler de Zeeuw
|
Author: Tyler de Zeeuw
|
||||||
License: GPL-3.0
|
License: GPL-3.0
|
||||||
@@ -10,7 +10,7 @@ License: GPL-3.0
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
# External library imports
|
# External library imports
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt, QThread, Signal
|
||||||
from PySide6.QtGui import QColor
|
from PySide6.QtGui import QColor
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
||||||
@@ -21,6 +21,20 @@ from plugin_manager import PluginManager, parse_version
|
|||||||
from src.shared.shareddata import APP_NAME, CURRENT_VERSION, PLUGINS_URL
|
from src.shared.shareddata import APP_NAME, CURRENT_VERSION, PLUGINS_URL
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteFetchWorker(QThread):
|
||||||
|
"""Background thread to fetch remote repository data without lagging the main UI."""
|
||||||
|
fetched = Signal(list, bool) # (plugins_data, all_failed)
|
||||||
|
|
||||||
|
def __init__(self, manager: PluginManager, urls: list[str]) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.manager = manager
|
||||||
|
self.urls = urls
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
plugins, all_failed = self.manager.fetch_remote_repositories(self.urls)
|
||||||
|
self.fetched.emit(plugins, all_failed)
|
||||||
|
|
||||||
|
|
||||||
class PluginsWindow(QWidget):
|
class PluginsWindow(QWidget):
|
||||||
|
|
||||||
def __init__(self, parent: QWidget | None, plugin_manager: PluginManager) -> None:
|
def __init__(self, parent: QWidget | None, plugin_manager: PluginManager) -> None:
|
||||||
@@ -29,12 +43,13 @@ class PluginsWindow(QWidget):
|
|||||||
self.main_app_window = parent
|
self.main_app_window = parent
|
||||||
self.manager: PluginManager = plugin_manager
|
self.manager: PluginManager = plugin_manager
|
||||||
|
|
||||||
self.setWindowTitle(f"{APP_NAME.upper()} - Plugins")
|
self.setWindowTitle(f"Plugins - {APP_NAME.upper()}")
|
||||||
self.resize(750, 500)
|
self.resize(750, 500)
|
||||||
|
|
||||||
self.repository_urls: list[str] = [PLUGINS_URL]
|
self.repository_urls: list[str] = [PLUGINS_URL]
|
||||||
self.remote_plugins_data: list[dict[str, Any]] = []
|
self.remote_plugins_data: list[dict[str, Any]] = []
|
||||||
self._has_fetched_remote: bool = False
|
self._has_fetched_remote: bool = False
|
||||||
|
self._fetch_worker: RemoteFetchWorker | None = None
|
||||||
|
|
||||||
# Refresh UI automatically if manager updates state
|
# Refresh UI automatically if manager updates state
|
||||||
self.manager.plugins_changed.connect(self.refresh_installed_plugins)
|
self.manager.plugins_changed.connect(self.refresh_installed_plugins)
|
||||||
@@ -74,6 +89,10 @@ class PluginsWindow(QWidget):
|
|||||||
self.installed_list.addItem("No plugins installed.")
|
self.installed_list.addItem("No plugins installed.")
|
||||||
self._clear_details_panel()
|
self._clear_details_panel()
|
||||||
|
|
||||||
|
# Re-populate browser list if remote data was already fetched to reflect newly installed/uninstalled plugins
|
||||||
|
if self._has_fetched_remote and self.remote_plugins_data:
|
||||||
|
self._populate_browser_list()
|
||||||
|
|
||||||
def _on_installed_item_changed(self, current: QListWidgetItem | None, _: Any) -> None:
|
def _on_installed_item_changed(self, current: QListWidgetItem | None, _: Any) -> None:
|
||||||
"""Updates the right-hand details panel when a plugin is selected."""
|
"""Updates the right-hand details panel when a plugin is selected."""
|
||||||
if not current:
|
if not current:
|
||||||
@@ -136,13 +155,25 @@ class PluginsWindow(QWidget):
|
|||||||
self.manager.uninstall_plugin(info["path"])
|
self.manager.uninstall_plugin(info["path"])
|
||||||
|
|
||||||
def fetch_remote_plugins(self) -> None:
|
def fetch_remote_plugins(self) -> None:
|
||||||
|
"""Asynchronously fetches remote plugins on a background thread."""
|
||||||
|
if self._fetch_worker is not None and self._fetch_worker.isRunning():
|
||||||
|
return # Fetch operation already in progress
|
||||||
|
|
||||||
self.browser_list.clear()
|
self.browser_list.clear()
|
||||||
self.browser_list.addItem("Fetching remote repositories...")
|
self.browser_list.addItem("Fetching remote repositories...")
|
||||||
self.btn_install.setEnabled(False)
|
self.btn_install.setEnabled(False)
|
||||||
|
self.btn_fetch.setEnabled(False)
|
||||||
|
|
||||||
plugins, all_failed = self.manager.fetch_remote_repositories(self.repository_urls)
|
# Defer network call to background worker to avoid UI freeze
|
||||||
|
self._fetch_worker = RemoteFetchWorker(self.manager, self.repository_urls)
|
||||||
|
self._fetch_worker.fetched.connect(self._on_remote_fetched)
|
||||||
|
self._fetch_worker.start()
|
||||||
|
|
||||||
|
def _on_remote_fetched(self, plugins: list[dict[str, Any]], all_failed: bool) -> None:
|
||||||
|
"""Callback executed on the main UI thread when remote fetching finishes."""
|
||||||
self.remote_plugins_data = plugins
|
self.remote_plugins_data = plugins
|
||||||
self._has_fetched_remote = True
|
self._has_fetched_remote = True
|
||||||
|
self.btn_fetch.setEnabled(True)
|
||||||
|
|
||||||
if plugins:
|
if plugins:
|
||||||
self._populate_browser_list()
|
self._populate_browser_list()
|
||||||
@@ -154,9 +185,17 @@ class PluginsWindow(QWidget):
|
|||||||
self.browser_list.addItem("No plugins found across configured repositories.")
|
self.browser_list.addItem("No plugins found across configured repositories.")
|
||||||
|
|
||||||
def _populate_browser_list(self) -> None:
|
def _populate_browser_list(self) -> None:
|
||||||
|
"""Populates the browser tab list and checks if each plugin is already installed."""
|
||||||
self.browser_list.clear()
|
self.browser_list.clear()
|
||||||
|
|
||||||
|
# Gather set of currently installed identifiers (by ID and Name)
|
||||||
|
installed_info = self.manager.get_installed_plugins_info()
|
||||||
|
installed_ids = {p.get("id") for p in installed_info if p.get("id")}
|
||||||
|
installed_names = {p.get("name") for p in installed_info if p.get("name")}
|
||||||
|
|
||||||
for plugin in self.remote_plugins_data:
|
for plugin in self.remote_plugins_data:
|
||||||
name = plugin.get("name", "Unknown")
|
name = plugin.get("name", "Unknown")
|
||||||
|
p_id = plugin.get("id", "")
|
||||||
version = plugin.get("version", "v0.0")
|
version = plugin.get("version", "v0.0")
|
||||||
desc = plugin.get("description", "")
|
desc = plugin.get("description", "")
|
||||||
platforms = plugin.get("platforms", [])
|
platforms = plugin.get("platforms", [])
|
||||||
@@ -166,16 +205,24 @@ class PluginsWindow(QWidget):
|
|||||||
is_version_ok = self.manager.current_app_version >= parse_version(min_v_str)
|
is_version_ok = self.manager.current_app_version >= parse_version(min_v_str)
|
||||||
is_compatible = is_platform_ok and is_version_ok
|
is_compatible = is_platform_ok and is_version_ok
|
||||||
|
|
||||||
|
# Check if plugin is already installed locally
|
||||||
|
is_installed = (bool(p_id) and p_id in installed_ids) or (bool(name) and name in installed_names)
|
||||||
|
|
||||||
display_text = f"{name} (v{version}) - {desc}"
|
display_text = f"{name} (v{version}) - {desc}"
|
||||||
if not is_compatible:
|
if is_installed:
|
||||||
|
display_text += " [Installed]"
|
||||||
|
elif not is_compatible:
|
||||||
display_text += " [Incompatible]"
|
display_text += " [Incompatible]"
|
||||||
|
|
||||||
item = QListWidgetItem(display_text, self.browser_list)
|
item = QListWidgetItem(display_text, self.browser_list)
|
||||||
item.setData(Qt.ItemDataRole.UserRole, plugin)
|
item.setData(Qt.ItemDataRole.UserRole, plugin)
|
||||||
item.setData(Qt.ItemDataRole.UserRole + 1, is_compatible)
|
item.setData(Qt.ItemDataRole.UserRole + 1, is_compatible)
|
||||||
|
item.setData(Qt.ItemDataRole.UserRole + 2, is_installed)
|
||||||
|
|
||||||
if not is_compatible:
|
if is_installed:
|
||||||
item.setForeground(QColor("#d32f2f"))
|
item.setForeground(QColor("#2e7d32")) # Green for installed
|
||||||
|
elif not is_compatible:
|
||||||
|
item.setForeground(QColor("#d32f2f")) # Red for incompatible
|
||||||
|
|
||||||
def install_selected_plugin(self) -> None:
|
def install_selected_plugin(self) -> None:
|
||||||
selected = self.browser_list.currentItem()
|
selected = self.browser_list.currentItem()
|
||||||
@@ -200,7 +247,21 @@ class PluginsWindow(QWidget):
|
|||||||
|
|
||||||
def _on_browser_item_changed(self, current: QListWidgetItem | None, _: Any) -> None:
|
def _on_browser_item_changed(self, current: QListWidgetItem | None, _: Any) -> None:
|
||||||
if current:
|
if current:
|
||||||
self.btn_install.setEnabled(bool(current.data(Qt.ItemDataRole.UserRole + 1)))
|
is_compatible = bool(current.data(Qt.ItemDataRole.UserRole + 1))
|
||||||
|
is_installed = bool(current.data(Qt.ItemDataRole.UserRole + 2))
|
||||||
|
|
||||||
|
# Disable install button if plugin is incompatible OR ALREADY INSTALLED
|
||||||
|
self.btn_install.setEnabled(is_compatible and not is_installed)
|
||||||
|
else:
|
||||||
|
self.btn_install.setEnabled(False)
|
||||||
|
|
||||||
|
def _on_add_repo(self) -> None:
|
||||||
|
"""Adds a custom repository URL and re-fetches plugins."""
|
||||||
|
url = self.repo_input.text().strip()
|
||||||
|
if url and url not in self.repository_urls:
|
||||||
|
self.repository_urls.append(url)
|
||||||
|
self.repo_input.clear()
|
||||||
|
self.fetch_remote_plugins()
|
||||||
|
|
||||||
def _create_installed_tab(self) -> QWidget:
|
def _create_installed_tab(self) -> QWidget:
|
||||||
tab = QWidget()
|
tab = QWidget()
|
||||||
@@ -284,6 +345,7 @@ class PluginsWindow(QWidget):
|
|||||||
self.repo_input = QLineEdit(tab)
|
self.repo_input = QLineEdit(tab)
|
||||||
self.repo_input.setPlaceholderText("Enter custom plugins.json URL...")
|
self.repo_input.setPlaceholderText("Enter custom plugins.json URL...")
|
||||||
btn_add = QPushButton("Add Repo", tab)
|
btn_add = QPushButton("Add Repo", tab)
|
||||||
|
btn_add.clicked.connect(self._on_add_repo)
|
||||||
|
|
||||||
repo_layout.addWidget(self.repo_input)
|
repo_layout.addWidget(self.repo_input)
|
||||||
repo_layout.addWidget(btn_add)
|
repo_layout.addWidget(btn_add)
|
||||||
@@ -292,14 +354,14 @@ class PluginsWindow(QWidget):
|
|||||||
self.browser_list.currentItemChanged.connect(self._on_browser_item_changed)
|
self.browser_list.currentItemChanged.connect(self._on_browser_item_changed)
|
||||||
|
|
||||||
btn_layout = QHBoxLayout()
|
btn_layout = QHBoxLayout()
|
||||||
btn_fetch = QPushButton("Fetch Remote Lists", tab)
|
self.btn_fetch = QPushButton("Fetch Remote Lists", tab)
|
||||||
self.btn_install = QPushButton("Install Plugin", tab)
|
self.btn_install = QPushButton("Install Plugin", tab)
|
||||||
self.btn_install.setEnabled(False)
|
self.btn_install.setEnabled(False)
|
||||||
|
|
||||||
btn_fetch.clicked.connect(self.fetch_remote_plugins)
|
self.btn_fetch.clicked.connect(self.fetch_remote_plugins)
|
||||||
self.btn_install.clicked.connect(self.install_selected_plugin)
|
self.btn_install.clicked.connect(self.install_selected_plugin)
|
||||||
|
|
||||||
btn_layout.addWidget(btn_fetch)
|
btn_layout.addWidget(self.btn_fetch)
|
||||||
btn_layout.addStretch()
|
btn_layout.addStretch()
|
||||||
btn_layout.addWidget(self.btn_install)
|
btn_layout.addWidget(self.btn_install)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user