From 0a09b564251e81815b135ebabb216a0dfb3e5d60 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 8 Jul 2026 09:42:05 +0000 Subject: [PATCH] =?UTF-8?q?Read=20document=20bytes=20from=20an=20arbitrary?= =?UTF-8?q?=20source=20bucket=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- infrastructure/s3/s3_document_bytes_reader.py | 19 ++++++++++++ .../test_s3_document_bytes_reader.py | 29 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 infrastructure/s3/s3_document_bytes_reader.py create mode 100644 tests/infrastructure/test_s3_document_bytes_reader.py diff --git a/infrastructure/s3/s3_document_bytes_reader.py b/infrastructure/s3/s3_document_bytes_reader.py new file mode 100644 index 000000000..930377740 --- /dev/null +++ b/infrastructure/s3/s3_document_bytes_reader.py @@ -0,0 +1,19 @@ +"""Reads document bytes from arbitrary S3 buckets (ADR-0060). + +Uploaded files live across many source buckets (each `uploaded_files` row +carries its own `s3_file_bucket`), so — unlike the bucket-bound `S3Client` — +this reader takes the bucket per call. Used by the Bulk Document Download +orchestrator to stream each chosen file into the ZIP. +""" + +from __future__ import annotations + +from typing import Any + + +class S3DocumentBytesReader: + def __init__(self, boto_s3_client: Any) -> None: + self._client = boto_s3_client + + def read(self, bucket: str, key: str) -> bytes: + raise NotImplementedError diff --git a/tests/infrastructure/test_s3_document_bytes_reader.py b/tests/infrastructure/test_s3_document_bytes_reader.py new file mode 100644 index 000000000..8bbcea895 --- /dev/null +++ b/tests/infrastructure/test_s3_document_bytes_reader.py @@ -0,0 +1,29 @@ +"""The multi-bucket document reader (ADR-0060) — reads object bytes from +whichever source bucket an uploaded file lives in.""" + +from collections.abc import Iterator + +import pytest +from moto import mock_aws + +from infrastructure.s3.s3_document_bytes_reader import S3DocumentBytesReader +from tests.infrastructure import make_boto_client + + +@pytest.fixture +def reader() -> Iterator[S3DocumentBytesReader]: + with mock_aws(): + boto_client = make_boto_client("s3") + boto_client.create_bucket(Bucket="src-a") + boto_client.create_bucket(Bucket="src-b") + boto_client.put_object(Bucket="src-a", Key="surveys/one.pdf", Body=b"AAA") + boto_client.put_object(Bucket="src-b", Key="photos/two.zip", Body=b"BBB") + yield S3DocumentBytesReader(boto_client) + + +def test_reads_bytes_from_the_named_source_bucket( + reader: S3DocumentBytesReader, +) -> None: + # act / assert — each object is read from its own bucket. + assert reader.read("src-a", "surveys/one.pdf") == b"AAA" + assert reader.read("src-b", "photos/two.zip") == b"BBB"