azuredol
Access Azure Blob Storage through a Mapping interface.
azuredol exposes Azure Blob Storage as dol-style Mapping /
MutableMapping interfaces.
Quick start:
from azuredol import azure_store
# Uses connection_string env var or Azurite (UseDevelopmentStorage=true)
store = azure_store(
'mycontainer',
connection_string='UseDevelopmentStorage=true',
create_container_if_missing=True,
)
store['k1'] = b'hello world'
store['k1'] # → b'hello world'
'k1' in store # → True
del store['k1']
See misc/docs/architecture.md for the layered design.
- class azuredol.AccountCollection(connection: AzureConnection | BlobServiceClient | str | dict | None = None, *, container_store_cls: type = None, container_store_kwargs: dict | None = None)[source]
Mapping over container names in an account (iter / contains / len).
- class azuredol.AccountReader(connection: AzureConnection | BlobServiceClient | str | dict | None = None, *, container_store_cls: type = None, container_store_kwargs: dict | None = None)[source]
Adds
__getitem__returning aContainerStore(or configured subclass).
- class azuredol.AccountStore(connection: AzureConnection | BlobServiceClient | str | dict | None = None, *, container_store_cls: type = None, container_store_kwargs: dict | None = None)[source]
Read-write Mapping over containers in an account.
__setitem__creates a container; the value is ignored except when it’s a Mapping (in which case it is treated as an initial bulk-load).__delitem__refuses non-empty containers — callself.delete(name, force=True)to acknowledge a cascading delete. Seemisc/docs/design_decisions.md§12.
- class azuredol.AzureConnection(credential: str | dict | Any | None = None, connection_string: str | None = None, account_url: str | None = None, account_key: str | None = None, client_kwargs: dict = <factory>)[source]
Holds a resolved credential and a lazy
BlobServiceClient.This is the dependency-injection seam for the whole package. Tests construct one pointing at Azurite without touching any store class.
- Parameters:
credential – explicit credential object, key string, or SAS string.
connection_string – full connection string (overrides
credential).account_url – storage account URL (with or without credential).
account_key – shared-key for the account.
All four args are optional; the credential cascade in
resolve_credentialis consulted if none are provided.- blob_client(container: str, blob: str)[source]
Cheap derivation of a
BlobClientfrom the shared service client.
- container_client(container: str)[source]
Cheap derivation of a
ContainerClientfrom the shared service client.
- classmethod from_anything(source) AzureConnection[source]
Convenience: build an
AzureConnectionfrom a thing-or-spec.- Accepts:
AzureConnection(returned as-is)BlobServiceClient(wrapped without further resolution)str(connection string)dict(passed as kwargs)None(defer to env / AAD)
- property service_client: BlobServiceClient
The lazily-constructed
BlobServiceClient. Cached for the connection’s lifetime.
- azuredol.AzureJsonStore
alias of
ContainerStore
- azuredol.AzurePickleStore
alias of
ContainerStore
- azuredol.AzureTextStore
alias of
ContainerStore
- exception azuredol.BlobAlreadyExistsError[source]
Raised on strict-create write attempts when the blob already exists.
KeyErrorsubclass for symmetry withBlobNotFoundError— both signal a key-vs-store mismatch.
- class azuredol.BlobHandle(container: str | ContainerClient, blob: str, *, connection: AzureConnection | BlobServiceClient | str | dict | None = None)[source]
Thin facade over one
BlobClient. Not a Mapping.Use when you need the full Azure-blob surface for a single blob: metadata, properties, conditional writes, leases, copy, append, SAS URL generation, streaming downloads.
- Parameters:
container – An existing
ContainerClientor a container name string.blob – The blob name (relative to the container root; full path including ‘/’).
connection – Ignored if
containeris aContainerClient. Otherwise resolved viaAzureConnection.from_anything.
- acquire_lease(lease_duration: int = -1)[source]
Acquire a lease (15-60s, or -1 for infinite). Returns a
BlobLeaseClient.
- copy_from(source_url: str, *, requires_sync: bool | None = None)[source]
Server-side copy from a URL. Same-account = sync; cross-account = async (poll).
- create(data, *, overwrite: bool = False, **kwargs) None[source]
Strict-create variant of
write; raisesBlobAlreadyExistsErroron conflict.
- download_stream(*, chunk_size: int | None = None)[source]
Return a streaming downloader. Iterate chunks via
.chunks()or.readinto(fp).
- properties()[source]
Return
BlobProperties(size, last_modified, etag, content_settings, metadata, …).
- read(*, offset: int | None = None, length: int | None = None) bytes[source]
Download (possibly a range) and return bytes.
- url(*, expires_in: timedelta | None = None) str[source]
Return the blob URL.
If
expires_inis set and the underlying credential is a shared-key, a SAS URL with read permission is generated. Otherwise the plain blob URL is returned (which is only useful for public containers or pre-shared SAS contexts).
- exception azuredol.BlobNotFoundError[source]
Raised when a blob does not exist.
KeyErrorsubclass soMappingconsumers work.
- exception azuredol.ContainerAlreadyExistsError[source]
Raised on strict-create attempts when the container already exists.
- class azuredol.ContainerCollection(container: str | ContainerClient, *, prefix: str = '', connection: AzureConnection | BlobServiceClient | str | dict | None = None, create_container_if_missing: bool = False, blob_type: BlobType = BlobType.BLOCKBLOB, upload_kwargs: dict | None = None, download_kwargs: dict | None = None)[source]
Iteration / membership / cardinality (__len__ deliberately omitted) over a container.
__len__is intentionally NOT implemented — seemisc/docs/design_decisions.md§2. Pagination cost is unbounded; users wanting a count callsum(1 for _ in store).
- exception azuredol.ContainerNotEmptyError[source]
Raised on
del account_store[name]when the container has blobs.The user must call
account_store.delete(name, force=True)to acknowledge the cascading delete. Seemisc/docs/design_decisions.md§12.
- class azuredol.ContainerReader(container: str | ContainerClient, *, prefix: str = '', connection: AzureConnection | BlobServiceClient | str | dict | None = None, create_container_if_missing: bool = False, blob_type: BlobType = BlobType.BLOCKBLOB, upload_kwargs: dict | None = None, download_kwargs: dict | None = None)[source]
Adds
__getitem__(returns bytes) overContainerCollection.The trailing-slash sub-store convention lives here:
store['sub/']returns a newContainerReaderwith extended prefix and zero round-trips.
- class azuredol.ContainerStore(container: str | ContainerClient, *, prefix: str = '', connection: AzureConnection | BlobServiceClient | str | dict | None = None, create_container_if_missing: bool = False, blob_type: BlobType = BlobType.BLOCKBLOB, upload_kwargs: dict | None = None, download_kwargs: dict | None = None)[source]
The primary read-write Mapping over an Azure container.
Doctest below requires Azurite (or live Azure). It is shown but not auto-run.
Example (requires Azurite):
>>> from azuredol import ContainerStore >>> s = ContainerStore( ... 'my-test-container', ... connection='UseDevelopmentStorage=true', ... create_container_if_missing=True, ... ) >>> s['k1'] = b'v1' >>> s['k1'] b'v1' >>> 'k1' in s True >>> del s['k1']
For unit tests without Azurite, prototype with
dol’s in-memory pattern:wrap_kvs(dict(), ...).
- azuredol.azure_func_service(rootfolder, extra_args='', *, verbose=True, wait_for_log=None, timeout=30, print_output=True)[source]
Context manager to start an Azure Function host using func start in the specified folder.
- Parameters:
rootfolder (str) – The directory containing the Azure Function App.
extra_args (str) – Additional command-line arguments for the func start command.
wait_for_log (str) – A substring or regular expression pattern that indicates when the service is ready. If provided, the context manager waits until a matching log line is detected.
timeout (int) – Maximum time in seconds to wait for the ready log message.
print_output (bool) – If True, prints the process output to stdout.
- Yields:
subprocess.Popen – The process object representing the running Azure Functions host.
- Usage Example:
- with azure_func_service(‘/path/to/azure_func’, extra_args=”–verbose”, wait_for_log=r’Host started’) as proc:
# Place code here to test the HTTP service. …
- azuredol.azure_store(container: str, *, prefix: str = '', connection: AzureConnection | str | dict | None = None, credential: Any = None, connection_string: str | None = None, account_url: str | None = None, account_key: str | None = None, create_container_if_missing: bool = False, blob_type: BlobType = BlobType.BLOCKBLOB, value_codec: Callable | None = None)[source]
Build a ready-to-use
ContainerStore(or codec-wrapped variant) in one call.This is the “simple things simple” entry point. For complex configurations construct
AzureConnectionandContainerStoredirectly.- Parameters:
container – Container name.
prefix – Blob-name prefix to scope all keys.
connection – An
AzureConnection(or anythingAzureConnection.from_anythingaccepts) to reuse a service client. Mutually exclusive with the explicitcredential/connection_string/account_*kwargs.credential – Forwarded to
AzureConnectionwhenconnectionis None.connection_string – Forwarded to
AzureConnectionwhenconnectionis None.account_url – Forwarded to
AzureConnectionwhenconnectionis None.account_key – Forwarded to
AzureConnectionwhenconnectionis None.create_container_if_missing – Create the container on first use if absent.
blob_type – Default blob type for writes.
value_codec – A decorator that, given a class, returns a wrapped class. Typically a partially-applied
dol.wrap_kvs(...). When None (default), bytes pass through.
- Returns:
A
ContainerStoreinstance, possibly codec-wrapped.
- azuredol.resolve_credential(*, credential: str | dict | Any | None = None, connection_string: str | None = None, account_url: str | None = None, account_key: str | None = None) dict[source]
Resolve a credential into a normalized form that can build a
BlobServiceClient.Cascade (first hit wins):
Explicit
credential=Explicit
connection_string=Explicit
account_url=+account_key=(or justaccount_url=+ AAD)Env var
AZURE_STORAGE_CONNECTION_STRINGEnv vars
AZURE_STORAGE_ACCOUNT_URL+AZURE_STORAGE_ACCOUNT_KEYEnv var
AZURE_STORAGE_ACCOUNT_URLalone +DefaultAzureCredential
- Returns:
{"conn_str": "..."}# for from_connection_string{"account_url": "...", "credential": <obj>}# for __init__- Return type:
A dict with one of these shapes
- Raises:
ValueError – if no source resolves.
- azuredol.translate_azure_errors(*, key_arg: int | str = 0, not_found_cls: type[KeyError] = <class 'azuredol.errors.BlobNotFoundError'>, exists_cls: type[KeyError] = <class 'azuredol.errors.BlobAlreadyExistsError'>) Callable[source]
Decorator: translate Azure SDK exceptions into
KeyErrorsubclasses.Auth errors (
ClientAuthenticationError) and all other Azure errors propagate untouched — they are never swallowed as “key absent”. Seemisc/docs/design_decisions.md§4.- Parameters:
key_arg – Position (int) or name (str) of the key argument in the wrapped method’s signature. Used to populate
KeyError(key). The receiverselfis at index 0, so the user-facing key is typically at index 1 (the default).not_found_cls – Exception class to raise on
ResourceNotFoundError.exists_cls – Exception class to raise on
ResourceExistsError.