diff --git a/b2sdk/_internal/stream/wrapper.py b/b2sdk/_internal/stream/wrapper.py index 1a9dd413..388af583 100644 --- a/b2sdk/_internal/stream/wrapper.py +++ b/b2sdk/_internal/stream/wrapper.py @@ -54,6 +54,10 @@ def flush(self): """ self.stream.flush() + @property + def closed(self): + return self.stream.closed + def readable(self): return self.stream.readable() diff --git a/test/unit/stream/__init__.py b/test/unit/stream/__init__.py new file mode 100644 index 00000000..ba90f642 --- /dev/null +++ b/test/unit/stream/__init__.py @@ -0,0 +1,9 @@ +###################################################################### +# +# File: test/unit/stream/__init__.py +# +# Copyright 2024 Backblaze Inc. All Rights Reserved. +# +# License https://www.backblaze.com/using_b2_code.html +# +###################################################################### diff --git a/test/unit/stream/test_progress.py b/test/unit/stream/test_progress.py new file mode 100644 index 00000000..b4b6c88b --- /dev/null +++ b/test/unit/stream/test_progress.py @@ -0,0 +1,53 @@ +###################################################################### +# +# File: test/unit/stream/test_progress.py +# +# Copyright 2024 Backblaze Inc. All Rights Reserved. +# +# License https://www.backblaze.com/using_b2_code.html +# +###################################################################### +import io +from unittest.mock import Mock + +from apiver_deps import ReadingStreamWithProgress + + +def test_reading_stream_with_progress(tmp_path): + stream = io.BytesIO(b"1234567890") + progress_listener = Mock() + with ReadingStreamWithProgress(stream, progress_listener=progress_listener) as wrapped_stream: + assert wrapped_stream.read(1) == b"1" + assert wrapped_stream.read(2) == b"23" + assert wrapped_stream.read(3) == b"456" + + assert progress_listener.bytes_completed.call_count == 3 + assert wrapped_stream.bytes_completed == 6 + + assert not stream.closed + + +def test_reading_stream_with_progress__not_closing_wrapped_stream(tmp_path): + stream = io.BytesIO(b"1234567890") + progress_listener = Mock() + with ReadingStreamWithProgress(stream, progress_listener=progress_listener) as wrapped_stream: + assert wrapped_stream.read() + + assert not stream.closed + + +def test_reading_stream_with_progress__closed_proxy(tmp_path): + """ + Test that the wrapped stream is closed when the original stream is closed. + + This is important for Python 3.13+ to prevent: + 'Exception ignored in: ' + messages. + """ + stream = io.BytesIO(b"1234567890") + progress_listener = Mock() + wrapped_stream = ReadingStreamWithProgress(stream, progress_listener=progress_listener) + + assert not stream.closed + stream.close() + assert wrapped_stream.closed