Skip to content

Networking

ctx.network is one injected HTTP client over one injected transport, the shape decision-4 fixed: coroutine methods are the UI-facing form, a blocking form exists for worker threads only, every response is fully buffered, and the live QNetworkReply never leaves the adapter. The host composes it; plugin code only ever sees Network.

from qgis_sdk.adapters.qgis import NativeNetworkTransport
from qgis_sdk.core import PluginContext, ResourceScope
from qgis_sdk.network import NetworkClient
scope = ResourceScope()
context = PluginContext(
notifications=notifications,
scope=scope,
network=NetworkClient(NativeNetworkTransport(scope), scope),
)
async def load(self, ctx):
api = ctx.network.configure(
base_url="https://example.org/api/",
headers={"Accept": "application/json"},
timeout=10,
auth_config="abc1234", # a QGIS authentication configuration id
)
response = await api.get("collections", params={"limit": 20})
return response.raise_for_status().json()

get/post/request are async def and suspend on a Handoff from qgis_sdk.core.scheduling: the job waits, the GUI thread does not. Cancelling the job aborts the reply; closing the owning scope aborts everything the client still has in flight, so a disposed plugin never gets a callback.

Blocking is explicit and off the GUI thread

Section titled “Blocking is explicit and off the GUI thread”

ctx.network.blocking.get(...) runs the same exchange on the calling thread under a local event loop and raises QgisSdkBlockingOnGuiThreadError on the GUI thread instead of nesting an event loop into the host’s. Use it from QThreadPool, QgsTask or a plain thread.

configure(base_url, headers, timeout, auth_config, max_redirects, max_body_bytes) returns a new client; nothing mutates a shared default, so a typed service client carries its own base URL without touching the plugin’s.

status_code, reason, headers (case-insensitive, credentials redacted in repr), content, text, json(), ok and raise_for_status(). A 404 is a response; only raise_for_status() turns it into QgisSdkHttpStatusError.

QgisSdkRequestRejectedError (bad URL, user-info in the URL, unsupported method), QgisSdkRequestCancelledError, QgisSdkConnectionError, QgisSdkRequestTimeoutError, QgisSdkTlsError, QgisSdkAuthenticationError, QgisSdkRedirectError, QgisSdkResponseTooLargeError, QgisSdkHttpStatusError, QgisSdkDecodeError, all under QgisSdkNetworkError with the method and the URL in the message.

30 s timeout, 20 redirects, 16 MiB buffered body; the last two were measured against QgsNetworkAccessManager on loopback servers, not chosen. A body over the ceiling is aborted while downloading, not buffered and then refused.

The native transport goes through QgsNetworkAccessManager, so the proxy, the certificate trust and the authentication database a user set in QGIS apply; auth_config is handed to QgsAuthManager.updateNetworkRequest, and no credential passes through the SDK. Trust changes made at runtime need rebuildTrustedCaCertsCache() and, for a host Qt already talked to, clearConnectionCache(); both are QGIS calls, not SDK ones.

Redirects are followed by the transport, not by Qt

Section titled “Redirects are followed by the transport, not by Qt”

The manager was measured forwarding Authorization and Cookie to another origin, so the transport follows hops itself and drops Authorization, Cookie, Proxy-Authorization and the auth configuration when scheme, host or port changes; https → http is refused.

qgis_sdk.network.OgcApiFeatures(network, base_url) is the first: collections(), items(collection_id, limit, bbox) and next_page(page) return dataclasses, and a malformed document is a QgisSdkServiceResponseError. WMS/WFS layers stay on QGIS providers.

qgis_sdk.testing.FakeNetworkTransport is scripted with expect(method, url, response | exception | responder, hold=False); an unexpected request fails the test with QgisSdkNetworkFakeError, a held request is released from the test with pending[0].deliver(), and assert_satisfied() reports unmet expectations. It never opens a socket. The native transport is covered by tests/test_network_native.py against loopback servers, including the QGIS proxy setting, a Basic authentication configuration, and a certificate trusted through the auth manager.