Skip to content

0.7.0 migration notes

Parameter kinds (decision-46 point 1). Six kinds join LayerInput/CrsInput/Metres: FileInput(filters=), DirectoryInput(), FieldInput(of=), Range(min, max), Colour() and Literal[...] choices (the table under “Providers” above). What changes for existing code:

  • A Literal[...] of strings is now the enum kind for algorithms: it was refused at declaration in 0.6 and now renders a QgsProcessingParameterEnum. Actions and jobs already accepted Literal; they are unchanged.
  • Declared inputs with a marker carry "x-qgis-sdk": {"kind": ...} in their schema (a Range also carries minimum/maximum). The keyword is accepted by both validators and the generator; a generated bridge.schema.ts gains /** @qgis-sdk-kind ... */ on those fields and its CONTRACT_FINGERPRINT moves - regenerate with qgis-sdk bridge generate. Pages reading request.properties[...] see one more key.
  • FileRef moved to qgis_sdk.models (qgis_sdk.bridge.authority still re-exports it) and gained kind = "directory"; FILE_REF lists both kinds, so the host contract’s HOST_FINGERPRINT moved (sha256:af91deac…); the schema and protocol versions did not. HostAuthority.grant_directory mints a directory read ref; resolve_file checks the ref’s kind against the grant.
  • NativeProcessing(..., authority=) and register_provider(..., authority=) accept the host authority the toolbox mints picker refs through; without one each provider owns its own.
  • FieldSpec gained details; FieldSpec.to_dict() emits it.
  • qgis_sdk.algorithms.input_refusal is the one rule a toolbox run, a page call and a form use to refuse a value; parameter_kind keeps its name and now delegates to qgis_sdk.declarations.resolve_kind.

Input components and ctx.files.

  • qgis_sdk.ui exports the eleven input components (LayerPicker, FieldPicker, CrsPicker, FileInput, DirectoryInput, Distance, Number, Text, Toggle, Choice, Colour), Component, Option and coerce_value; see Input components above. Surface.build() may return a component; the host attaches and mounts it.
  • PluginContext gained the files capability (qgis_sdk.services.Files, implemented by qgis_sdk.files.FilesService); UiContext gained files, layers and project. A context that lacks them refuses by name as before, and has("layers") on a UiContext is now a real probe rather than a ValueError.
  • The Desktop host builds one HostAuthority per runtime and hands it to Processing (NativeProcessing(authority=)), to ctx.files and - through HostServices.from_context, which now defaults to the context’s files.authority - to the WebEngine host. A host that built its own HostServices(authority=...) keeps it; pass none to share.
  • qgis_sdk.testing.FakeFiles.
  • Form coercion (coerce_values, and so UiContext.actions, the declared form dialog and the bridge) now refuses a negative Metres value (“a distance of 0 or more metres”), matching the spin box and the Processing parameter; refusal messages keep their action '<id>': field <name> expects ... shape.

Form, Button, Column; NativeForms and DeclaredFormDialog removed. See Forms: an action’s inputs as a window.

  • qgis_sdk.adapters.qgis.ui is gone: NativeForms(runtime), .fields(id), .render(id), .run(id), .dispatch(id, values) and DeclaredFormDialog. Migration, line by line:

    0.6 0.7
    NativeForms(runtime).fields("buffer") Form.for_action(ctx, "buffer").fields (components; form_fields(description) still gives the FieldSpecs)
    dialog = forms.render("buffer"); dialog.widget("layer_id") form = Form.for_action(self.ctx, "buffer") inside a Dialog.build(); form.field("layer_id").widget after mount
    dialog.values() form.values()
    forms.dispatch("buffer", values) form.submit() (or self.ctx.actions.buffer(**values))
    forms.run("buffer") (modal, None on cancel) a Dialog subclass returning Column([form, Button]), opened by a binding or ctx.ui.open; add your own cancel Button calling self.ctx.view.request_close()

    A form carries the view’s authority, so FileInput/DirectoryInput fields, which the 0.6 dialog refused by name, now render and submit FileRefs.

  • qgis_sdk.ui exports Form, Button, Column, Input, input_for, schema_fields, ViewActions, ActionCall. Component is now the identity/lifecycle base shared with containers; the eleven inputs subclass Input and accept required=. Component.attach(ctx) with the same context is a no-op (a container attaches its children); a second context is still refused.

  • ViewActions.describe(action_id) is public: the declared description a form builds from.

  • form_fields refusals name their owner (action 'x': field ...) as before; schema_fields(schema, owner=) is the same rule for a bare schema (form: field ...).

  • ctx.notifications gained success, warning, critical and with_action(label, action_id, **arguments); info is unchanged. A hand-written Notifications double with info only keeps working for code that calls info; subclass qgis_sdk.services.NotificationsBase and implement _deliver(notification) to get all four plus the button. RecordingNotifications.messages is unchanged; records, press() and bind_actions() are new. NativeNotifications(sink=) now receives a Notification, not a string. MessageBarNotifications pushes at the level and grows bind_actions, which DesktopHost.initGui calls.

  • qgis-sdk check reports UI001; the scaffold’s PingDialog already names its widgets. The desktop-adapter qualification fixture gained a Form-built dialog and the form_submitted stage.

Wiring, mixins, containers, feedback, Custom, ctx.log. See Wiring, Containers, feedback, buttons and Custom, Behaviour mixins, Designer files and the pure-PyQt path and Testing surfaces without QGIS above.

  • qgis_sdk.ui exports on, subscribe, wire_surface, wires_of, StreamEvent, ViewStreams, ViewSubscription, load_ui, the containers Panel/Group/Tabs/Row (next to Column), the feedback JobProgress/LogView/ResultTable, the buttons RunButton/AcceptCancel (next to Button), Custom, ui_snapshot and the mixins RunsJobs/SubscribesStreams/HasAcceptCancel. Surface gained the ui class attribute and the on_accept()/on_close() hooks; a plain class with kind and a ctx constructor argument is accepted in surfaces (the widget form).
  • A Button/Form listener connected by hand inside build() keeps working; the @on form is the one the fake wires for you, so a test that called build() directly and clicked should move to build_surface.
  • UiContext gained log and streams and the on(stream, callback) method; PluginContext gained log (qgis_sdk.services.Log, NativeLog on the Desktop, RecordingLog in qgis_sdk.testing). fake_ui_context(runtime=) builds actions and streams.
  • A view’s own synchronous push during ctx.actions.<id>() is delivered with StreamEvent.echo = True; bridge subscribers are unchanged.
  • qgis-sdk check reports UI002 and the warning UI004; check_bindings(..., directory=) is how the Designer file is found.
  • The simple example gained ResultsDock, a Dock of the catalogue; the scaffold’s PingDialog uses @on("ping").clicked instead of button.clicked.connect.

The declarative surface form (decision-55 amendment). See The declarative form above.

  • Every component’s name is optional and every catalogue class has a keyword form; Component gained __set_name__, named, lazy label and object_name, Button.text is a property, RunButton.progress is readable. A Container checks for clashing child names when built and when attached (declared children get their names after the class body).
  • Surface.build()’s default returns the declared tree before refusing; qgis_sdk.ui.declarative (declared_components, materialise, declared_root, resolve_declared) is what the host, build_surface and wire_surface use; Wire.target may be a Component.
  • derive_title capitalises a lower-camel name (fieldTools → Field Tools); it read field Tools before.
  • ResultsDock in the example is declared; its button is buttons/fixture (was buttons/open) and the table self.results (was self.table).
  • Adoption: Form accepts unnamed inputs and keys them by name lazily (Form._fields resolves on first use; a form of inputs that never get a name refuses when read); the default build() seeds declared inputs from initial and refuses an unknown key (qgis_sdk.ui.declarative.apply_initial, declared_inputs); snapshot nodes of declared components carry "attribute" (Component.attribute); qgis-sdk check gained UI005; the scaffold’s PingDialog is declared (form/value, buttons/ping, feedback/answers; it was value, ping and answer built in PyQt).

Any registered algorithm (decision-64). See Any registered algorithm above. Nothing existing breaks; what is new:

  • Algorithms gains providers(), list(provider=None), describe(id) and run(request, params=None); execute and BufferRequest / CentroidRequest stay as they are and are documented as the predecessors of native.Buffer / native.Centroids. FakeAlgorithms answers list/describe from the shipped snapshot and run from script_run(...); its runs list records every run as an AlgorithmRun.
  • New generated subpackage qgis_sdk.processing (native, qgis, gdal, p3d, pdal, catalogue.json) and new models ProviderInfo, AlgorithmInfo, ParameterInfo, OutputInfo, AlgorithmRun, RunResult, RunOutput; new errors QgisSdkAlgorithmNotFoundError, QgisSdkAlgorithmRejectedError, QgisSdkAlgorithmFailedError.
  • Host operations algorithms.providers/list/describe/run behind the grants algorithms.read / algorithms.run; HOST_FINGERPRINT moved once to sha256:16790dc8…. qgis-sdk new --web grants algorithms.run, writes web/src/processing.schema.ts and runs qgis-sdk processing generate --check from bindings.
  • New developer command qgis-sdk processing generate (tools never import QGIS: the reader runs in the project’s interpreter) and the repo script scripts/generate_processing_snapshot.py with a CI drift check.