synology_apm_repo.sdk.storage.azure module

AzureStore — a real, executable ObjectStore implementation for Azure Blob Storage, matching the s3 module’s scope, structure, and contract exactly (same four methods, same EOF/NotFoundError semantics, same lazy-import pattern) — this one only differs where the Azure SDK’s own shapes force a difference. list_containers mirrors that module’s list_buckets().

The one genuine shape difference from S3Store: Azure’s hierarchical listing (azure.storage.blob.ContainerClient.walk_blobs) already returns one unified sequence of BlobProperties/BlobPrefix entries, so there’s no separate paginated “common prefixes” collection to merge in the way S3’s CommonPrefixes/Contents split requires; the SDK’s own ItemPaged/AsyncItemPaged iterator handles continuation-token pagination internally too.

Why ``azure.storage.blob.aio``: this is network I/O, and — like S3Store — this module sits on aiohttp, where many outstanding round-trips genuinely overlap on one thread; that’s a real gain over a thread-pool wrapper around a synchronous client. Its client owns an aiohttp session that must be closed, hence AzureStore.aclose, which Session.close() calls.

Every client this module builds goes through _with_default_timeouts, which trims azure-core’s batch-job-tuned defaults down to values an interactive caller — the TUI’s connect dialog, in particular — can actually wait through when an endpoint is unreachable (see the module-level constants below for the exact values).

class synology_apm_repo.sdk.storage.azure.AzureStore(container, *, client=None, **client_kwargs)

Bases: object

An Azure Blob Storage container, addressed by "/"-separated paths relative to the container root.

client, if given, is used as-is (tests inject a mocked BlobServiceClient this way — the contract this class must get right is status-code-to-ObjectStore-semantics translation, not anything a live Azurite instance would exercise differently); otherwise one is built from client_kwargs (most commonly account_url, one of credential/connection_string) after _resolve_shared_key_credential resolves a plain-string credential against account_url.

async aclose()

Close the underlying aiohttp transport.

Only for a client this class built itself — an injected client belongs to whoever created it. Safe to call more than once.

async read(path, offset=0, length=None)
async size(path)
async exists(path)

True for either a blob exactly at path, or a “directory” — a prefix with at least one blob under it: db/ @data are never blobs in their own right on an object-storage layout, only prefixes with real blobs underneath (layout.py relies on this).

async listdir(path)

An absent “directory” (a prefix with zero blobs under it) and an empty one are indistinguishable in an object store with no real directory entities — both correctly report [], the same as S3Store.listdir.

async synology_apm_repo.sdk.storage.azure.list_containers(**client_kwargs)

Every container visible to these credentials — a container-less operation AzureStore has no method for, since all four of its methods are scoped to one chosen container. Builds its own transient client the same lazy-import way AzureStore does and closes it before returning; no lifecycle for a caller to manage beyond this one call.

client_kwargs is exactly what a caller would otherwise pass to AzureStore. Raises whatever the underlying SDK call raises — most notably HttpResponseError when the credential has no account-level “list containers” permission, which a container-scoped SAS token never does — unhandled, the same as every other backend-specific exception AzureStore’s own methods let propagate.