summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorChristian Kolset <ckolset@colostate.edu>2026-08-04 16:10:47 -0600
committerChristian Kolset <ckolset@colostate.edu>2026-08-04 16:10:47 -0600
commitb070d2849e4b3ac45e2ba270f7f02a491899eb08 (patch)
tree87c3b6bd79cdf1279ceed79d57245ced3c78a50e /docs
parent4a77f5825efe2905e22998cd784983eb914c1fc2 (diff)
Added plugin zip file creation instructions
Diffstat (limited to 'docs')
-rw-r--r--docs/plugin-development.md24
1 files changed, 23 insertions, 1 deletions
diff --git a/docs/plugin-development.md b/docs/plugin-development.md
index 8722376..c9ec492 100644
--- a/docs/plugin-development.md
+++ b/docs/plugin-development.md
@@ -2,6 +2,8 @@
Plugins live under `plugins/` as self-contained directories. The app discovers them automatically; the user enables or disables them in **Settings → Plugins**. A disabled plugin leaves zero trace in the UI.
+Plugins can also be installed at runtime as a `.zip` file via **Settings → Plugins → Install Plugin…** — no need to hand-copy files into `plugins/`. See [§1.1](#11-installing-from-a-zip).
+
---
## Table of Contents
@@ -43,6 +45,22 @@ from my_device import MyDevice # works inside plugin.py
from ui.my_window import MyWindow # works too
```
+### 1.1 Installing from a .zip
+
+`PluginManager` scans two locations: the bundled `plugins/` dir in the repo, and a per-user dir (`PluginManager(user_dir, extra_scan_dirs=[project_plugins])`). **Settings → Plugins → Install Plugin…** lets a user pick a `.zip` and calls `PluginManager.install_from_zip(zip_path)`, which:
+
+- requires the zip contain exactly **one top-level directory**, matching the layout above (`my_plugin/manifest.json`, `my_plugin/plugin.py`, ...)
+- extracts it into the user dir (overwriting any existing folder of the same name)
+- re-runs `discover()` and returns the new `PluginManifest`
+
+Plugins installed this way show a **Remove** button in Settings (`PluginManager.uninstall(plugin_id)` — deletes the folder; the plugin must be disabled first). Bundled plugins under the repo's `plugins/` dir are not removable — `is_user_installed()` is `False` for them.
+
+When packaging a plugin for distribution, zip the plugin directory itself (not its contents) so the single-top-level-dir rule holds:
+
+```bash
+zip -r my_plugin.zip my_plugin/
+```
+
---
## 2. manifest.json
@@ -54,7 +72,9 @@ from ui.my_window import MyWindow # works too
"version": "1.0.0",
"description": "One-line description shown in Settings.",
"author": "Your Name",
- "entry_point": "plugin.MyPlugin"
+ "entry_point": "plugin.MyPlugin",
+ "requires": ["opencv-python>=4.8.0"],
+ "source_url": "https://github.com/you/my_plugin"
}
```
@@ -66,6 +86,8 @@ from ui.my_window import MyWindow # works too
| `description` | No | One sentence. Shown in Settings. |
| `author` | No | Shown in Settings. |
| `entry_point` | No | `"module.ClassName"` relative to the plugin dir. Defaults to `"plugin.Plugin"`. |
+| `requires` | No | List of pip-style requirement strings (e.g. `"numpy>=1.24"`). Checked via `importlib.metadata` against the installed distribution name (not the import name — `opencv-python` imports as `cv2`). A plugin with unmet requirements fails to load; missing deps are printed to the console. |
+| `source_url` | No | Informational link to where the plugin comes from. Not currently rendered in the UI. |
---