Skip to content

multicloud.blob

Cloud-agnostic object storage. The user-facing entry points are BucketClient (sync) and AsyncBucketClient (async).

Sync API

Cloud-agnostic blob client package.

Public entry point — :class:BucketClient::

from multicloud.blob.blob_client import BucketClient

with BucketClient(
    provider="aws", bucket="my-bucket", region="us-west-2"
) as client:
    client.upload("hello.txt", b"hi")
    resp = client.download("hello.txt")
    client.delete("hello.txt")

Switch clouds by changing the provider kwarg only::

BucketClient(provider="gcp", bucket="my-bucket", region="us-central1")

Provider classes (AwsBlobStore, GcpBlobStore, ...) live in sibling distributions (multicloud-blob-aws, -gcp, -ali) and are discovered at runtime via setuptools entry points. They are hidden behind the registry; users never reference them directly.

BucketClient

BucketClient(
    *,
    provider: str,
    bucket: str,
    region: Optional[str] = None,
    endpoint: Optional[str] = None,
    credentials_overrider: Optional[
        CredentialsOverrider
    ] = None,
    proxy_config: Optional[ProxyConfig] = None
)

Cloud-agnostic blob storage client.

The user-facing API surface. Construction takes a provider id and a unified set of cloud-agnostic options; the underlying provider class is selected from the registry. Operations (upload, download, delete) take cloud-agnostic value objects and never reference a provider.

Parameters:

Name Type Description Default
provider str

Provider id — "aws", "gcp", or "ali".

required
bucket str

Bucket name.

required
region Optional[str]

Region (interpreted per provider). Optional; falls back to provider defaults (env vars, IAM role, ADC).

None
endpoint Optional[str]

Endpoint override URL. Optional.

None
credentials_overrider Optional[CredentialsOverrider]

Override default credential resolution. Optional.

None

upload

upload(
    key: str,
    payload: Union[bytes, BinaryIO],
    *,
    content_type: Optional[str] = None,
    content_length: Optional[int] = None,
    metadata: Optional[Mapping[str, str]] = None,
    tags: Optional[Mapping[str, str]] = None,
    object_lock: Optional[ObjectLockConfiguration] = None,
    create_if_absent: bool = False,
    if_match: Optional[str] = None,
    if_version_match: Optional[str] = None,
    kms_key_id: Optional[str] = None,
    use_kms_managed_key: bool = False
) -> UploadResponse

Upload payload to the object identified by key.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
payload Union[bytes, BinaryIO]

Content to upload - raw bytes or a binary file-like object.

required
content_type Optional[str]

MIME type (e.g., "text/plain", "application/json").

None
content_length Optional[int]

Size in bytes (optional, calculated automatically if omitted).

None
metadata Optional[Mapping[str, str]]

User-defined metadata dict (keys and values are strings).

None
tags Optional[Mapping[str, str]]

Object tags dict (keys and values are strings). Encoding is provider-specific — providers that lack native tagging encode tags in object metadata. Provider-specific limits on tag count, key length, and value length apply.

None
object_lock Optional[ObjectLockConfiguration]

Object lock configuration (retention mode + expiry and/or legal hold) to apply to the object at upload time. On some providers a legal hold is applied by a follow-up write after the object is created; if that write fails the error is raised and the object is left WITHOUT the hold.

None
create_if_absent bool

Only create when absent; else ResourceExistsException. A concurrent write that races the condition raises ResourceConflictException (the write may not have happened; retry). Mutually exclusive with if_match and if_version_match.

False
if_match Optional[str]

Only overwrite when the current ETag matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support conditional overwrite on upload; unsupported providers raise UnsupportedOperationException.

None
if_version_match Optional[str]

Only overwrite when the current version id matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support version-based conditional overwrite; unsupported providers raise UnsupportedOperationException.

None
kms_key_id Optional[str]

Provider-managed key id for server-side encryption.

None
use_kms_managed_key bool

Request a provider-managed encryption key when no kms_key_id is given. A no-op on providers that always encrypt at rest.

False

Returns:

Type Description
UploadResponse

UploadResponse containing the key, ETag, and version ID.

upload_from_path

upload_from_path(
    key: str,
    path: Union[str, Path, "os.PathLike[str]"],
    *,
    content_type: Optional[str] = None,
    content_length: Optional[int] = None,
    metadata: Optional[Mapping[str, str]] = None,
    object_lock: Optional[ObjectLockConfiguration] = None,
    create_if_absent: bool = False,
    if_match: Optional[str] = None,
    if_version_match: Optional[str] = None,
    kms_key_id: Optional[str] = None,
    use_kms_managed_key: bool = False
) -> UploadResponse

Upload a local file to the object identified by key.

Convenience method that reads a file from the local filesystem and uploads its content. Auto-detects content_type from the file extension (via :mod:mimetypes) and content_length from the file size when not explicitly provided.

Note

tags is not supported on this method yet.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
path Union[str, Path, 'os.PathLike[str]']

Local file path to upload. Accepts a string, :class:~pathlib.Path, or any :class:os.PathLike.

required
content_type Optional[str]

MIME type (e.g., "text/plain"). Auto-detected from file extension if omitted.

None
content_length Optional[int]

Size in bytes. Calculated from file size if omitted.

None
metadata Optional[Mapping[str, str]]

User-defined metadata dict (keys and values are strings).

None
object_lock Optional[ObjectLockConfiguration]

Object lock configuration (retention mode + expiry and/or legal hold) to apply to the object at upload time.

None
create_if_absent bool

Only create when absent; else ResourceExistsException. A concurrent write that races the condition raises ResourceConflictException (the write may not have happened; retry). Mutually exclusive with if_match and if_version_match.

False
if_match Optional[str]

Only overwrite when the current ETag matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support conditional overwrite on upload; unsupported providers raise UnsupportedOperationException.

None
if_version_match Optional[str]

Only overwrite when the current version id matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support version-based conditional overwrite; unsupported providers raise UnsupportedOperationException.

None
kms_key_id Optional[str]

Provider-managed key id for server-side encryption.

None
use_kms_managed_key bool

Request a provider-managed encryption key when no kms_key_id is given. A no-op on providers that always encrypt at rest.

False

Returns:

Type Description
UploadResponse

UploadResponse containing the key, ETag, and version ID.

Raises:

Type Description
InvalidArgumentException

If key is empty, file does not exist, or path is not a regular file.

download

download(
    key: str,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None,
    if_match: Optional[str] = None
) -> DownloadResponse

Download the object identified by key.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific version to download (if versioning is enabled).

None
start Optional[int]

Start byte position for range download (inclusive).

None
end Optional[int]

End byte position for range download (inclusive).

None
if_match Optional[str]

Only download when the current ETag matches; else FailedPreconditionException.

None

Returns:

Type Description
DownloadResponse

DownloadResponse containing the key, content bytes, and metadata.

download_to_path

download_to_path(
    key: str,
    destination: Path,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None,
    create_parent_dirs: bool = False
) -> DownloadResponse

Download the object directly to a file path.

Writes content directly to the local filesystem without loading the entire blob into memory. Suitable for large objects.

Conditional reads (if_match) are supported on download() only; use it when you need an ETag precondition.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
destination Path

Local file path to write the content to.

required
version_id Optional[str]

Specific version to download (if versioning is enabled).

None
start Optional[int]

Start byte position for range download (inclusive).

None
end Optional[int]

End byte position for range download (inclusive).

None
create_parent_dirs bool

If True, create parent directories of destination if they do not exist.

False

Returns:

Type Description
DownloadResponse

DownloadResponse with metadata (content field is empty bytes).

download_to_file

download_to_file(
    key: str,
    file_obj: BinaryIO,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None
) -> DownloadResponse

Download the object directly to a file-like object.

Writes content directly to the provided writable binary file object without loading the entire blob into memory.

Conditional reads (if_match) are supported on download() only; use it when you need an ETag precondition.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
file_obj BinaryIO

A writable binary file-like object (must support write(bytes)).

required
version_id Optional[str]

Specific version to download (if versioning is enabled).

None
start Optional[int]

Start byte position for range download (inclusive).

None
end Optional[int]

End byte position for range download (inclusive).

None

Returns:

Type Description
DownloadResponse

DownloadResponse with metadata (content field is empty bytes).

download_stream

download_stream(
    key: str,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None
) -> StreamingDownloadResponse

Download the object as a streaming response for lazy consumption.

Returns a streaming response that yields content on demand without loading the entire blob into memory. The caller must close the response (preferably via a context manager) to release the underlying HTTP connection.

Conditional reads (if_match) are supported on download() only; use it when you need an ETag precondition.

Example::

with client.download_stream("large-file.bin") as stream:
    for chunk in stream:
        process(chunk)

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific version to download (if versioning is enabled).

None
start Optional[int]

Start byte position for range download (inclusive).

None
end Optional[int]

End byte position for range download (inclusive).

None

Returns:

Type Description
StreamingDownloadResponse

StreamingDownloadResponse with an iterator and read() interface.

delete

delete(
    key: str, *, version_id: Optional[str] = None
) -> None

Delete the object identified by key.

Idempotent — returns silently if the object does not exist.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific version to delete. If None, deletes the latest version (or creates a delete marker on versioned buckets).

None

delete_objects

delete_objects(
    objects: List[BlobIdentifier],
) -> DeleteObjectsResponse

Delete multiple objects in a single batch operation.

The caller is responsible for chunking to stay within provider limits (e.g. 1000 for S3).

Parameters:

Name Type Description Default
objects List[BlobIdentifier]

Collection of blob identifiers to delete. Each identifier specifies a key and an optional version ID.

required

Returns:

Type Description
DeleteObjectsResponse

DeleteObjectsResponse with any per-object errors. An empty

DeleteObjectsResponse

errors list means all objects were deleted successfully.

Raises:

Type Description
InvalidArgumentException

If objects is empty or contains entries with empty keys.

copy

copy(
    src_key: str,
    *,
    dest_bucket: str,
    dest_key: str,
    src_version_id: Optional[str] = None
) -> CopyResponse

Copy an object from this bucket to another bucket.

Performs a server-side copy — no data is transferred through the client.

Parameters:

Name Type Description Default
src_key str

Key of the source object in this bucket.

required
dest_bucket str

Name of the destination bucket.

required
dest_key str

Key for the copied object in the destination bucket.

required
src_version_id Optional[str]

Specific version of the source to copy. If None, copies the latest version.

None

Returns:

Type Description
CopyResponse

CopyResponse with the key, version ID, ETag, and last-modified

CopyResponse

timestamp of the new copy.

Raises:

Type Description
InvalidArgumentException

If any required parameter is empty.

copy_from

copy_from(
    src_bucket: str,
    src_key: str,
    *,
    dest_key: str,
    src_version_id: Optional[str] = None
) -> CopyResponse

Copy an object from a source bucket into this bucket.

Performs a server-side copy — no data is transferred through the client.

Parameters:

Name Type Description Default
src_bucket str

Name of the source bucket.

required
src_key str

Key of the source object in the source bucket.

required
dest_key str

Key for the copied object in this bucket.

required
src_version_id Optional[str]

Specific version of the source to copy. If None, copies the latest version.

None

Returns:

Type Description
CopyResponse

CopyResponse with the key, version ID, ETag, and last-modified

CopyResponse

timestamp of the new copy.

Raises:

Type Description
InvalidArgumentException

If any required parameter is empty.

list_page

list_page(
    *,
    prefix: Optional[str] = None,
    delimiter: Optional[str] = None,
    max_results: int = 1000,
    pagination_token: Optional[str] = None
) -> ListBlobsPageResponse

Retrieve a single page of blobs matching the given criteria.

Parameters:

Name Type Description Default
prefix Optional[str]

Filter results to keys starting with this prefix.

None
delimiter Optional[str]

Character to group keys into common prefixes (usually "/").

None
max_results int

Maximum number of blobs to return (1-1000, default 1000).

1000
pagination_token Optional[str]

Continuation token from a previous response for pagination.

None

Returns:

Type Description
ListBlobsPageResponse

ListBlobsPageResponse with blobs, common_prefixes,

ListBlobsPageResponse

is_truncated, and next_pagination_token.

does_object_exist

does_object_exist(
    key: str, *, version_id: Optional[str] = None
) -> bool

Check whether a blob exists in the bucket.

Parameters:

Name Type Description Default
key str

Object key to check.

required
version_id Optional[str]

Optional version ID for versioned buckets.

None

Returns:

Type Description
bool

True if the object exists, False if not found.

bool

Other errors (auth, server) propagate as translated

bool

exceptions.

get_metadata

get_metadata(
    key: str, *, version_id: Optional[str] = None
) -> BlobMetadata

Retrieve object metadata (HEAD-style) without downloading the body.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Optional version ID for versioned buckets.

None

Returns:

Type Description
BlobMetadata

BlobMetadata with key, content_length, content_type, e_tag,

BlobMetadata

version_id, custom metadata, last_modified, and created_time.

Raises:

Type Description
InvalidArgumentException

If key is empty.

ResourceNotFoundException

If the object does not exist.

does_bucket_exist

does_bucket_exist() -> bool

Check whether the configured bucket exists.

Returns:

Type Description
bool

True if the bucket exists, False if not found.

bool

Other errors (auth, server) propagate as translated

bool

exceptions.

get_tags

get_tags(key: str) -> Mapping[str, str]

Retrieve all tags associated with the object.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required

Returns:

Type Description
Mapping[str, str]

A mapping of tag keys to tag values. Returns an empty dict

Mapping[str, str]

if the object exists but has no tags.

Raises:

Type Description
InvalidArgumentException

If key is empty.

set_tags

set_tags(key: str, tags: Mapping[str, str]) -> None

Set tags on the object, replacing all existing tags.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
tags Mapping[str, str]

Mapping of tag keys to tag values. Replaces all existing tags on the object.

required

Raises:

Type Description
InvalidArgumentException

If key is empty or tags is empty.

update_object_retention

update_object_retention(
    key: str,
    retention: ObjectRetentionConfig,
    *,
    version_id: Optional[str] = None
) -> None

Update the retention configuration of a single object.

The object must already have retention configured; this updates it and does not establish retention for the first time.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
retention ObjectRetentionConfig

Retention settings to apply (retain-until date, an optional mode where None preserves the current mode, plus an optional flag to bypass an existing governance-mode retention).

required
version_id Optional[str]

Optional version identifier to target a specific version of the object.

None

Raises:

Type Description
InvalidArgumentException

If key is empty or the retention config is missing a retain-until date.

generate_presigned_url

generate_presigned_url(
    key: str,
    operation: PresignedOperation,
    *,
    duration_seconds: int = 3600,
    content_type: Optional[str] = None,
    metadata: Optional[Mapping[str, str]] = None,
    tags: Optional[Mapping[str, str]] = None,
    kms_key_id: Optional[str] = None,
    content_disposition: Optional[str] = None
) -> PresignedUrlResponse

Generate a presigned URL for uploading or downloading an object.

The returned URL can be used by any HTTP client (no SDK or credentials required) to perform the specified operation within the expiration window.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
operation PresignedOperation

Whether to generate an UPLOAD (PUT) or DOWNLOAD (GET) URL.

required
duration_seconds int

URL validity duration in seconds (default 3600 = 1 hour).

3600
content_type Optional[str]

MIME type (upload only). Callers must send this header.

None
metadata Optional[Mapping[str, str]]

User-defined metadata (upload only). Callers must send the corresponding provider-specific headers.

None
tags Optional[Mapping[str, str]]

Object tags (upload only). Encoding is provider-specific.

None
kms_key_id Optional[str]

KMS key for server-side encryption (upload only, provider- dependent — silently ignored on providers that do not support it).

None
content_disposition Optional[str]

Content-Disposition header value. For uploads, the header is baked into the URL; for downloads, it overrides the response header.

None

Returns:

Type Description
PresignedUrlResponse

PresignedUrlResponse containing the URL, HTTP method, and any

PresignedUrlResponse

headers the caller must include when using the URL.

get_object_lock

get_object_lock(
    key: str, *, version_id: Optional[str] = None
) -> Optional[ObjectLockInfo]

Retrieve the object lock state (retention + legal hold) for an object.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version. Optional; None targets the latest version.

None

Returns:

Type Description
Optional[ObjectLockInfo]

ObjectLockInfo with retention mode/date, legal hold, and

Optional[ObjectLockInfo]

event-based hold, or None when the object has no retention and

Optional[ObjectLockInfo]

no legal hold.

Raises:

Type Description
InvalidArgumentException

If key is empty.

update_legal_hold(
    key: str,
    enabled: bool,
    *,
    version_id: Optional[str] = None
) -> None

Set or remove a legal hold on an object.

A legal hold prevents the object from being deleted or overwritten until the hold is explicitly removed. On providers with a dedicated legal-hold flag this is independent of any retention period; on providers where the legal-hold and retention mechanisms share the same underlying flag, the two concerns may be entangled.

Provider notes
  • Placing a hold may require object lock / versioning to be enabled on the bucket for some providers; the call errors otherwise.
  • Some providers guard the write with an optimistic-concurrency check, so a concurrent modification can surface as a translated error on those providers only.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
enabled bool

True to place a legal hold, False to remove it.

required
version_id Optional[str]

Specific object version. Optional; None targets the latest version.

None

list_blob_versions

list_blob_versions(key: str) -> Iterator[BlobInfo]

Iterate all versions of a blob in the bucket.

Parameters:

Name Type Description Default
key str

Object key whose versions to list.

required

Returns:

Type Description
Iterator[BlobInfo]

Iterator yielding BlobInfo for each version.

Raises:

Type Description
UnsupportedOperationException

If the provider does not support version listing.

initiate_multipart_upload

initiate_multipart_upload(
    key: str,
    *,
    metadata: Optional[Mapping[str, str]] = None,
    content_type: Optional[str] = None,
    tags: Optional[Mapping[str, str]] = None,
    object_lock: Optional[ObjectLockConfiguration] = None
) -> MultipartUpload

Initiate a multipart upload session.

Parameters:

Name Type Description Default
key str

Object key for the final assembled blob.

required
metadata Optional[Mapping[str, str]]

Optional user-defined metadata.

None
content_type Optional[str]

Optional MIME type.

None
tags Optional[Mapping[str, str]]

Optional object tags applied to the final assembled blob.

None
object_lock Optional[ObjectLockConfiguration]

Optional object lock (retention mode + expiry and/or legal hold) applied to the final assembled blob.

None

Returns:

Type Description
MultipartUpload

MultipartUpload handle for subsequent part operations.

upload_part

upload_part(
    mpu: MultipartUpload, part: MultipartPart
) -> UploadPartResponse

Upload a single part within a multipart upload session.

Parameters:

Name Type Description Default
mpu MultipartUpload

The multipart upload handle from initiate.

required
part MultipartPart

The part data (part_number + content).

required

Returns:

Type Description
UploadPartResponse

UploadPartResponse with part_number, e_tag, and size.

complete_multipart_upload

complete_multipart_upload(
    mpu: MultipartUpload, parts: List[UploadPartResponse]
) -> MultipartUploadResponse

Complete a multipart upload, assembling all parts into the final blob.

Parameters:

Name Type Description Default
mpu MultipartUpload

The multipart upload handle from initiate.

required
parts List[UploadPartResponse]

List of all uploaded part responses.

required

Returns:

Type Description
MultipartUploadResponse

MultipartUploadResponse with the final e_tag.

list_parts

list_parts(
    mpu: MultipartUpload,
) -> List[UploadPartResponse]

List all parts uploaded so far for a multipart upload.

Parameters:

Name Type Description Default
mpu MultipartUpload

The multipart upload handle from initiate.

required

Returns:

Type Description
List[UploadPartResponse]

List of UploadPartResponse for each uploaded part.

abort_multipart_upload

abort_multipart_upload(mpu: MultipartUpload) -> None

Abort a multipart upload, discarding all uploaded parts.

Parameters:

Name Type Description Default
mpu MultipartUpload

The multipart upload handle from initiate.

required

close

close() -> None

Release underlying resources.

BlobInfo dataclass

BlobInfo(
    key: str,
    size: Optional[int] = None,
    e_tag: Optional[str] = None,
    last_modified: Optional[datetime] = None,
    storage_class: Optional[str] = None,
    version_id: Optional[str] = None,
    is_latest: Optional[bool] = None,
)

A blob's identity and lightweight metadata from listing operations.

BlobMetadata dataclass

BlobMetadata(
    key: str,
    content_length: Optional[int] = None,
    content_type: Optional[str] = None,
    e_tag: Optional[str] = None,
    version_id: Optional[str] = None,
    metadata: Mapping[str, str] = dict(),
    last_modified: Optional[datetime] = None,
    created_time: Optional[datetime] = None,
    replication_status: Optional[ReplicationStatus] = None,
)

Metadata returned alongside a download or HEAD-style lookup.

CopyResponse dataclass

CopyResponse(
    key: str,
    version_id: Optional[str] = None,
    e_tag: Optional[str] = None,
    last_modified: Optional[datetime] = None,
)

Result of a copy operation.

Attributes:

Name Type Description
key str

The key of the copied blob in the destination bucket.

version_id Optional[str]

Version ID assigned to the new copy (if versioning is enabled on the destination bucket).

e_tag Optional[str]

Entity tag of the new copy.

last_modified Optional[datetime]

Timestamp when the copy was created.

DeleteObjectsResponse dataclass

DeleteObjectsResponse(errors: List[DeleteError] = list())

Result of a batch delete operation.

Attributes:

Name Type Description
errors List[DeleteError]

List of objects that failed to delete. Empty list indicates all objects were successfully deleted.

DownloadResponse dataclass

DownloadResponse(
    key: str, content: bytes, metadata: BlobMetadata
)

Wrapper object for download result data.

ListBlobsPageResponse dataclass

ListBlobsPageResponse(
    blobs: List[BlobInfo] = list(),
    common_prefixes: List[str] = list(),
    is_truncated: bool = False,
    next_pagination_token: Optional[str] = None,
)

Single page of blob listing results with pagination support.

MultipartPart dataclass

MultipartPart(
    part_number: int,
    content: Union[bytes, BinaryIO],
    content_length: Optional[int] = None,
)

A single part to upload within a multipart upload session.

Accepts either raw bytes or a binary file-like object (BinaryIO). When using BinaryIO, content_length is required.

MultipartUpload dataclass

MultipartUpload(
    bucket: str,
    key: str,
    upload_id: str,
    metadata: Mapping[str, str] = dict(),
    content_type: Optional[str] = None,
    tags: Mapping[str, str] = dict(),
    object_lock: Optional[ObjectLockConfiguration] = None,
    correlation_id: Optional[str] = None,
)

Identifies an in-progress multipart upload session.

Returned by initiate_multipart_upload and passed to all subsequent multipart operations (upload_part, complete, list, abort).

MultipartUploadResponse dataclass

MultipartUploadResponse(
    e_tag: Optional[str] = None,
    key: Optional[str] = None,
    version_id: Optional[str] = None,
    correlation_id: Optional[str] = None,
)

Response from completing a multipart upload.

Only e_tag is set by the synchronous client; the remaining fields are populated by the async client.

ObjectLockConfiguration dataclass

ObjectLockConfiguration(
    mode: Optional[RetentionMode] = None,
    retain_until_date: Optional[datetime] = None,
    legal_hold: bool = False,
    use_event_based_hold: bool = False,
)

Object lock settings applied to an object at upload time.

Bundles first-time retention (mode + retain-until instant) and legal hold into a single input value passed to upload / upload_from_path. All fields are optional so callers can set retention only, a legal hold only, or both.

Attributes:

Name Type Description
mode Optional[RetentionMode]

Retention mode to apply. Requires retain_until_date.

retain_until_date Optional[datetime]

Timezone-aware instant until which the object must be retained. Requires mode.

legal_hold bool

When True, place a legal hold on the object.

use_event_based_hold bool

When True, a requested legal hold is applied as an event-based hold instead of the default hold mechanism. Ignored by providers that do not distinguish the two.

ObjectLockInfo dataclass

ObjectLockInfo(
    mode: Optional[RetentionMode] = None,
    retain_until_date: Optional[datetime] = None,
    legal_hold: bool = False,
    event_based_hold: Optional[bool] = None,
)

Unified read result describing an object's lock state.

Combines retention and legal-hold state into a single value object so callers retrieve everything in one read.

Attributes:

Name Type Description
mode Optional[RetentionMode]

Retention mode in effect, or None if no retention is set.

retain_until_date Optional[datetime]

Instant until which the object is retained, or None if no retention is set.

legal_hold bool

True if a legal hold is currently in place.

event_based_hold Optional[bool]

Provider-specific event-based hold flag, or None when the provider does not report one. None ("not reported") is distinct from False ("reported, and off"), so test it with is True / is False rather than plain truthiness.

ObjectRetentionConfig dataclass

ObjectRetentionConfig(
    retain_until_date: datetime,
    mode: Optional[RetentionMode] = None,
    bypass_governance: bool = False,
)

Retention settings to apply to a single object.

Input type for the retention write API. This updates the retention of an object that already has retention configured; it does not establish retention for the first time.

Attributes:

Name Type Description
retain_until_date datetime

Instant until which the object must be retained. Must be timezone-aware — it denotes an absolute instant and is compared against the timezone-aware retain-until the provider reads back. A naive (timezone-less) value is rejected with InvalidArgumentException.

mode Optional[RetentionMode]

Retention mode to apply, or None to preserve the object's current mode while changing only the retain-until date.

bypass_governance bool

When True, allows shortening an existing GOVERNANCE-mode retention, or upgrading GOVERNANCE to COMPLIANCE. Ignored for COMPLIANCE, which is immutable.

PresignedOperation

Bases: Enum

Supported presigned URL operation types.

PresignedUrlResponse dataclass

PresignedUrlResponse(
    url: str,
    http_method: str,
    required_headers: Mapping[str, str] = (
        lambda: MappingProxyType({})
    )(),
)

Result of generating a presigned URL.

Attributes:

Name Type Description
url str

The presigned URL string.

http_method str

The HTTP method the consumer must use (e.g. "PUT", "GET").

required_headers Mapping[str, str]

Headers the consumer MUST include in the HTTP request for the presigned URL to work. Includes signed metadata, tagging, content-type, and encryption headers. Empty mapping if none required. Wrapped in MappingProxyType to prevent accidental mutation of shared state.

ReplicationStatus

Bases: Enum

Cross-region / cross-bucket replication state of an object.

Reported on metadata lookups by providers that support replication. Providers that do not track replication leave the field None.

Attributes:

Name Type Description
COMPLETE

The object has been replicated to all configured targets.

PENDING

Replication is in progress.

FAILED

Replication failed for at least one target.

REPLICA

This object is itself a replica created in a destination bucket by a replication rule.

RetentionMode

Bases: Enum

Object lock retention mode.

GOVERNANCE retention can be shortened or removed by sufficiently privileged callers; COMPLIANCE retention cannot be shortened or removed by anyone until it expires.

StreamingDownloadResponse

StreamingDownloadResponse(
    key: str,
    metadata: BlobMetadata,
    stream: Iterator[bytes],
    close_func: Optional[Callable[[], None]] = None,
)

Streaming download response for lazy consumption of large blobs.

Provides both an iterator interface (for chunk-by-chunk processing) and a file-like read() method. Must be closed after use to release the underlying HTTP connection.

Supports context manager usage::

with client.download_stream("large-file.bin") as stream:
    for chunk in stream:
        process(chunk)

Or with explicit read calls::

with client.download_stream("large-file.bin") as stream:
    while data := stream.read(8192):
        dest.write(data)

key property

key: str

Object key that was downloaded.

metadata property

metadata: BlobMetadata

Metadata for the downloaded object.

closed property

closed: bool

Whether the stream has been closed.

read

read(size: int = -1) -> bytes

Read up to size bytes from the stream.

Parameters:

Name Type Description Default
size int

Maximum number of bytes to read. If -1, read all remaining content (caution: loads everything into memory).

-1

Returns:

Type Description
bytes

Bytes read from the stream. Returns empty bytes when the

bytes

stream is exhausted.

Raises:

Type Description
ValueError

If the stream has been closed.

close

close() -> None

Release the underlying HTTP connection and resources.

UploadPartResponse dataclass

UploadPartResponse(
    part_number: int,
    e_tag: str,
    size_in_bytes: int,
    correlation_id: Optional[str] = None,
)

Response from uploading an individual part.

UploadResponse dataclass

UploadResponse(
    key: str,
    e_tag: Optional[str] = None,
    version_id: Optional[str] = None,
)

Wrapper for upload result data.

AsyncBucketClient

AsyncBucketClient(
    *,
    provider: str,
    bucket: str,
    region: Optional[str] = None,
    endpoint: Optional[str] = None,
    transfer_config: Optional[AsyncTransferConfig] = None,
    credentials_overrider: Optional[
        CredentialsOverrider
    ] = None,
    proxy_config: Optional[ProxyConfig] = None
)

Cloud-agnostic async blob storage client.

Construction takes a provider id and unified options; the underlying provider class is selected from the async registry.

Every method here is awaited except :meth:list_blob_versions, which hands back an async iterator directly so callers write async for info in client.list_blob_versions(key).

Parameters:

Name Type Description Default
provider str

Provider id -- "aws", "gcp", or "ali".

required
bucket str

Bucket name.

required
region Optional[str]

Region (interpreted per provider). Optional.

None
endpoint Optional[str]

Endpoint override URL. Optional.

None
transfer_config Optional[AsyncTransferConfig]

Transfer configuration. Uses defaults if omitted.

None
credentials_overrider Optional[CredentialsOverrider]

Override default credential resolution. Optional.

None

bucket property

bucket: str

The bucket this client operates on.

provider property

provider: str

The provider id (e.g. 'aws', 'gcp').

download async

download(
    key: str,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None,
    if_match: Optional[str] = None
) -> AsyncDownloadResponse

Download the object identified by key into memory.

Returns an :class:AsyncDownloadResponse containing the blob content as bytes in the content field.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version to download. Optional.

None
start Optional[int]

First byte of a range download (inclusive). Optional.

None
end Optional[int]

Last byte of a range download (inclusive). Optional.

None
if_match Optional[str]

Only download when the current ETag matches; else FailedPreconditionException. Optional.

None

Returns:

Type Description
AsyncDownloadResponse

AsyncDownloadResponse with key, content bytes, and metadata.

Raises:

Type Description
InvalidArgumentException

If key is empty.

download_to_path async

download_to_path(
    key: str,
    destination: Union[str, Path, PathLike],
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None,
    create_parent_dirs: bool = False
) -> AsyncDownloadResponse

Download the object to a local file path.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
destination Union[str, Path, PathLike]

Local file path to write the blob content.

required
version_id Optional[str]

Specific object version to download. Optional.

None
start Optional[int]

First byte of a range download (inclusive). Optional.

None
end Optional[int]

Last byte of a range download (inclusive). Optional.

None
create_parent_dirs bool

If True, create parent directories if they don't exist.

False

Returns:

Type Description
AsyncDownloadResponse

AsyncDownloadResponse with download metadata.

Raises:

Type Description
InvalidArgumentException

If key is empty.

download_to_file async

download_to_file(
    key: str,
    file_obj: BinaryIO,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None
) -> AsyncDownloadResponse

Download the object to a file-like object.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
file_obj BinaryIO

Binary file-like object to write the blob content.

required
version_id Optional[str]

Specific object version to download. Optional.

None
start Optional[int]

First byte of a range download (inclusive). Optional.

None
end Optional[int]

Last byte of a range download (inclusive). Optional.

None

Returns:

Type Description
AsyncDownloadResponse

AsyncDownloadResponse with download metadata.

Raises:

Type Description
InvalidArgumentException

If key is empty.

download_stream async

download_stream(
    key: str,
    *,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None
) -> AsyncStreamingDownloadResponse

Open the object for lazy reading instead of loading it into memory.

Use this instead of :meth:download when the object may be too large to hold, or when it can be processed incrementally.

The returned stream holds a connection until it is closed, so close it even if only part of the object is read. async with does that::

async with await client.download_stream("large.bin") as stream:
    async for chunk in stream:
        process(chunk)

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version. Optional.

None
start Optional[int]

First byte to read, inclusive. Optional. Omitting it while giving end reads the last end bytes.

None
end Optional[int]

Last byte to read, inclusive. Optional.

None

Returns:

Type Description
AsyncStreamingDownloadResponse

An AsyncStreamingDownloadResponse supporting async iteration, an

AsyncStreamingDownloadResponse

awaitable read, and async context management.

Raises:

Type Description
InvalidArgumentException

If key is empty or the range is invalid.

SubstrateSdkException

On provider error.

upload async

upload(
    key: str,
    payload: AsyncUploadPayload,
    *,
    content_type: Optional[str] = None,
    content_length: Optional[int] = None,
    metadata: Optional[Mapping[str, str]] = None,
    create_if_absent: bool = False,
    if_match: Optional[str] = None,
    if_version_match: Optional[str] = None,
    kms_key_id: Optional[str] = None,
    use_kms_managed_key: bool = False
) -> AsyncUploadResponse

Upload data to the object identified by key.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
payload AsyncUploadPayload

Content to upload -- bytes, Path, or BinaryIO.

required
content_type Optional[str]

MIME type (auto-detected from Path extension if not specified). Falls back to "application/octet-stream".

None
content_length Optional[int]

Explicit size in bytes. Calculated if omitted.

None
metadata Optional[Mapping[str, str]]

User-defined metadata dict attached to the object.

None
create_if_absent bool

Only create when absent; else ResourceExistsException. A concurrent write that races the condition raises ResourceConflictException (the write may not have happened; retry). Mutually exclusive with if_match and if_version_match.

False
if_match Optional[str]

Only overwrite when the current ETag matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support conditional overwrite on upload; unsupported providers raise UnsupportedOperationException.

None
if_version_match Optional[str]

Only overwrite when the current version id matches; else FailedPreconditionException; a racing write raises ResourceConflictException (the write may not have happened; retry). Not all providers support version-based conditional overwrite; unsupported providers raise UnsupportedOperationException.

None
kms_key_id Optional[str]

Provider key id for server-side encryption.

None
use_kms_managed_key bool

Request a provider-managed encryption key when no kms_key_id is given. A no-op on providers that always encrypt at rest.

False

Returns:

Type Description
AsyncUploadResponse

AsyncUploadResponse with key, version_id, e_tag.

Raises:

Type Description
InvalidArgumentException

If key is empty or payload unsupported.

upload_from_path async

upload_from_path(
    key: str,
    path: Union[str, Path, PathLike],
    *,
    content_type: Optional[str] = None,
    content_length: Optional[int] = None,
    metadata: Optional[Mapping[str, str]] = None,
    create_if_absent: bool = False,
    if_match: Optional[str] = None,
    if_version_match: Optional[str] = None,
    kms_key_id: Optional[str] = None,
    use_kms_managed_key: bool = False
) -> AsyncUploadResponse

Upload a local file to the object identified by key.

Convenience over :meth:upload for a file on disk: the path may be a string as well as a Path, a missing or non-regular file is rejected up front rather than surfacing as a transport error, and the content type is detected from the extension when not given. Reading is done off the event loop.

Note

The file is read into memory before being sent, so use the multipart API for uploads too large to buffer. tags and object_lock are not accepted here, matching :meth:upload.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
path Union[str, Path, PathLike]

Local file to upload.

required
content_type Optional[str]

MIME type. Detected from the extension if omitted.

None
content_length Optional[int]

Size in bytes. Taken from the file if omitted.

None
metadata Optional[Mapping[str, str]]

User-defined metadata to attach.

None
create_if_absent bool

Only create; fail if the key already exists.

False
if_match Optional[str]

Only write if the current entity tag matches.

None
if_version_match Optional[str]

Only write if the current version matches.

None
kms_key_id Optional[str]

Customer-managed encryption key.

None
use_kms_managed_key bool

Encrypt with a provider-managed key.

False

Returns:

Type Description
AsyncUploadResponse

AsyncUploadResponse with key, version_id, e_tag.

Raises:

Type Description
InvalidArgumentException

If key is empty, the file does not exist, or it is not a regular file.

delete async

delete(
    key: str, *, version_id: Optional[str] = None
) -> None

Delete a single object. Idempotent — does not raise if the object does not exist.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version to delete. Optional. If None, targets the latest version.

None

Raises:

Type Description
InvalidArgumentException

If key is empty.

delete_objects async

delete_objects(
    identifiers: list[BlobIdentifier],
) -> BulkDeleteResponse

Delete multiple objects. Does NOT raise on partial failure.

Non-existent objects are reported as successfully deleted (idempotent semantics). Inspect BulkDeleteResponse.errors for any objects that genuinely failed.

Parameters:

Name Type Description Default
identifiers list[BlobIdentifier]

List of BlobIdentifiers to delete.

required

Returns:

Type Description
BulkDeleteResponse

BulkDeleteResponse with per-object outcomes.

Raises:

Type Description
InvalidArgumentException

If identifiers is empty or invalid.

get_tags async

get_tags(key: str) -> Mapping[str, str]

Retrieve the tags attached to the object identified by key.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required

Returns:

Type Description
Mapping[str, str]

A mapping of tag keys to values. Empty if the object has no tags.

Raises:

Type Description
InvalidArgumentException

If key is empty.

set_tags async

set_tags(key: str, tags: Mapping[str, str]) -> None

Replace all tags on the object identified by key.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
tags Mapping[str, str]

Mapping of tag keys to values. Replaces any existing tags.

required

Raises:

Type Description
InvalidArgumentException

If key is empty or tags is empty.

get_metadata async

get_metadata(
    key: str, *, version_id: Optional[str] = None
) -> BlobMetadata

Retrieve object metadata (HEAD-style) without downloading the body.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version. Optional.

None

Returns:

Type Description
BlobMetadata

BlobMetadata with key, size (content_length), content_type,

BlobMetadata

e_tag, version_id, custom metadata, last_modified, and created_time.

Raises:

Type Description
InvalidArgumentException

If key is empty.

BlobNotFoundError

If the object does not exist.

SubstrateSdkException

On other provider errors.

get_object_lock async

get_object_lock(
    key: str, *, version_id: Optional[str] = None
) -> Optional[ObjectLockInfo]

Retrieve the retention and legal-hold state of an object.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version. Optional; None targets the latest version.

None

Returns:

Type Description
Optional[ObjectLockInfo]

ObjectLockInfo describing the lock, or None when the object has

Optional[ObjectLockInfo]

neither retention nor a legal hold.

Optional[ObjectLockInfo]

event_based_hold is a tri-state: None means the provider does

Optional[ObjectLockInfo]

not report one, so test it with is True / is False rather

Optional[ObjectLockInfo]

than plain truthiness.

Raises:

Type Description
InvalidArgumentException

If key is empty.

SubstrateSdkException

On provider error, including a bucket that does not have object lock enabled.

update_object_retention async

update_object_retention(
    key: str,
    retention: ObjectRetentionConfig,
    *,
    version_id: Optional[str] = None
) -> None

Update the retention configuration of a single object.

The object must ALREADY have retention configured. This changes an existing retention; it does not establish one, and a call against an object without retention is refused.

Shortening or relaxing an existing retention is restricted: an immutable-mode retention can only be extended, and a mutable one can be shortened only with bypass_governance.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
retention ObjectRetentionConfig

The retention change to apply. retain_until_date must be timezone-aware.

required
version_id Optional[str]

Specific object version. Optional; None targets the latest version.

None

Raises:

Type Description
InvalidArgumentException

If key is empty, the config is missing, or its retain-until instant is missing or timezone-naive.

FailedPreconditionException

If the object has no retention yet, or the change is not permitted from its current state.

SubstrateSdkException

On provider error.

update_legal_hold(
    key: str,
    enabled: bool,
    *,
    version_id: Optional[str] = None
) -> None

Set or remove a legal hold on an object.

A legal hold prevents the object from being deleted or overwritten until the hold is explicitly removed. On providers with a dedicated legal-hold flag this is independent of any retention period; on providers where the legal-hold and retention mechanisms share the same underlying flag, the two concerns may be entangled.

Provider notes
  • Placing a hold may require object lock / versioning to be enabled on the bucket for some providers; the call errors otherwise.
  • Some providers guard the write with an optimistic-concurrency check, so a concurrent modification can surface as a translated error on those providers only.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
enabled bool

True to place a legal hold, False to remove it.

required
version_id Optional[str]

Specific object version. Optional; None targets the latest version.

None

Raises:

Type Description
InvalidArgumentException

If key is empty.

SubstrateSdkException

On provider error.

copy async

copy(
    src_key: str,
    *,
    dest_bucket: str,
    dest_key: str,
    src_version_id: Optional[str] = None,
    metadata: Optional[Mapping[str, str]] = None
) -> CopyResponse

Copy a blob from this bucket to another bucket.

Parameters:

Name Type Description Default
src_key str

Source object key in this bucket.

required
dest_bucket str

Destination bucket name.

required
dest_key str

Key for the copied object.

required
src_version_id Optional[str]

Source version to copy; latest if None.

None
metadata Optional[Mapping[str, str]]

Replacement metadata; source metadata kept if None.

None

Returns:

Type Description
CopyResponse

CopyResponse for the new copy.

Raises:

Type Description
SubstrateSdkException

A subclass instance on failure.

copy_from async

copy_from(
    src_bucket: str,
    src_key: str,
    *,
    dest_key: str,
    src_version_id: Optional[str] = None,
    metadata: Optional[Mapping[str, str]] = None
) -> CopyResponse

Copy a blob from another bucket into this bucket.

Parameters:

Name Type Description Default
src_bucket str

Source bucket name.

required
src_key str

Source object key in the source bucket.

required
dest_key str

Key for the copied object in this bucket.

required
src_version_id Optional[str]

Source version to copy; latest if None.

None
metadata Optional[Mapping[str, str]]

Replacement metadata; source metadata kept if None.

None

Returns:

Type Description
CopyResponse

CopyResponse for the new copy.

Raises:

Type Description
SubstrateSdkException

A subclass instance on failure.

generate_presigned_url async

generate_presigned_url(
    key: str,
    operation: str = "GET",
    *,
    expiration_seconds: int = 3600,
    version_id: Optional[str] = None,
    content_type: Optional[str] = None,
    metadata: Optional[Mapping[str, str]] = None,
    tags: Optional[Mapping[str, str]] = None,
    kms_key_id: Optional[str] = None,
    content_disposition: Optional[str] = None
) -> PresignedUrlResult

Generate a presigned URL for GET or PUT operations.

Returns a time-limited URL that grants temporary access to an object without requiring credentials. Useful for direct browser uploads/downloads.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
operation str

HTTP method - either "GET" (download) or "PUT" (upload). Defaults to "GET".

'GET'
expiration_seconds int

URL validity duration in seconds. Must be between 1 and 604800 (7 days). Defaults to 3600 (1 hour).

3600
version_id Optional[str]

Specific object version (GET only). Optional.

None
content_type Optional[str]

MIME type for PUT operations. Optional but recommended.

None
metadata Optional[Mapping[str, str]]

Custom metadata for PUT operations. Optional.

None
tags Optional[Mapping[str, str]]

Object tags for PUT operations. Optional.

None
kms_key_id Optional[str]

KMS key ARN for server-side encryption (PUT). Optional.

None
content_disposition Optional[str]

Content-Disposition header value. Optional.

None

Returns:

Type Description
PresignedUrlResult

PresignedUrlResult with: - url: The presigned URL string - expiration: Absolute expiration datetime (UTC) - correlation_id: Unique request identifier - http_method: The HTTP method (GET/PUT) - required_headers: Headers that must be included in the request

Raises:

Type Description
InvalidArgumentException

If key is empty, operation is not GET/PUT, or expiration is out of range.

SubstrateSdkException

On provider error (bucket not found, etc.).

upload_directory async

upload_directory(
    local_source_directory: str,
    *,
    prefix: str = "",
    include_sub_folders: bool = True,
    follow_symbolic_links: bool = False,
    max_concurrency: int = DEFAULT_MAX_CONCURRENCY,
    tags: Optional[Mapping[str, str]] = None
) -> AsyncDirectoryUploadResponse

Upload a local directory to cloud storage asynchronously.

Uploads all files in the specified local directory to the bucket, preserving the directory structure as key prefixes. Operations are parallelized using asyncio with bounded concurrency.

Parameters:

Name Type Description Default
local_source_directory str

Absolute or relative path to the local directory to upload.

required
prefix str

Key prefix to prepend to all uploaded objects.

''
include_sub_folders bool

Whether to recurse into subdirectories.

True
follow_symbolic_links bool

Whether to follow symlinks during traversal.

False
max_concurrency int

Maximum number of concurrent upload coroutines. Defaults to 10.

DEFAULT_MAX_CONCURRENCY
tags Optional[Mapping[str, str]]

Tags to apply to all uploaded objects. Encoding is provider-specific. Optional.

None

Returns:

Type Description
AsyncDirectoryUploadResponse

AsyncDirectoryUploadResponse with total files, successful

AsyncDirectoryUploadResponse

uploads, per-file failures, and bytes transferred.

Raises:

Type Description
InvalidArgumentException

If the source directory doesn't exist or is not a directory.

download_directory async

download_directory(
    prefix: str,
    local_destination_directory: str,
    *,
    max_concurrency: int = DEFAULT_MAX_CONCURRENCY,
    prefixes_to_exclude: Optional[List[str]] = None
) -> AsyncDirectoryDownloadResponse

Download all objects under a prefix to a local directory asynchronously.

Downloads all objects matching the specified prefix into the local directory, preserving the key structure as subdirectories. Operations are parallelized using asyncio with bounded concurrency.

Parameters:

Name Type Description Default
prefix str

Key prefix identifying the "directory" to download.

required
local_destination_directory str

Local path to write files into.

required
max_concurrency int

Maximum concurrent download coroutines. Defaults to 10.

DEFAULT_MAX_CONCURRENCY
prefixes_to_exclude Optional[List[str]]

Prefixes to skip during download. Optional.

None

Returns:

Type Description
AsyncDirectoryDownloadResponse

AsyncDirectoryDownloadResponse with total files, successful

AsyncDirectoryDownloadResponse

downloads, per-file failures, and bytes transferred.

Raises:

Type Description
InvalidArgumentException

If the prefix or destination is empty.

delete_directory async

delete_directory(
    prefix: Optional[str],
    *,
    max_concurrency: int = DEFAULT_MAX_CONCURRENCY
) -> None

Delete all objects under a prefix asynchronously.

Deletes every object whose key begins with the prefix. Deletes are parallelized using asyncio with bounded concurrency. A prefix matching no objects is a successful no-op, and objects already absent count as deleted.

The prefix is matched verbatim and is never normalized, so a prefix without a trailing "/" also matches sibling keys sharing its leading characters -- "logs" matches "logs.txt" and "logs-archive/x" as well as "logs/x". Pass a trailing "/" to target only the directory.

Warning

An empty or None prefix matches every object in the bucket and deletes all of them.

Only the current version of each object is deleted, so on a version-enabled bucket earlier versions are retained and storage is not necessarily reclaimed. The operation is not atomic: objects written under the prefix while it runs may survive.

Parameters:

Name Type Description Default
prefix Optional[str]

Key prefix identifying the "directory" to delete. Empty or None deletes every object in the bucket.

required
max_concurrency int

Maximum concurrent delete coroutines. Defaults to 10.

DEFAULT_MAX_CONCURRENCY

Raises:

Type Description
InvalidArgumentException

If max_concurrency is not positive.

SubstrateSdkException

If any matched object could not be deleted.

list_page async

list_page(
    *,
    prefix: Optional[str] = None,
    delimiter: Optional[str] = None,
    max_results: int = 1000,
    pagination_token: Optional[str] = None
) -> ListBlobsPageResponse

Retrieve a single page of blobs matching the given criteria.

Fetches exactly one page of listings and returns it alongside a continuation token for manual pagination. To iterate, feed the returned next_pagination_token back in as pagination_token until is_truncated is False.

Parameters:

Name Type Description Default
prefix Optional[str]

Restrict results to keys beginning with this prefix. Optional.

None
delimiter Optional[str]

Group keys sharing a common prefix up to the next delimiter into common_prefixes (e.g. "/" for a directory-style listing). Optional.

None
max_results int

Maximum number of blobs to return in this page. Defaults to 1000. Must be a positive integer.

1000
pagination_token Optional[str]

Continuation token from a previous page's next_pagination_token. Omit for the first page.

None

Returns:

Type Description
ListBlobsPageResponse

ListBlobsPageResponse with blobs, common_prefixes,

ListBlobsPageResponse

is_truncated, and next_pagination_token. Empty results

ListBlobsPageResponse

yield empty lists, is_truncated=False, and a None token.

Raises:

Type Description
InvalidArgumentException

If max_results is not a positive integer.

SubstrateSdkException

On provider error (bucket not found, etc.).

list_blob_versions

list_blob_versions(key: str) -> AsyncIterator[BlobInfo]

Iterate every version of one key.

Not a coroutine, so no await is needed to obtain the iterator::

async for info in client.list_blob_versions("report.pdf"):
    print(info.version_id, info.size)

Pages are fetched as they are consumed, so a key with many versions is never held in memory all at once.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required

Returns:

Type Description
AsyncIterator[BlobInfo]

An async iterator of BlobInfo, one per version. A key that does not

AsyncIterator[BlobInfo]

exist yields nothing rather than raising.

AsyncIterator[BlobInfo]

The order is the provider's own and is not normalised, so do not

AsyncIterator[BlobInfo]

rely on it. What is guaranteed: is_latest identifies the

AsyncIterator[BlobInfo]

current version on every provider, and last_modified is

AsyncIterator[BlobInfo]

populated on every entry, so chronology is recoverable by sorting.

Raises:

Type Description
InvalidArgumentException

If key is empty.

SubstrateSdkException

On provider error. Because the listing is lazy, this surfaces from the loop rather than from this call -- including a failure on the very first page.

does_object_exist async

does_object_exist(
    key: str, *, version_id: Optional[str] = None
) -> bool

Check if an object exists in the bucket.

Parameters:

Name Type Description Default
key str

Object key (path) in the bucket.

required
version_id Optional[str]

Specific object version to check. Optional. Provider support varies.

None

Returns:

Type Description
bool

True if the object exists, False otherwise.

Raises:

Type Description
InvalidArgumentException

If key is empty or version_id unsupported.

does_bucket_exist async

does_bucket_exist() -> bool

Check if the configured bucket exists.

Returns:

Type Description
bool

True if the bucket exists, False otherwise.

initiate_multipart_upload async

initiate_multipart_upload(
    key: str,
    *,
    metadata: Optional[Mapping[str, str]] = None,
    content_type: Optional[str] = None,
    tags: Optional[Mapping[str, str]] = None
) -> MultipartUpload

Start a multipart upload.

Parameters:

Name Type Description Default
key str

Object key the assembled parts will be written to.

required
metadata Optional[Mapping[str, str]]

User metadata to set on the finished object.

None
content_type Optional[str]

MIME type of the finished object.

None
tags Optional[Mapping[str, str]]

Tags to set on the finished object.

None

Returns:

Type Description
MultipartUpload

A handle identifying the session, to pass to the calls below.

Raises:

Type Description
InvalidArgumentException

If the key is empty.

SubstrateSdkException

If the provider rejects the request.

The handle is only meaningful to the client that created it. Whether a stale or hand-built one is detected is provider-dependent: some report it on the next call, others accept it and orphan the part, so do not rely on either.

upload_part async

upload_part(
    mpu: MultipartUpload, part: MultipartPart
) -> UploadPartResponse

Upload one part.

Parameters:

Name Type Description Default
mpu MultipartUpload

Handle from :meth:initiate_multipart_upload.

required
part MultipartPart

Part number and content. Part numbers start at 1; the maximum is provider-specific.

required

Returns:

Type Description
UploadPartResponse

The part's ETag, which completion needs.

Raises:

Type Description
InvalidArgumentException

If the part number is below 1, above the provider's ceiling, or the content length does not match the bytes read.

SubstrateSdkException

If the upload is unknown to the provider, or the request fails.

complete_multipart_upload async

complete_multipart_upload(
    mpu: MultipartUpload, parts: List[UploadPartResponse]
) -> MultipartUploadResponse

Assemble the uploaded parts into the final object.

Parameters:

Name Type Description Default
mpu MultipartUpload

Handle from :meth:initiate_multipart_upload.

required
parts List[UploadPartResponse]

The results of the part uploads. Order does not matter; parts are assembled by part number, and a repeated part number is rejected.

required

Raises:

Type Description
InvalidArgumentException

If parts is empty or repeats a part number.

SubstrateSdkException

If the upload is unknown to the provider, a part is missing, or a part is below the provider's minimum size.

How much of each entry is used varies by provider: all of them need the part number, and some also verify the ETag. Pass the responses you got from :meth:upload_part unmodified rather than reconstructing them.

list_parts async

list_parts(
    mpu: MultipartUpload,
) -> List[UploadPartResponse]

List the parts uploaded so far for an in-progress upload.

Parameters:

Name Type Description Default
mpu MultipartUpload

Handle from :meth:initiate_multipart_upload.

required

Returns:

Type Description
List[UploadPartResponse]

The parts the provider currently holds, ascending by part number.

List[UploadPartResponse]

Every page is fetched, so a long upload is not truncated.

Raises:

Type Description
SubstrateSdkException

If the request fails.

An upload the provider has no record of is not reported uniformly: some raise, others return an empty list, so do not rely on either. Which fields are populated also varies; the part number is always set.

abort_multipart_upload async

abort_multipart_upload(mpu: MultipartUpload) -> None

Discard an upload and its parts.

Idempotent, so it is safe in a finally. Without it, the parts of an abandoned upload are retained and billed.

Raises:

Type Description
SubstrateSdkException

If the parts could not be discarded, for instance when the credentials do not permit it. An upload that is already gone is not an error.

close async

close() -> None

Release underlying resources (HTTP sessions, connections).

BlobIdentifier dataclass

BlobIdentifier(key: str, version_id: Optional[str] = None)

Identifies a blob for bulk delete operations.

Attributes:

Name Type Description
key str

Object key (path) in the bucket. Required.

version_id Optional[str]

Specific object version to delete. Optional. If None, targets the latest version (or inserts a delete marker on versioned buckets).

AsyncDirectoryDownloadResponse dataclass

AsyncDirectoryDownloadResponse(
    total_files: int = 0,
    successful_downloads: int = 0,
    failed_transfers: List[
        FailedAsyncBlobDownload
    ] = list(),
    total_bytes_transferred: int = 0,
)

Result of an async directory download operation.

Attributes:

Name Type Description
total_files int

Total number of files attempted.

successful_downloads int

Number of files successfully downloaded.

failed_transfers List[FailedAsyncBlobDownload]

List of per-file failures with destination and exception.

total_bytes_transferred int

Total bytes successfully downloaded.

has_failures property

has_failures: bool

True if any downloads failed.

AsyncDirectoryUploadResponse dataclass

AsyncDirectoryUploadResponse(
    total_files: int = 0,
    successful_uploads: int = 0,
    failed_transfers: List[FailedAsyncBlobUpload] = list(),
    total_bytes_transferred: int = 0,
)

Result of an async directory upload operation.

Attributes:

Name Type Description
total_files int

Total number of files attempted.

successful_uploads int

Number of files successfully uploaded.

failed_transfers List[FailedAsyncBlobUpload]

List of per-file failures with source and exception.

total_bytes_transferred int

Total bytes successfully uploaded.

has_failures property

has_failures: bool

True if any uploads failed.

AsyncDownloadRequest dataclass

AsyncDownloadRequest(
    key: str,
    version_id: Optional[str] = None,
    start: Optional[int] = None,
    end: Optional[int] = None,
    if_match: Optional[str] = None,
)

Request parameters for an async download operation.

Attributes:

Name Type Description
key str

Object key (path) in the bucket.

version_id Optional[str]

Specific object version to download. Optional. Provider support varies -- implementations that do not support versioning will raise InvalidArgumentException.

start Optional[int]

First byte offset (inclusive) for a range download, or None for a full download. When only start is set, produces an open-ended range (bytes=start-).

end Optional[int]

Last byte offset (inclusive, per RFC 7233) for a range download, or None. When only end is set, it is interpreted as a suffix-range meaning "last N bytes" (bytes=-N), NOT an absolute position.

if_match Optional[str]

Only download when the current ETag matches; else FailedPreconditionException. Empty/whitespace is rejected as a caller mistake. None skips the precondition.

AsyncDownloadResponse dataclass

AsyncDownloadResponse(
    key: str, content: bytes, metadata: BlobMetadata
)

Result of an async download operation.

AsyncTransferConfig dataclass

AsyncTransferConfig(
    max_concurrency: int = 50,
    multipart_threshold: int = 8 * 1024 * 1024,
    multipart_chunksize: int = 8 * 1024 * 1024,
    download_chunk_size: int = 1024 * 1024,
)

Configuration for async transfer operations.

Fields below are reserved for the upcoming multipart upload and streaming download phases; they are not yet honored by the single-shot upload path shipped in this release.

AsyncUploadResponse dataclass

AsyncUploadResponse(
    key: str,
    e_tag: Optional[str] = None,
    version_id: Optional[str] = None,
)

Result of an async upload operation.

BlobAsyncError

BlobAsyncError(
    message: str, *, cause: Optional[Exception] = None
)

Bases: SubstrateSdkException

Transport failure during an async blob operation.

BlobNotFoundError

BlobNotFoundError(
    message: str,
    *,
    key: Optional[str] = None,
    cause: Optional[Exception] = None
)

Bases: BlobAsyncError, ResourceNotFoundException

The requested blob was not found in the bucket.

Also a ResourceNotFoundException so that a caller writing one except ResourceNotFoundException handles a missing blob the same way whichever provider raised it, and the same way the synchronous client reports it.

BulkDeleteResponse dataclass

BulkDeleteResponse(
    deleted: list[DeletedBlob] = list(),
    errors: list[DeleteError] = list(),
)

Result of a bulk delete operation.

Reports per-object outcomes. The operation does NOT raise on partial failure — inspect errors for failed items.

Attributes:

Name Type Description
deleted list[DeletedBlob]

List of successfully deleted objects.

errors list[DeleteError]

List of objects that failed to delete.

has_errors property

has_errors: bool

True if any objects failed to delete.

AsyncCopyRequest dataclass

AsyncCopyRequest(
    source_bucket: str,
    source_key: str,
    destination_bucket: str,
    destination_key: str,
    source_version_id: Optional[str] = None,
    metadata: Optional[Mapping[str, str]] = None,
)

Request parameters for an async blob copy operation.

Supports same-bucket copy (rename/move pattern) and cross-bucket copy. Metadata override replaces the source object's metadata on the copy.

Attributes:

Name Type Description
source_bucket str

Bucket containing the source object.

source_key str

Key of the source object to copy.

destination_bucket str

Bucket for the copied object.

destination_key str

Key for the copied object.

source_version_id Optional[str]

Specific version of the source to copy (optional).

metadata Optional[Mapping[str, str]]

If provided, replaces the source object's metadata on the destination. If None, the source metadata is preserved.

AsyncCopyResponse dataclass

AsyncCopyResponse(
    key: str,
    version_id: Optional[str] = None,
    e_tag: Optional[str] = None,
    last_modified: Optional[str] = None,
    correlation_id: Optional[str] = None,
)

Result of an async blob copy operation.

Attributes:

Name Type Description
key str

Destination key where the object was copied to.

version_id Optional[str]

Version ID of the newly created copy (if versioning is enabled on the destination bucket). None otherwise.

e_tag Optional[str]

Entity tag (checksum) of the new copy.

last_modified Optional[str]

ISO-8601 timestamp of when the copy was created. Corresponds to S3 CopyObjectResult.LastModified or GCS timeCreated/updated. None if not available from the provider.

correlation_id Optional[str]

Unique identifier for tracking this operation.

DeleteError dataclass

DeleteError(
    key: str,
    version_id: Optional[str] = None,
    code: str = "",
    message: str = "",
)

A blob that failed to delete in a bulk delete operation.

Attributes:

Name Type Description
key str

Object key that failed.

version_id Optional[str]

Version that was targeted (if specified).

code str

Provider-specific error code (e.g. "AccessDenied").

message str

Human-readable error description.

DeletedBlob dataclass

DeletedBlob(key: str, version_id: Optional[str] = None)

A successfully deleted blob entry in a bulk delete response.

Attributes:

Name Type Description
key str

Object key that was deleted.

version_id Optional[str]

Version that was deleted (if versioned bucket).

FailedAsyncBlobDownload dataclass

FailedAsyncBlobDownload(
    destination: Path, exception: Exception
)

A single failed download within an async directory download operation.

FailedAsyncBlobUpload dataclass

FailedAsyncBlobUpload(source: Path, exception: Exception)

A single failed upload within an async directory upload operation.

PresignedUrlResult dataclass

PresignedUrlResult(
    url: str,
    expiration: datetime,
    correlation_id: str,
    http_method: str = "GET",
    required_headers: Mapping[str, str] = (
        lambda: MappingProxyType({})
    )(),
)

Result of an async presigned URL generation.

Attributes:

Name Type Description
url str

The presigned URL string for direct blob access.

expiration datetime

UTC datetime when the URL expires.

correlation_id str

Unique identifier for tracing/correlation.

http_method str

The HTTP method the consumer must use ("GET" or "PUT").

required_headers Mapping[str, str]

Headers the consumer MUST include in the HTTP request for the presigned URL to work. Includes signed metadata, content-type, and encryption headers. Empty mapping if none required.