yggdrasil.aws.fs.s3_http¶
s3_http ¶
Pure-HTTP S3 REST client — the boto3-free S3 data plane.
Speaks the S3 REST API directly over :class:yggdrasil.http_.session.HTTPSession
(connection pooling, retries, streaming) with requests signed by
:class:yggdrasil.aws.fs.sigv4.SigV4Signer. Covers exactly what
:class:yggdrasil.aws.fs.path.S3Path needs:
HEAD/ rangedGET/PUT/DELETEsingle objects,ListObjectsV2(paginated,CommonPrefixes+Contents),- multi-object
DeleteObjects, - multipart upload (create / upload-part / complete / abort) so a multi-GB write streams to S3 in bounded-memory parts.
The wire is reached through an injectable transport — (method, url,
headers, body) -> S3Response — defaulting to an :class:HTTPSession. Tests
swap in an in-memory transport; production rides the pooled session. XML is
parsed with the stdlib (S3 list/multipart payloads are small + flat).
S3Error ¶
Bases: OSError
Non-success S3 response (4xx/5xx that isn't a benign 404/416).
S3NotFound ¶
S3Response
dataclass
¶
Minimal wire response the transport hands back.
S3HttpClient ¶
S3HttpClient(
*,
bucket: str,
endpoint: URL,
signer: SigV4Signer,
transport: Optional[Callable[..., S3Response]] = None,
path_style: bool = False,
region: Optional[str] = None,
managed: bool = True,
no_proxy: Optional[str] = None
)
Signed S3 REST client for one bucket.
endpoint is the scheme+host the bucket lives behind (virtual-hosted
https://<bucket>.s3.<region>.amazonaws.com by default; a path-style
override host is honored for S3-compatible stores). One instance per
:class:yggdrasil.aws.fs.path.S3Bucket, so the pooled session and signer
are shared by every key under it.
head ¶
HEAD — returns the response (Content-Length / Last-Modified /
Content-Type in headers) or None when the object is absent.
get ¶
Ranged GET. length < 0 from start reads to EOF; the
whole-object fast path omits the Range header entirely.
put ¶
put(
key: str,
body: bytes,
*,
content_type: "str | None" = None,
if_none_match: bool = False
) -> S3Response
PUT an object.
if_none_match=True sends If-None-Match: * so the PUT only
succeeds if the key does not already exist — S3's atomic
create-if-absent (GA since late 2024). A losing writer gets HTTP 412
PreconditionFailed, which we surface as :class:FileExistsError.
This is what makes a Delta commit JSON race genuinely atomic on
object storage (two writers contending for the same version: exactly
one wins, the other rebases) — the local-FS path uses O_EXCL for
the same guarantee.
delete_batch ¶
Multi-object delete (POST /?delete). Content-MD5 is required by
S3 for this op; DeleteObjects errors are surfaced as one OSError.
put_streamed ¶
Multipart-upload an iterator of byte chunks; returns total bytes.
Each chunk should be >= 5 MiB (the S3 part minimum) except the
last. Aborts the upload on any failure so no orphaned parts linger.