diff options
| author | Christian Kolset <ckolset@colostate.edu> | 2026-07-29 13:21:05 -0600 |
|---|---|---|
| committer | Christian Kolset <ckolset@colostate.edu> | 2026-07-29 13:21:05 -0600 |
| commit | 45ff7227fabb97273d4645601733f90f5f744eb1 (patch) | |
| tree | 97dd17bf24d2a36c490856484bb4de8a2a8e8798 /ui/main_window.py | |
| parent | b407a079000f6a4b04ecf38eca17c57719e7a7ec (diff) | |
Check plugin dependencies before loading, warn instead of silent console error
manifest.json already had an unused "requires" field (motion_capture's
manifest lists opencv-python>=4.8.0) — PluginManifest never parsed it,
so a missing dependency just crashed the import inside _load_plugin(),
caught by the broad except and only ever printed to the console.
Adds PluginManifest.requires, PluginManager.missing_requirements()/
get_missing_dependencies(), and an early check in _load_plugin() that
skips the risky import entirely when a requirement is missing.
main_window.plugin_enable() now checks this before calling
PluginManager.enable() and shows a QMessageBox with the missing
packages and a pip install command instead of failing silently.
Checks by distribution name via importlib.metadata (what pip installed
it as), not import name — those differ for packages like opencv-python
(imports as cv2) or pyserial (imports as serial), so importlib.util.
find_spec() would give false negatives.
Also fixes a button-state bug this surfaces: SettingsWindow's plugin
toggle optimistically flipped to "Disable" the instant Enable was
clicked, before knowing whether enabling actually succeeds — pre-existing,
but now trivially reproducible (any plugin missing a dependency). Enable
no longer flips the button immediately; main_window calls the new
sync_plugin_button() once the real outcome is known.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'ui/main_window.py')
| -rw-r--r-- | ui/main_window.py | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/ui/main_window.py b/ui/main_window.py index d0e0ac4..95cdb84 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -296,10 +296,22 @@ class MainWindow(QMainWindow): def plugin_enable(self, plugin_id: str): """Called by SettingsWindow when user enables a plugin.""" - ctx = self._make_plugin_context() - plugin = self._plugin_mgr.enable(plugin_id, ctx) - if plugin: - self._install_plugin(plugin) + missing = self._plugin_mgr.get_missing_dependencies(plugin_id) + if missing: + from PyQt6.QtWidgets import QMessageBox + QMessageBox.warning( + self, "Missing Plugin Dependencies", + f"Can't enable this plugin — missing Python packages:\n\n" + f" {', '.join(missing)}\n\n" + f"Install with:\n pip install {' '.join(missing)}" + ) + else: + ctx = self._make_plugin_context() + plugin = self._plugin_mgr.enable(plugin_id, ctx) + if plugin: + self._install_plugin(plugin) + if self._win_settings: + self._win_settings.sync_plugin_button(plugin_id) def plugin_disable(self, plugin_id: str): """Called by SettingsWindow when user disables a plugin.""" |
