Skip to content

0.6.0 migration notes

Project shape (decision-43). A 0.6 project carries no metadata.txt, classFactory or webview.py; qgis-sdk check reports the old files as META001/ENTRY002. To migrate a 0.5 project:

  1. Delete <plugin>/metadata.txt and <plugin>/webview.py; remove classFactory, the build_context/notifications glue and the desktop wrapper class from <plugin>/plugin.py and the from .plugin import classFactory line from <plugin>/__init__.py. What remains is the @plugin class (plus your own modules).
  2. Add to pyproject.toml: [project] name, version, description, authors and dependencies = ["qgis-sdk-runtime>=0.6,<0.7"]; [tool.qgis-sdk] plugin = "<package>.plugin:<Class>", qgis-minimum-version, experimental; any extra metadata.txt keys under [tool.qgis-sdk.metadata]; with a page, [tool.qgis-sdk.web] placement = "dock" | "dialog" and grants = [...] naming the host operations the page calls (the former webview.py registered them all; list the ones you use - qgis-sdk check names an unknown id).
  3. In the project’s own tests, bind the entry point the way build does: classFactory = host("<package>.plugin:<Class>", placement=...) from qgis_sdk.adapters.desktop.

qgis-sdk build and qgis-sdk dev then produce metadata.txt and classFactory themselves; see Desktop host above.

0.6.0 of qgis-sdk-runtime changes how a job is written (decision-38) and how optional services are reached on every context (decision-39). Everything about submission, handles, delivery and ownership is as in 0.5.

  • require_<name>() is gone; the attribute refuses by name. On PluginContext, UiContext, AlgorithmContext and JobContext every optional service (desktop, network, layers, project, settings, styles, algorithms, workers) is now typed as the service itself and reading one the host did not provide raises QgisSdkUnsupportedCapabilityError(capability=<name>) — the same error require_<name>() raised, now on ctx.workers.offload(...) directly. Replace ctx.require_workers() with ctx.workers, ctx.require_native() with ctx.desktop, and so on; constructor keyword arguments are unchanged. Code that probed a slot (if ctx.network is not None:) uses ctx.has("network") or ctx.capabilities instead - the attribute no longer evaluates to None, and has() raises ValueError for a name the context does not carry. Contexts are no longer dataclasses: they stay immutable (AttributeError on assignment) but dataclasses.replace/asdict do not apply to them.

  • @job decorates a function, not a class. The first parameter is the JobContext the runtime injects, the remaining parameters are typed keyword inputs (defaults allowed, the same annotations an @action accepts) and the return annotation is the result. delay takes the inputs as keywords and refuses a submission that does not fit the signature with QgisSdkJobRejectedError before anything is queued. ctx.jobs.delay(fn, **inputs) is the one-call spelling of bind then delay. The class form is refused by @job and bind with a message that names the change; see Migrating from the 0.5 class form for the side-by-side.

  • JobDescription describes a signature. inputs_type is gone; parameters, required and annotations describe the keyword inputs and inputs_schema is their object schema (so to_dict()["inputs"] is the schema itself, not {"type": ...}). result_type / result_schema are unchanged. describe(fn) answers for a @job function; the refusal for an undecorated class now reads “describe requires a class declared with @plugin, or a function declared with @job or @provider.algorithm”.

Algorithms follow the same move (decision-42). Every rename, in one list:

  • @provider.algorithm decorates a function, not a class. run(self, inputs: Request) -> Result becomes def name(ctx: AlgorithmContext, **typed inputs) -> VectorLayerInfo; the request dataclass’s fields become the keyword parameters and the result dataclass’s output becomes the return value. The class form is refused with a message naming the change. The bare @algorithm decorator and qgis_sdk.algorithms.algorithm are gone: a provider is the only container. A derived algorithm id is now the plain function name (no hash suffix); pass id= to keep an old suffixed id. The class-form inspectors declarations.RunSignature / describe_run_method (never in __all__) went with it; describe(fn) is the one inspector.
  • invoke(Class, Request, algorithms=, project=, scope=, ...) becomes invoke(function, ctx, **inputs): pass the PluginContext, JobContext or AlgorithmContext you hold instead of its three services, and the inputs as keywords. It returns the VectorLayerInfo directly; AlgorithmResult and result.output are gone. progress=, cancellation= and add_to_project= keep their meaning; left out, progress and cancellation now come from a job or algorithm context.
  • register_provider(...) / bridge.unregister() leave the plugin. Delete those lines from initGui/unload and add providers = [tools] to the @plugin class; PluginRuntime.start()/unload() register and remove them through the new processing capability of PluginContext (native_plugin_context supplies NativeProcessing; qgis_sdk.testing gains FakeProcessing). register_provider is no longer exported from qgis_sdk.adapters.qgis.
  • LayerInput, CrsInput, Metres are annotation aliases. Annotated[str, LayerInput()] becomes LayerInput (or Annotated[str, LayerParameter()]), Annotated[str, CrsInput()] becomes CrsInput (CrsParameter), Annotated[float, Metres()] becomes Metres (MetresParameter); a bound moves to Annotated[float, MetresParameter(minimum=..., maximum=...)]. This applies to @action parameters too - qgis_sdk.ui and NativeForms read the new markers.
  • AlgorithmDescription describes a signature. inputs_type is gone; parameters, required, annotations and kinds describe the inputs, inputs_schema is their object schema, and group, provider_id and qualified_id are on the description. ProviderDescription.algorithms is a tuple of AlgorithmDescription (RegisteredAlgorithm is gone), and Provider.class_for is Provider.function_for. parameter_kinds(dataclass) is qgis_sdk.algorithms.parameter_kind(path, annotation); LAYER_PARAMETER, CRS_PARAMETER, METRES_PARAMETER live there too.
  • qgis_sdk.reference is gone. BufferLayer/BufferResult/ CentroidLayer/CentroidResult have no runtime replacement: what a plugin computes is the plugin’s, so the two operations live in the example as examples/simple/simple/algorithms.py (provider = Provider(id="simple", ...), buffer_layer, centroid_layer; toolbox ids simple:buffer and simple:centroid). Copy that module into your plugin and rename the provider; the request models BufferRequest/CentroidRequest and the native service behind ctx.algorithms.execute are unchanged. The runtime keeps no Processing algorithms of its own.
  • Contexts gain capabilities, additively. JobContext carries algorithms and project (JobService(..., algorithms=, project=)), AlgorithmContext carries project, and PluginContext carries processing; all are optional constructor keywords that refuse by name when a host leaves them out. The wire contract, describe_plugin output and HOST_FINGERPRINT do not move.
  • Desktop bindings and surfaces (decisions 45 and 55), additively. qgis_sdk exports toolbar, menu, shortcut and describe_bindings; qgis_sdk.ui exports Dialog, Dock and Surface next to the 0.5 form-field helpers, which moved to qgis_sdk.ui.form_fields and are re-exported from qgis_sdk.ui unchanged. PluginContext gains an optional ui capability (host() supplies it inside QGIS Desktop; qgis_sdk.testing.FakeUi elsewhere) and UiContext gains actions and settings. A plugin that places its own QActions in initGui keeps working; moving them to @toolbar/@menu lets host() add and remove them with the plugin. See Desktop bindings and native surfaces.

qgis-sdk-tools 0.6.0 changes one thing in what qgis-sdk bridge generate emits (decision-40):

  • The generated contract error is QgisSdkContractError (was ContractError). It still extends Error - the module stays import-free - and now carries code: "contract_validation_failed" next to operation. Regenerate the client (CI fails on the stale file anyway) and rename the class in catch clauses, or match on error.code. The bridge package this release pairs with is @archont561/qgis-sdk 0.4.0, whose own notes are in doc-13.