Skip to content

Commit 2dc9f61

Browse files
committed
feat: implement "append_from_file"
1 parent df42160 commit 2dc9f61

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

google/cloud/storage/_experimental/asyncio/async_appendable_object_writer.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,16 @@ async def append_from_stream(self, stream_obj):
339339
"""
340340
raise NotImplementedError("append_from_stream is not implemented yet.")
341341

342-
async def append_from_file(self, file_path: str):
343-
"""Create a file object from `file_path` and call append_from_stream(file_obj)"""
344-
raise NotImplementedError("append_from_file is not implemented yet.")
342+
async def append_from_file(
343+
self, file_obj: BufferedReader, block_size: int = _DEFAULT_FLUSH_INTERVAL_BYTES
344+
):
345+
"""
346+
Appends data to an Appendable Object using file_handle which is opened
347+
for reading in binary mode.
348+
349+
:type file_obj: file
350+
:param file_obj: A file handle opened in binary mode for reading.
351+
352+
"""
353+
while block := file_obj.read(block_size):
354+
await self.append(block)

tests/unit/asyncio/test_async_appendable_object_writer.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from io import BytesIO
1516
import pytest
1617
from unittest import mock
1718

@@ -21,6 +22,7 @@
2122
)
2223
from google.cloud.storage._experimental.asyncio.async_appendable_object_writer import (
2324
_MAX_CHUNK_SIZE_BYTES,
25+
_DEFAULT_FLUSH_INTERVAL_BYTES,
2426
)
2527
from google.cloud import _storage_v2
2628

@@ -285,9 +287,6 @@ async def test_unimplemented_methods_raise_error(mock_client):
285287
with pytest.raises(NotImplementedError):
286288
await writer.append_from_stream(mock.Mock())
287289

288-
with pytest.raises(NotImplementedError):
289-
await writer.append_from_file("file.txt")
290-
291290

292291
@pytest.mark.asyncio
293292
@mock.patch(
@@ -529,9 +528,6 @@ async def test_append_flushes_when_buffer_is_full(
529528
mock_write_object_stream, mock_client
530529
):
531530
"""Test that append flushes the stream when the buffer size is reached."""
532-
from google.cloud.storage._experimental.asyncio.async_appendable_object_writer import (
533-
_DEFAULT_FLUSH_INTERVAL_BYTES,
534-
)
535531

536532
writer = AsyncAppendableObjectWriter(mock_client, BUCKET, OBJECT)
537533
writer._is_stream_open = True
@@ -595,3 +591,29 @@ async def test_append_data_two_times(mock_write_object_stream, mock_client):
595591
total_data_length = len(data1) + len(data2)
596592
assert writer.offset == total_data_length
597593
assert writer.simple_flush.await_count == 0
594+
595+
596+
@pytest.mark.asyncio
597+
@pytest.mark.parametrize(
598+
"file_size, block_size",
599+
[
600+
(10, 4 * 1024),
601+
(20 * 1024 * 1024, _DEFAULT_FLUSH_INTERVAL_BYTES),
602+
(16 * 1024 * 1024, _DEFAULT_FLUSH_INTERVAL_BYTES),
603+
],
604+
)
605+
async def test_append_from_file(file_size, block_size, mock_client):
606+
# arrange
607+
fp = BytesIO(b"a" * file_size)
608+
writer = AsyncAppendableObjectWriter(mock_client, BUCKET, OBJECT)
609+
writer._is_stream_open = True
610+
writer.append = mock.AsyncMock()
611+
612+
# act
613+
await writer.append_from_file(fp, block_size=block_size)
614+
615+
# assert
616+
if file_size % block_size == 0:
617+
writer.append.await_count == file_size // block_size
618+
else:
619+
writer.append.await_count == file_size // block_size + 1

0 commit comments

Comments
 (0)