objectstore_client package

class objectstore_client.Client(base_url: str, metrics_backend: MetricsBackend | None = None, propagate_traces: bool = False, retries: int | None = None, timeout_ms: float | None = None, connection_kwargs: Mapping[str, Any] | None = None, token: SecretKey | str | None = None)[source]

Bases: object

A client for Objectstore. Constructing it initializes a connection pool.

Parameters:
  • base_url – The base URL of the Objectstore server (e.g., “http://objectstore:8888”). metrics_backend: Optional metrics backend for tracking storage operations. Defaults to NoOpMetricsBackend if not provided.

  • propagate_traces – Whether to propagate Sentry trace headers in requests to objectstore. Defaults to False.

  • retries – Number of connection retries for failed requests. Defaults to 3 if not specified. Note: only connection failures are retried, not read failures (as compression streams cannot be rewound).

  • timeout_ms

    Read timeout in milliseconds for API requests. The read timeout is the maximum time to wait between consecutive read operations on the socket (i.e., between receiving chunks of data). Defaults to no read timeout if not specified. The connection timeout is always 100ms. To override the connection timeout, pass a custom urllib3.Timeout object via connection_kwargs. For example:

    client = Client(
        "http://objectstore:8888", connection_kwargs={
            "timeout": urllib3.Timeout(connect=1.0, read=5.0)
        }
    )
    

  • connection_kwargs – Additional keyword arguments to pass to the underlying urllib3 connection pool (e.g., custom headers, SSL settings, advanced timeouts).

  • token – A SecretKey that signs a fresh JWT for each request using an EdDSA keypair, or a static pre-signed JWT string used as-is for every request. Use a SecretKey for internal services that have access to the signing key, and a string for external services that receive a token from another source.

session(usecase: Usecase, **scopes: str | int | bool) Session[source]

Create a [Session] with the Objectstore server, tied to a specific [Usecase] and [Scope].

A Scope is a (possibly nested) namespace within a Usecase, given as a sequence of key-value pairs passed as kwargs. IMPORTANT: the order of the kwargs matters!

The admitted characters for keys and values are: A-Za-z0-9_-()$!+’.

Users are free to choose the scope structure that best suits their Usecase. The combination of Usecase and Scope will determine the physical key/path of the blob in the underlying storage backend.

For most usecases, it’s recommended to use the organization and project ID as the first components of the scope, as follows: ` client.session(usecase, org=organization_id, project=project_id, ...) `

Parameters:
  • usecase – The Usecase to scope this session to.

  • **scopes – Key-value pairs defining the scope within the usecase.

class objectstore_client.GetResponse(metadata, payload)[source]

Bases: NamedTuple

metadata: Metadata

Alias for field number 0

payload: IO[bytes]

Alias for field number 1

class objectstore_client.Metadata(content_type: 'str | None', compression: 'Compression | None', expiration_policy: 'ExpirationPolicy | None', time_created: 'datetime | None', time_expires: 'datetime | None', origin: 'str | None', filename: 'str | None', custom: 'dict[str, str]')[source]

Bases: object

compression: Literal['zstd'] | Literal['none'] | None
content_type: str | None
custom: dict[str, str]
expiration_policy: TimeToIdle | TimeToLive | None
filename: str | None

An optional filename associated with this object.

When present, the server includes a Content-Disposition header in GET responses, prompting browsers and download tools to save the file under this name.

classmethod from_headers(headers: Mapping[str, str]) Metadata[source]
origin: str | None

The origin of the object, typically the IP address of the original source.

This tracks where the payload was originally obtained from (e.g., the IP of a Sentry SDK or CLI).

time_created: datetime | None

Timestamp indicating when the object was created or the last time it was replaced.

This means that a PUT request to an existing object causes this value to be bumped. This field is computed by the server, it cannot be set by clients.

time_expires: datetime | None

Timestamp indicating when the object will expire.

When using a Time To Idle expiration policy, this value will reflect the expiration timestamp present prior to the current access to the object.

This field is computed by the server, it cannot be set by clients. Use expiration_policy to set an expiration policy instead.

class objectstore_client.MetricsBackend(*args, **kwargs)[source]

Bases: Protocol

An abstract class that defines the interface for metrics backends.

abstractmethod distribution(name: str, value: int | float, tags: Mapping[str, str] | None = None, unit: str | None = None) None[source]

Records a distribution metric.

abstractmethod gauge(name: str, value: int | float, tags: Mapping[str, str] | None = None) None[source]

Sets a gauge metric to the given value.

abstractmethod increment(name: str, value: int | float = 1, tags: Mapping[str, str] | None = None) None[source]

Increments a counter metric by a given value.

class objectstore_client.NoOpMetricsBackend(*args, **kwargs)[source]

Bases: MetricsBackend

Default metrics backend that does not record anything.

distribution(name: str, value: int | float, tags: Mapping[str, str] | None = None, unit: str | None = None) None[source]

Records a distribution metric.

gauge(name: str, value: int | float, tags: Mapping[str, str] | None = None) None[source]

Sets a gauge metric to the given value.

increment(name: str, value: int | float = 1, tags: Mapping[str, str] | None = None) None[source]

Increments a counter metric by a given value.

class objectstore_client.Permission(value)[source]

Bases: StrEnum

Enum listing permissions that Objectstore tokens may be granted.

OBJECT_DELETE = 'object.delete'
OBJECT_READ = 'object.read'
OBJECT_WRITE = 'object.write'
classmethod max() list[Self][source]
exception objectstore_client.RequestError(message: str, status: int, response: str)[source]

Bases: Exception

Exception raised if an API call to Objectstore fails.

class objectstore_client.SecretKey(kid: str, secret_key: str, expiry_seconds: int = 60, permissions: list[Permission] | None = None)[source]

Bases: object

An EdDSA keypair used to authenticate with Objectstore.

Can generate JWTs for request-level auth and sign canonical forms for pre-signed URLs. Pass a SecretKey directly to Client(token=...) and it will sign a fresh JWT for each request.

sign_for_scope(usecase: str, scope: Scope, permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str

Sign a JWT for the passed-in usecase and scope using the configured key information, expiry, and permissions.

When permissions is None, the default permissions are used. When provided, they override the defaults for this token only.

When expiry_seconds is None, the default expiry is used.

Raises ValueError if any requested permission is not granted to this key.

The JWT is signed using EdDSA, so self.secret_key must be an EdDSA private key. self.kid is used by the Objectstore server to load the corresponding public key from its configuration.

signature_for_canonical_form(canonical_form: str) str[source]

Signs a canonical request form with the Ed25519 private key.

Returns the base64url-encoded (no padding) signature, suitable as the value of the os_sig query parameter.

token_for_scope(usecase: str, scope: Scope, permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str[source]

Sign a JWT for the passed-in usecase and scope using the configured key information, expiry, and permissions.

When permissions is None, the default permissions are used. When provided, they override the defaults for this token only.

When expiry_seconds is None, the default expiry is used.

Raises ValueError if any requested permission is not granted to this key.

The JWT is signed using EdDSA, so self.secret_key must be an EdDSA private key. self.kid is used by the Objectstore server to load the corresponding public key from its configuration.

class objectstore_client.Session(pool: HTTPConnectionPool, base_path: str, metrics_backend: MetricsBackend, propagate_traces: bool, usecase: Usecase, scope: Scope, token: SecretKey | str | None = None)[source]

Bases: object

A session with the Objectstore server, scoped to a specific [Usecase] and Scope.

This should never be constructed directly, use [Client.session].

delete(key: str) None[source]

Deletes the blob with the given key.

get(key: str, decompress: bool = True, accept_encoding: Sequence[str] | None = None) GetResponse[source]

This fetches the blob with the given key, returning an IO stream that can be read.

By default, content that was uploaded compressed will be automatically decompressed, unless decompress=False is passed.

If accept_encoding is provided, any compression algorithm listed there will be passed through compressed instead of decompressed, even when decompress=True. For example, passing accept_encoding=[“zstd”] returns the raw zstd-compressed bytes when the stored object is zstd-compressed.

head(key: str) Metadata | None[source]

Checks whether an object exists and retrieves its metadata.

Returns the object’s Metadata if it exists, None otherwise.

If the object has a TTI expiration policy, this is considered an access, and therefore bumps its expiration.

initiate_multipart_upload(*, key: str | None = None, compression: Literal['zstd'] | Literal['none'] | None = None, content_type: str | None = None, metadata: dict[str, str] | None = None, expiration_policy: TimeToIdle | TimeToLive | None = None, origin: str | None = None, filename: str | None = None) MultipartUpload[source]

Initiates a multipart upload.

Returns a MultipartUpload handle that can be used to upload parts, list parts, complete, or abort.

Important: unlike put(), the compression parameter only records the compression algorithm in the object’s metadata. The caller is responsible for compressing each part in accordance with the chosen algorithm before passing it to upload_part().

mint_token(permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str[source]

Returns a signed token.

When permissions is None, the generator’s default permissions are used. When provided, they must be a subset of the generator’s permissions.

When expiry_seconds is None, the generator’s default expiry is used.

Raises ValueError if no SecretKey is configured or if any requested permission is not granted to the key.

object_url(key: str, token_validity: timedelta | None = None) str[source]

Generates a GET url to the object with the given key.

This can then be used by downstream services to fetch the given object. NOTE however that the service does not strictly follow HTTP semantics, in particular in relation to Accept-Encoding.

When token_validity is provided, read-only authorization information is embedded in the returned URL’s query string, valid for the given duration.

Raises ValueError if token_validity is provided but no SecretKey is configured on this session.

presigned_object_url(method: Literal['GET', 'HEAD'], key: str, duration: timedelta = datetime.timedelta(seconds=3600)) str[source]

Generates a pre-signed URL authorizing a single method request on the object with the given key, valid for duration.

Warning

Experimental: pre-signed URLs are an experimental feature and this API may change in a future release.

Raises ValueError if no SecretKey is configured on this session’s client, if method is not supported, or if duration is above the one-week maximum.

The returned URL carries a signature that allows the recipient to perform a request without an auth token. It can be handed to any HTTP client; the URL is already percent-encoded, and must be transmitted verbatim.

Note that HEAD and GET are considered equivalent from the point of view of signatures, meaning that a signature for GET can also be used for HEAD, and viceversa.

put(contents: bytes | IO[bytes], key: str | None = None, compression: Literal['zstd'] | Literal['none'] | None = None, content_type: str | None = None, metadata: dict[str, str] | None = None, expiration_policy: TimeToIdle | TimeToLive | None = None, origin: str | None = None, filename: str | None = None) str[source]

Uploads the given contents to blob storage.

If no key is provided, one will be automatically generated and returned from this function.

The client will select the configured default_compression if none is given explicitly. This can be overridden by explicitly giving a compression argument. Providing “none” as the argument will instruct the client to not apply any compression to this upload, which is useful for uncompressible formats.

You can use the utility function objectstore_client.utils.guess_mime_type to attempt to guess a content_type based on magic bytes.

resume_multipart_upload(key: str, upload_id: str) MultipartUpload[source]

Reconstructs a multipart upload handle.

This does not make any network calls. Use it to resume an upload after a process restart or to continue an upload started elsewhere.

class objectstore_client.TimeToIdle(delta: 'timedelta')[source]

Bases: object

delta: timedelta
class objectstore_client.TimeToLive(delta: 'timedelta')[source]

Bases: object

delta: timedelta
objectstore_client.TokenGenerator

alias of SecretKey

class objectstore_client.Usecase(name: str, compression: Literal['zstd', 'none'] = 'zstd', expiration_policy: TimeToIdle | TimeToLive | None = None)[source]

Bases: object

An identifier for a workload in Objectstore, along with defaults to use for all operations within that Usecase.

Usecases need to be statically defined in Objectstore’s configuration server-side. Objectstore can make decisions based on the Usecase. For example, choosing the most suitable storage backend.

name: str
objectstore_client.parse_accept_encoding(header: str) list[str][source]

Parse an Accept-Encoding header value for use in objectstore GET requests.

Returns a list of encoding names, normalized to lowercase and stripped of q-values, per RFC 7231. Encodings explicitly rejected via q=0 are excluded.

Note: identity;q=0 is not supported and will be silently ignored (i.e., treated as acceptable), since objectstore always serves an identity fallback.

Submodules

objectstore_client.auth module

class objectstore_client.auth.Permission(value)[source]

Bases: StrEnum

Enum listing permissions that Objectstore tokens may be granted.

OBJECT_DELETE = 'object.delete'
OBJECT_READ = 'object.read'
OBJECT_WRITE = 'object.write'
classmethod max() list[Self][source]
class objectstore_client.auth.SecretKey(kid: str, secret_key: str, expiry_seconds: int = 60, permissions: list[Permission] | None = None)[source]

Bases: object

An EdDSA keypair used to authenticate with Objectstore.

Can generate JWTs for request-level auth and sign canonical forms for pre-signed URLs. Pass a SecretKey directly to Client(token=...) and it will sign a fresh JWT for each request.

sign_for_scope(usecase: str, scope: Scope, permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str

Sign a JWT for the passed-in usecase and scope using the configured key information, expiry, and permissions.

When permissions is None, the default permissions are used. When provided, they override the defaults for this token only.

When expiry_seconds is None, the default expiry is used.

Raises ValueError if any requested permission is not granted to this key.

The JWT is signed using EdDSA, so self.secret_key must be an EdDSA private key. self.kid is used by the Objectstore server to load the corresponding public key from its configuration.

signature_for_canonical_form(canonical_form: str) str[source]

Signs a canonical request form with the Ed25519 private key.

Returns the base64url-encoded (no padding) signature, suitable as the value of the os_sig query parameter.

token_for_scope(usecase: str, scope: Scope, permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str[source]

Sign a JWT for the passed-in usecase and scope using the configured key information, expiry, and permissions.

When permissions is None, the default permissions are used. When provided, they override the defaults for this token only.

When expiry_seconds is None, the default expiry is used.

Raises ValueError if any requested permission is not granted to this key.

The JWT is signed using EdDSA, so self.secret_key must be an EdDSA private key. self.kid is used by the Objectstore server to load the corresponding public key from its configuration.

objectstore_client.auth.TokenGenerator

alias of SecretKey

objectstore_client.auth.TokenProvider = objectstore_client.auth.SecretKey | str

Authentication provider for Objectstore requests.

Can be either a SecretKey that signs a fresh JWT per request, or a static pre-signed JWT string.

objectstore_client.client module

class objectstore_client.client.Client(base_url: str, metrics_backend: MetricsBackend | None = None, propagate_traces: bool = False, retries: int | None = None, timeout_ms: float | None = None, connection_kwargs: Mapping[str, Any] | None = None, token: SecretKey | str | None = None)[source]

Bases: object

A client for Objectstore. Constructing it initializes a connection pool.

Parameters:
  • base_url – The base URL of the Objectstore server (e.g., “http://objectstore:8888”). metrics_backend: Optional metrics backend for tracking storage operations. Defaults to NoOpMetricsBackend if not provided.

  • propagate_traces – Whether to propagate Sentry trace headers in requests to objectstore. Defaults to False.

  • retries – Number of connection retries for failed requests. Defaults to 3 if not specified. Note: only connection failures are retried, not read failures (as compression streams cannot be rewound).

  • timeout_ms

    Read timeout in milliseconds for API requests. The read timeout is the maximum time to wait between consecutive read operations on the socket (i.e., between receiving chunks of data). Defaults to no read timeout if not specified. The connection timeout is always 100ms. To override the connection timeout, pass a custom urllib3.Timeout object via connection_kwargs. For example:

    client = Client(
        "http://objectstore:8888", connection_kwargs={
            "timeout": urllib3.Timeout(connect=1.0, read=5.0)
        }
    )
    

  • connection_kwargs – Additional keyword arguments to pass to the underlying urllib3 connection pool (e.g., custom headers, SSL settings, advanced timeouts).

  • token – A SecretKey that signs a fresh JWT for each request using an EdDSA keypair, or a static pre-signed JWT string used as-is for every request. Use a SecretKey for internal services that have access to the signing key, and a string for external services that receive a token from another source.

session(usecase: Usecase, **scopes: str | int | bool) Session[source]

Create a [Session] with the Objectstore server, tied to a specific [Usecase] and [Scope].

A Scope is a (possibly nested) namespace within a Usecase, given as a sequence of key-value pairs passed as kwargs. IMPORTANT: the order of the kwargs matters!

The admitted characters for keys and values are: A-Za-z0-9_-()$!+’.

Users are free to choose the scope structure that best suits their Usecase. The combination of Usecase and Scope will determine the physical key/path of the blob in the underlying storage backend.

For most usecases, it’s recommended to use the organization and project ID as the first components of the scope, as follows: ` client.session(usecase, org=organization_id, project=project_id, ...) `

Parameters:
  • usecase – The Usecase to scope this session to.

  • **scopes – Key-value pairs defining the scope within the usecase.

class objectstore_client.client.GetResponse(metadata, payload)[source]

Bases: NamedTuple

metadata: Metadata

Alias for field number 0

payload: IO[bytes]

Alias for field number 1

class objectstore_client.client.Session(pool: HTTPConnectionPool, base_path: str, metrics_backend: MetricsBackend, propagate_traces: bool, usecase: Usecase, scope: Scope, token: SecretKey | str | None = None)[source]

Bases: object

A session with the Objectstore server, scoped to a specific [Usecase] and Scope.

This should never be constructed directly, use [Client.session].

delete(key: str) None[source]

Deletes the blob with the given key.

get(key: str, decompress: bool = True, accept_encoding: Sequence[str] | None = None) GetResponse[source]

This fetches the blob with the given key, returning an IO stream that can be read.

By default, content that was uploaded compressed will be automatically decompressed, unless decompress=False is passed.

If accept_encoding is provided, any compression algorithm listed there will be passed through compressed instead of decompressed, even when decompress=True. For example, passing accept_encoding=[“zstd”] returns the raw zstd-compressed bytes when the stored object is zstd-compressed.

head(key: str) Metadata | None[source]

Checks whether an object exists and retrieves its metadata.

Returns the object’s Metadata if it exists, None otherwise.

If the object has a TTI expiration policy, this is considered an access, and therefore bumps its expiration.

initiate_multipart_upload(*, key: str | None = None, compression: Literal['zstd'] | Literal['none'] | None = None, content_type: str | None = None, metadata: dict[str, str] | None = None, expiration_policy: TimeToIdle | TimeToLive | None = None, origin: str | None = None, filename: str | None = None) MultipartUpload[source]

Initiates a multipart upload.

Returns a MultipartUpload handle that can be used to upload parts, list parts, complete, or abort.

Important: unlike put(), the compression parameter only records the compression algorithm in the object’s metadata. The caller is responsible for compressing each part in accordance with the chosen algorithm before passing it to upload_part().

mint_token(permissions: list[Permission] | None = None, expiry_seconds: int | None = None) str[source]

Returns a signed token.

When permissions is None, the generator’s default permissions are used. When provided, they must be a subset of the generator’s permissions.

When expiry_seconds is None, the generator’s default expiry is used.

Raises ValueError if no SecretKey is configured or if any requested permission is not granted to the key.

object_url(key: str, token_validity: timedelta | None = None) str[source]

Generates a GET url to the object with the given key.

This can then be used by downstream services to fetch the given object. NOTE however that the service does not strictly follow HTTP semantics, in particular in relation to Accept-Encoding.

When token_validity is provided, read-only authorization information is embedded in the returned URL’s query string, valid for the given duration.

Raises ValueError if token_validity is provided but no SecretKey is configured on this session.

presigned_object_url(method: Literal['GET', 'HEAD'], key: str, duration: timedelta = datetime.timedelta(seconds=3600)) str[source]

Generates a pre-signed URL authorizing a single method request on the object with the given key, valid for duration.

Warning

Experimental: pre-signed URLs are an experimental feature and this API may change in a future release.

Raises ValueError if no SecretKey is configured on this session’s client, if method is not supported, or if duration is above the one-week maximum.

The returned URL carries a signature that allows the recipient to perform a request without an auth token. It can be handed to any HTTP client; the URL is already percent-encoded, and must be transmitted verbatim.

Note that HEAD and GET are considered equivalent from the point of view of signatures, meaning that a signature for GET can also be used for HEAD, and viceversa.

put(contents: bytes | IO[bytes], key: str | None = None, compression: Literal['zstd'] | Literal['none'] | None = None, content_type: str | None = None, metadata: dict[str, str] | None = None, expiration_policy: TimeToIdle | TimeToLive | None = None, origin: str | None = None, filename: str | None = None) str[source]

Uploads the given contents to blob storage.

If no key is provided, one will be automatically generated and returned from this function.

The client will select the configured default_compression if none is given explicitly. This can be overridden by explicitly giving a compression argument. Providing “none” as the argument will instruct the client to not apply any compression to this upload, which is useful for uncompressible formats.

You can use the utility function objectstore_client.utils.guess_mime_type to attempt to guess a content_type based on magic bytes.

resume_multipart_upload(key: str, upload_id: str) MultipartUpload[source]

Reconstructs a multipart upload handle.

This does not make any network calls. Use it to resume an upload after a process restart or to continue an upload started elsewhere.

class objectstore_client.client.Usecase(name: str, compression: Literal['zstd', 'none'] = 'zstd', expiration_policy: TimeToIdle | TimeToLive | None = None)[source]

Bases: object

An identifier for a workload in Objectstore, along with defaults to use for all operations within that Usecase.

Usecases need to be statically defined in Objectstore’s configuration server-side. Objectstore can make decisions based on the Usecase. For example, choosing the most suitable storage backend.

name: str

objectstore_client.errors module

exception objectstore_client.errors.RequestError(message: str, status: int, response: str)[source]

Bases: Exception

Exception raised if an API call to Objectstore fails.

objectstore_client.errors.raise_for_status(response: BaseHTTPResponse) None[source]

objectstore_client.metadata module

class objectstore_client.metadata.Metadata(content_type: 'str | None', compression: 'Compression | None', expiration_policy: 'ExpirationPolicy | None', time_created: 'datetime | None', time_expires: 'datetime | None', origin: 'str | None', filename: 'str | None', custom: 'dict[str, str]')[source]

Bases: object

compression: Literal['zstd'] | Literal['none'] | None
content_type: str | None
custom: dict[str, str]
expiration_policy: TimeToIdle | TimeToLive | None
filename: str | None

An optional filename associated with this object.

When present, the server includes a Content-Disposition header in GET responses, prompting browsers and download tools to save the file under this name.

classmethod from_headers(headers: Mapping[str, str]) Metadata[source]
origin: str | None

The origin of the object, typically the IP address of the original source.

This tracks where the payload was originally obtained from (e.g., the IP of a Sentry SDK or CLI).

time_created: datetime | None

Timestamp indicating when the object was created or the last time it was replaced.

This means that a PUT request to an existing object causes this value to be bumped. This field is computed by the server, it cannot be set by clients.

time_expires: datetime | None

Timestamp indicating when the object will expire.

When using a Time To Idle expiration policy, this value will reflect the expiration timestamp present prior to the current access to the object.

This field is computed by the server, it cannot be set by clients. Use expiration_policy to set an expiration policy instead.

class objectstore_client.metadata.TimeToIdle(delta: 'timedelta')[source]

Bases: object

delta: timedelta
class objectstore_client.metadata.TimeToLive(delta: 'timedelta')[source]

Bases: object

delta: timedelta
objectstore_client.metadata.format_expiration(expiration_policy: TimeToIdle | TimeToLive) str[source]
objectstore_client.metadata.format_timedelta(delta: timedelta) str[source]
objectstore_client.metadata.itertools_batched(iterable: Iterable[T], n: int, strict: bool = False) Iterator[tuple[T, ...]][source]

Vendored version of itertools.batched, not available in Python 3.11. Batch data from the iterable into tuples of length n. The last batch may be shorter than n. If strict is true, will raise a ValueError if the final batch is shorter than n. Loops over the input iterable and accumulates data into tuples up to size n. The input is consumed lazily, just enough to fill a batch. The result is yielded as soon as the batch is full or when the input iterable is exhausted:

objectstore_client.metadata.parse_expiration(value: str) TimeToIdle | TimeToLive | None[source]
objectstore_client.metadata.parse_timedelta(delta: str) timedelta[source]

objectstore_client.metrics module

class objectstore_client.metrics.MetricsBackend(*args, **kwargs)[source]

Bases: Protocol

An abstract class that defines the interface for metrics backends.

abstractmethod distribution(name: str, value: int | float, tags: Mapping[str, str] | None = None, unit: str | None = None) None[source]

Records a distribution metric.

abstractmethod gauge(name: str, value: int | float, tags: Mapping[str, str] | None = None) None[source]

Sets a gauge metric to the given value.

abstractmethod increment(name: str, value: int | float = 1, tags: Mapping[str, str] | None = None) None[source]

Increments a counter metric by a given value.

class objectstore_client.metrics.NoOpMetricsBackend(*args, **kwargs)[source]

Bases: MetricsBackend

Default metrics backend that does not record anything.

distribution(name: str, value: int | float, tags: Mapping[str, str] | None = None, unit: str | None = None) None[source]

Records a distribution metric.

gauge(name: str, value: int | float, tags: Mapping[str, str] | None = None) None[source]

Sets a gauge metric to the given value.

increment(name: str, value: int | float = 1, tags: Mapping[str, str] | None = None) None[source]

Increments a counter metric by a given value.

class objectstore_client.metrics.StorageMetricEmitter(backend: MetricsBackend, operation: str, usecase: str)[source]

Bases: object

maybe_record_compression_ratio() None[source]
maybe_record_throughputs() None[source]
record_compressed_size(value: int, compression: str = 'unknown') None[source]
record_latency(elapsed: float) None[source]
record_size(value: int) None[source]
record_uncompressed_size(value: int) None[source]
objectstore_client.metrics.measure_storage_operation(backend: MetricsBackend, operation: str, usecase: str, uncompressed_size: int | None = None, compressed_size: int | None = None, compression: str = 'unknown') Generator[StorageMetricEmitter][source]

Context manager which records the latency of the enclosed storage operation. Can also record the compressed or uncompressed size of an object, the compression ratio, the throughput, and the inverse throughput.

Yields a StorageMetricEmitter because for some operations (GET) the size is not known until the inside of the enclosed block.

objectstore_client.multipart module

class objectstore_client.multipart.CompletePart(part_number: int, etag: str)[source]

Bases: object

A reference to an uploaded part, used when completing a multipart upload.

etag: str
part_number: int
exception objectstore_client.multipart.MultipartCompleteError(code: str, message: str)[source]

Bases: RequestError

Error returned as part of a multipart:complete response’s body.

class objectstore_client.multipart.MultipartUpload(session: Session, key: str, upload_id: str)[source]

Bases: object

Handle for an in-progress multipart upload.

Create via initiate_multipart_upload() or resume_multipart_upload().

abort() None[source]

Aborts this multipart upload, cleaning up server-side state.

complete(parts: Sequence[CompletePart | PartInfo]) str[source]

Completes the multipart upload, assembling all parts into the final object.

Returns the final object key.

Raises MultipartCompleteError if the server reports an error during assembly, or RequestError if the server returns a non-2XX response.

property key: str
list_parts() list[PartInfo][source]

Lists all uploaded parts.

put_part(contents: bytes | IO[bytes], *, part_number: int, content_length: int, content_md5: bytes | None = None) CompletePart[source]

Uploads a single part.

IMPORTANT: Unlike put(), this does not automatically compress contents. The caller must pre-compress each part according to the compression set as part of the metadata when initiating the upload.

Parameters:
  • contents – The part data. If this upload was initiated with compression, this must be pre-compressed.

  • part_number – 1-indexed part number.

  • content_length – The length in bytes of the payload being uploaded. If this upload was initiated with compression, this must be the post-compression length.

  • content_md5 – Optional raw MD5 digest of contents.

property upload_id: str
class objectstore_client.multipart.PartInfo(part_number: int, etag: str, last_modified: datetime, size: int)[source]

Bases: object

Information about an uploaded part

etag: str
last_modified: datetime
part_number: int
size: int

objectstore_client.presign module

Utilities for pre-signed URLs.

A pre-signed URL lets a client that owns an Ed25519 keypair hand out a time-limited URL that authorizes a specific request, without the recipient needing an auth token.

Experimental: pre-signed URLs are an experimental feature and this API may change in a future release.

See objectstore-types/src/presign.rs for details on the scheme.

objectstore_client.presign.build_canonical_form(method: str, encoded_path: str, encoded_query: str) str[source]

Builds the canonical form of a request to be signed.

encoded_path and encoded_query must already be percent-encoded as they will appear on the wire (see objectstore_client.utils.encode_path() and objectstore_client.utils.encode_query()).

objectstore_client.scope module

class objectstore_client.scope.Scope(**scopes: str | int | bool)[source]

Bases: object

dict() dict[str, str | int | bool][source]

objectstore_client.utils module

objectstore_client.utils.encode_path(path: str) str[source]

Percent-encodes a request path as it will appear on the wire.

Leaves the RFC 3986 unreserved set, sub-delims, and : @ / unescaped (see _PATH_SAFE); everything else is percent-encoded. This treats the input as a literal string: a literal % becomes %25.

objectstore_client.utils.encode_query(query: str) str[source]

Percent-encodes a query string as it will appear on the wire.

Same set as encode_path(), additionally leaving ? unescaped (see _QUERY_SAFE).

objectstore_client.utils.guess_mime_type(contents: bytes | IO[bytes]) str | None[source]

Guesses the MIME type from the given contents.

Reads up to 261 bytes from the beginning of the content to determine the MIME type using file header signatures.

To guess the MIME type from a filename, use mimetypes.guess_type, which is part of the standard library.

objectstore_client.utils.parse_accept_encoding(header: str) list[str][source]

Parse an Accept-Encoding header value for use in objectstore GET requests.

Returns a list of encoding names, normalized to lowercase and stripped of q-values, per RFC 7231. Encodings explicitly rejected via q=0 are excluded.

Note: identity;q=0 is not supported and will be silently ignored (i.e., treated as acceptable), since objectstore always serves an identity fallback.