QGIS plugin development
How the lsdtt3 QGIS plugin is put together, how its versions fit together, and the loop for changing it.
Where the commands live. The exact packaging and release commands are in
tools/README.mdin the repository, and the end-user install and troubleshooting guide is the QGIS plugin page (generated fromqgis_plugin/README.md). This page explains how the pieces relate; it does not repeat those command sequences, because copies drift.
Two artefacts, built separately
The plugin does no analysis itself. Its Processing algorithms write a parameter
file and run the lsdtt-* command-line tools as subprocesses. A working
install therefore needs two things:
| Artefact | Source | Built by | Output |
|---|---|---|---|
| Plugin zip — pure Python | qgis_plugin/lsdtt_qgis/ |
python3 qgis_plugin/package_plugin.py (any platform) |
qgis_plugin/dist/lsdtt3-qgis-plugin-<plugin version>.zip |
| Backend bundle — the compiled CLIs plus their libraries and GDAL/PROJ data | cli/, src/ |
a per-platform packaging script, on that platform | dist/lsdtt3-backend-<platform>-<profile>-v<backend version>.{zip,tar.gz} |
In QGIS, the plugin is installed from the zip, and pointed at the unpacked
backend in lsdtt3 → LSDTT Backend Settings. Select the bundle root (the
folder containing bin/, share/ and manifest.json), not bin/.
Which CLIs the backend needs
The qgis profile in tools/cli_profiles.txt is the list of CLIs the plugin
wraps. It is the single source of truth for every packaging script. Each CLI
has a wrapper in qgis_plugin/lsdtt_qgis/algorithms/.
The plugin keeps the same list as REQUIRED_CLIS in
qgis_plugin/lsdtt_qgis/backend/health.py, and checks that the configured
backend has them. Saving a backend in LSDTT Backend Settings checks all
of them and warns, naming every missing CLI; the path is still saved. Running
an algorithm checks only that algorithm's CLI, so an older bundle still runs
the algorithms it has, and the others stop with an error naming the missing
CLI before anything runs. test_backend_health.py fails if REQUIRED_CLIS differs from the
qgis profile or from the CLIs named in algorithms/*.py.
Backend per platform
| QGIS on | Build | Package |
|---|---|---|
| Windows | Native Windows in build\windows-qgis |
tools\package_windows_backend.ps1 (default profile qgis) |
| Linux | Linux | tools/package_linux_backend.sh --cli-profile qgis |
| macOS | Native in build/macos-qgis |
tools/package_macos_backend.sh (default profile qgis; built by release.yml on every tag) |
A WSL2 build cannot serve as the backend for a Windows QGIS: its binaries are Linux executables.
Versions: one number, one rule
lsdtt3 has one version number. The plugin, the backend bundles, the C++ package
and the Python package all carry the X.Y.Z in project(lsdtt3 VERSION ...)
on line 2 of CMakeLists.txt.
| Copy | Where it is set | What reads it |
|---|---|---|
| Plugin version | qgis_plugin/lsdtt_qgis/metadata.txt ([general] version=), a checked copy |
the zip filename; the compatibility check |
| Backend version | the -Version / --version you pass to the packaging script, which must equal CMakeLists.txt |
the bundle filename; manifest.json → backend_version |
tools/set_version.py X.Y.Z changes every copy together, and the CTest test
unit_version_consistency fails if they differ. CLIs have no version of their
own: each carries a stability label, k_status (experimental or stable),
which the banner, -v and --help-json report. The plugin does not read it.
When QGIS loads a backend, qgis_plugin/lsdtt_qgis/backend/manifest.py rejects
it unless both of these hold:
- The backend has the plugin's major.minor version. A plugin
X.Y.*accepts a backendX.Y.*; the patch level is free, so a plugin-only or backend-only patch release still works with the other. A backend from an older series gets "install the lsdtt3 X.Y backend bundle"; a newer one gets "upgrade the plugin". - The plugin version satisfies the bundle's
plugin_version_range. The packaging scripts write this intomanifest.json. The default is the bundle's own series,>=X.Y.0 <X.(Y+1).0; override it with-PluginVersionRange(PowerShell) or--plugin-version-range(bash).
[!WARNING]
backend_versionmust be plainX.Y.Z. The plugin's version parser accepts digits and dots only. A suffixed version such as0.5.0-rc1or0.5.0-local-dirtypackages without complaint and is then refused by the plugin as an invalidbackend_version. For a local test bundle, use a plain version number.
Rules of thumb:
- A wrapper change that needs a new CLI behaviour (a renamed parameter, a new key) is a minor version bump. That is what keeps an older backend from being accepted: the bump moves the plugin into a series the old backend is not in.
- A fix that needs no change on the other side is a patch bump.
- Plugins up to 0.4.0 predate this rule. Faced with a 0.7 backend they report that it "supports plugin versions '>=0.7.0 <0.8.0'"; the fix is to upgrade the plugin.
Development loop
Changing the plugin (Python only)
- Edit
qgis_plugin/lsdtt_qgis/. - Run the plugin unit tests. They do not need QGIS:
cd qgis_plugin pixi run python -m pytest lsdtt_qgis/tests - Bump
metadata.txtif this is going to anyone else. python3 qgis_plugin/package_plugin.py, then in QGIS Plugins → Manage and Install Plugins… → Install from ZIP. Installing over the old version replaces it; restart QGIS if the old behaviour persists.
Changing a CLI the plugin wraps
- Change and test the CLI on Linux as usual.
- If a parameter was added or renamed, update the wrapper in
qgis_plugin/lsdtt_qgis/algorithms/and its tests. - Rebuild the backend on the platform QGIS runs on, and package it (see the
table above, and
tools/README.mdfor the commands). - Unzip to a new, versioned folder, and point LSDTT Backend Settings at it. Keeping old bundles makes it easy to switch back.
Adding a CLI to the plugin
- Write the wrapper in
qgis_plugin/lsdtt_qgis/algorithms/and register it inqgis_plugin/lsdtt_qgis/provider.py. A CLI that computes several independent products can be several algorithms, one short form each:drainage_analysis.pydoes this forlsdtt-drainage-analysiswith a shared base class, and writes everywrite_*switch so a run produces only what its form asked for. - List the algorithm in the table in
qgis_plugin/README.md(the user page on the documentation site). - Add the CLI to the
qgisprofile intools/cli_profiles.txt, so every packaging script ships it, and toREQUIRED_CLISinqgis_plugin/lsdtt_qgis/backend/health.py. The plugin tests fail until all three lists agree. - Add its target to the native Windows build command in Building on Windows.
See also
- QGIS plugin — end-user install, update and troubleshooting
tools/README.md— packaging and release commands- Making release packages — what the bundles are and how releases are published
- Building on Windows — the native Windows backend build