bpo-35950: Raise UnsupportedOperation in BufferedReader.truncate() (GH-18586)

The truncate() method of io.BufferedReader() should raise
UnsupportedOperation when it is called on a read-only
io.BufferedReader() instance.





https://bugs.python.org/issue35950



Automerge-Triggered-By: @methane
This commit is contained in:
Berker Peksag 2020-02-21 20:57:26 +03:00 committed by GitHub
parent d4d17fd2cf
commit fd5116c0e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 25 additions and 5 deletions

View File

@ -792,6 +792,9 @@ class _BufferedIOMixin(BufferedIOBase):
return pos return pos
def truncate(self, pos=None): def truncate(self, pos=None):
self._checkClosed()
self._checkWritable()
# Flush the stream. We're mixing buffered I/O with lower-level I/O, # Flush the stream. We're mixing buffered I/O with lower-level I/O,
# and a flush may be necessary to synch both views of the current # and a flush may be necessary to synch both views of the current
# file state. # file state.

View File

@ -1528,6 +1528,13 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
self.assertRaises(ValueError, b.peek) self.assertRaises(ValueError, b.peek)
self.assertRaises(ValueError, b.read1, 1) self.assertRaises(ValueError, b.read1, 1)
def test_truncate_on_read_only(self):
rawio = self.MockFileIO(b"abc")
bufio = self.tp(rawio)
self.assertFalse(bufio.writable())
self.assertRaises(self.UnsupportedOperation, bufio.truncate)
self.assertRaises(self.UnsupportedOperation, bufio.truncate, 0)
class CBufferedReaderTest(BufferedReaderTest, SizeofTest): class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
tp = io.BufferedReader tp = io.BufferedReader
@ -2372,6 +2379,10 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
# You can't construct a BufferedRandom over a non-seekable stream. # You can't construct a BufferedRandom over a non-seekable stream.
test_unseekable = None test_unseekable = None
# writable() returns True, so there's no point to test it over
# a writable stream.
test_truncate_on_read_only = None
class CBufferedRandomTest(BufferedRandomTest, SizeofTest): class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
tp = io.BufferedRandom tp = io.BufferedRandom

View File

@ -0,0 +1,2 @@
Raise :exc:`io.UnsupportedOperation` in :meth:`io.BufferedReader.truncate`
when it is called on a read-only :class:`io.BufferedReader` instance.

View File

@ -1315,15 +1315,19 @@ _io__Buffered_truncate_impl(buffered *self, PyObject *pos)
PyObject *res = NULL; PyObject *res = NULL;
CHECK_INITIALIZED(self) CHECK_INITIALIZED(self)
CHECK_CLOSED(self, "truncate of closed file")
if (!self->writable) {
return bufferediobase_unsupported("truncate");
}
if (!ENTER_BUFFERED(self)) if (!ENTER_BUFFERED(self))
return NULL; return NULL;
if (self->writable) { res = buffered_flush_and_rewind_unlocked(self);
res = buffered_flush_and_rewind_unlocked(self); if (res == NULL) {
if (res == NULL) goto end;
goto end;
Py_CLEAR(res);
} }
Py_CLEAR(res);
res = PyObject_CallMethodOneArg(self->raw, _PyIO_str_truncate, pos); res = PyObject_CallMethodOneArg(self->raw, _PyIO_str_truncate, pos);
if (res == NULL) if (res == NULL)
goto end; goto end;