From 00390bc2360f82cc245afd93f198eb1ac58f5527 Mon Sep 17 00:00:00 2001 From: mibe Date: Mon, 5 Jan 2026 09:39:37 +0000 Subject: [PATCH 1/3] #262: Fixed a wrong type interpretation in `path.write` --- doc/changes/unreleased.md | 4 ++++ exasol/bucketfs/_path.py | 13 ++++++------- test/integration/test_path.py | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 88d02ee7..a14290ed 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -1,5 +1,9 @@ # Unreleased +## Bug Fixing + +* #262: Fixed a wrong type interpretation in `path.write`. The chunks are now passed as a Sequence, not Iterable. + ## Internal * #260: Re-locked transitive dependencies urllib3, filelock, and Werkzeug and update to exasol-toolbox 4.0.0 \ No newline at end of file diff --git a/exasol/bucketfs/_path.py b/exasol/bucketfs/_path.py index 5af0e8e5..9652eceb 100644 --- a/exasol/bucketfs/_path.py +++ b/exasol/bucketfs/_path.py @@ -6,6 +6,7 @@ ByteString, Generator, Iterable, + Sequence, ) from enum import ( Enum, @@ -115,7 +116,7 @@ def read(self, chunk_size: int = 8192) -> Iterable[ByteString]: IsADirectoryError: if the pathlike object points to a directory. """ - def write(self, data: ByteString | BinaryIO | Iterable[ByteString]) -> None: + def write(self, data: ByteString | BinaryIO | Sequence[ByteString]) -> None: """ Writes data to this path. @@ -353,12 +354,10 @@ def is_file(self) -> bool: def read(self, chunk_size: int = 8192) -> Iterable[ByteString]: return self._bucket_api.download(str(self._path), chunk_size) - def write(self, data: ByteString | BinaryIO | Iterable[ByteString]) -> None: - if ( - not isinstance(data, IOBase) - and isinstance(data, Iterable) - and all(isinstance(chunk, ByteString) for chunk in data) - ): + def write(self, data: ByteString | BinaryIO | Sequence[ByteString]) -> None: + if isinstance(data, Sequence): + if not all(isinstance(chunk, ByteString) for chunk in data): + raise ValueError("The file chunks must be byte strings") data = b"".join(data) self._bucket_api.upload(str(self._path), data) diff --git a/test/integration/test_path.py b/test/integration/test_path.py index 3aa9e621..8f358827 100644 --- a/test/integration/test_path.py +++ b/test/integration/test_path.py @@ -54,6 +54,27 @@ def test_write_read_back(backend_aware_bucketfs_params, children_poem): assert data_back == children_poem +def test_write_chunks_read_back(backend_aware_bucketfs_params, children_poem, classic_poem): + + base_path = bfs.path.build_path(**backend_aware_bucketfs_params) + file_name = "test_bucket_path/test_write_read_back/two_poems.txt" + poem_path = base_path / file_name + + poem_path.write([children_poem, classic_poem]) + data_back = b"".join(poem_path.read(20)) + assert data_back == children_poem + classic_poem + + +def test_write_chunks_error(backend_aware_bucketfs_params): + + base_path = bfs.path.build_path(**backend_aware_bucketfs_params) + file_name = "test_bucket_path/test_write_read_back/data_error.txt" + file_path = base_path / file_name + + with pytest.raises(ValueError, match='byte strings'): + file_path.write([b"part1", "part2"]) + + def test_write_read_back_tar_gz(backend_aware_bucketfs_params, children_poem, tmp_path): # Write the content into a tar.gz file From 4711d11f2a02f0c474ccf8fc07f5e62e81e1d2eb Mon Sep 17 00:00:00 2001 From: mibe Date: Mon, 5 Jan 2026 09:43:49 +0000 Subject: [PATCH 2/3] #262: Fixed formatting --- exasol/bucketfs/_path.py | 1 - test/integration/test_path.py | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/exasol/bucketfs/_path.py b/exasol/bucketfs/_path.py index 9652eceb..711699f3 100644 --- a/exasol/bucketfs/_path.py +++ b/exasol/bucketfs/_path.py @@ -12,7 +12,6 @@ Enum, auto, ) -from io import IOBase from pathlib import ( PurePath, PureWindowsPath, diff --git a/test/integration/test_path.py b/test/integration/test_path.py index 8f358827..23a1d5d6 100644 --- a/test/integration/test_path.py +++ b/test/integration/test_path.py @@ -54,7 +54,9 @@ def test_write_read_back(backend_aware_bucketfs_params, children_poem): assert data_back == children_poem -def test_write_chunks_read_back(backend_aware_bucketfs_params, children_poem, classic_poem): +def test_write_chunks_read_back( + backend_aware_bucketfs_params, children_poem, classic_poem +): base_path = bfs.path.build_path(**backend_aware_bucketfs_params) file_name = "test_bucket_path/test_write_read_back/two_poems.txt" @@ -71,7 +73,7 @@ def test_write_chunks_error(backend_aware_bucketfs_params): file_name = "test_bucket_path/test_write_read_back/data_error.txt" file_path = base_path / file_name - with pytest.raises(ValueError, match='byte strings'): + with pytest.raises(ValueError, match="byte strings"): file_path.write([b"part1", "part2"]) From 3191dc26e595b8a0b58aa040c6a10cedd64fc45c Mon Sep 17 00:00:00 2001 From: mibe Date: Mon, 5 Jan 2026 10:17:19 +0000 Subject: [PATCH 3/3] #262: Fixed type checking --- exasol/bucketfs/_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/bucketfs/_path.py b/exasol/bucketfs/_path.py index 711699f3..3fca590f 100644 --- a/exasol/bucketfs/_path.py +++ b/exasol/bucketfs/_path.py @@ -354,7 +354,7 @@ def read(self, chunk_size: int = 8192) -> Iterable[ByteString]: return self._bucket_api.download(str(self._path), chunk_size) def write(self, data: ByteString | BinaryIO | Sequence[ByteString]) -> None: - if isinstance(data, Sequence): + if (not isinstance(data, ByteString)) and isinstance(data, Sequence): if not all(isinstance(chunk, ByteString) for chunk in data): raise ValueError("The file chunks must be byte strings") data = b"".join(data)