Skip to content
Snippets Groups Projects
Commit f6bf3788 authored by paulavidas's avatar paulavidas Committed by Copybara-Service
Browse files

Return number of bytes written in case of BlockingIOError.

In case of a partial write BufferedIOBase doesn't return the length of data written, but gives a BlockingIOError that contains the number of characters written.
See https://docs.python.org/3/library/io.html#io.BufferedIOBase.write

Also, RawIOBase returns None (and not 0) when no data can be written.

PiperOrigin-RevId: 268167212
parent 3404474d
No related branches found
No related tags found
No related merge requests found
......@@ -20,6 +20,8 @@ from __future__ import division
from __future__ import google_type_annotations
from __future__ import print_function
import io
from tink.python.cc.clif import simple_output_stream
......@@ -35,7 +37,11 @@ class FileObjectAdapter(simple_output_stream.SimpleOutputStream):
def write(self, data: bytes) -> int:
"""Writes to underlying file object and returns number of bytes written."""
return self._file_object.write(data)
try:
written = self._file_object.write(data)
return 0 if written is None else written
except io.BlockingIOError as e:
return e.characters_written
def close(self) -> None:
self._file_object.close()
......
......@@ -18,6 +18,7 @@ from __future__ import print_function
import io
from absl.testing import absltest
import mock
from tink.python.util import file_object_adapter
......@@ -57,41 +58,35 @@ class FileObjectAdapterTest(absltest.TestCase):
adapter.close()
def test_non_writable(self):
file_object = mock.Mock()
file_object.writable = mock.Mock(return_value=False)
class TestNonWritableObject(io.RawIOBase):
"""Test non-writable file-like object."""
def writable(self):
return False
non_writable_object = TestNonWritableObject()
self.assertRaises(TypeError, file_object_adapter.FileObjectAdapter,
non_writable_object)
file_object)
def test_partial_write(self):
def test_write_returns_none(self):
file_object = mock.Mock()
file_object.writable = mock.Mock(return_value=True)
file_object.write = mock.Mock(return_value=None)
class TestFileObject(io.RawIOBase):
"""Test file-like object that always writes only first 5 bytes of data."""
def __init__(self):
super(TestFileObject, self).__init__()
self.value = b''
adapter = file_object_adapter.FileObjectAdapter(file_object)
self.assertEqual(0, adapter.write(b'something'))
def writable(self):
return True
def test_write_raises_blocking_error(self):
file_object = mock.Mock()
file_object.writable = mock.Mock(return_value=True)
file_object.write = mock.Mock(side_effect=io.BlockingIOError(None, None, 5))
def write(self, data):
self.value += data[:5]
return 5
adapter = file_object_adapter.FileObjectAdapter(file_object)
self.assertEqual(5, adapter.write(b'something'))
def tell(self):
return len(self.value)
def test_partial_write(self):
file_object = mock.Mock()
file_object.writable = mock.Mock(return_value=True)
file_object.write = mock.Mock(wraps=lambda data: len(data) - 1)
file_object = TestFileObject()
adapter = file_object_adapter.FileObjectAdapter(file_object)
self.assertEqual(5, adapter.write(b'something'))
self.assertEqual(5, adapter.position())
self.assertEqual(b'somet', file_object.value)
self.assertEqual(8, adapter.write(b'something'))
if __name__ == '__main__':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment