(original) (raw)

changeset: 95184:dcf25060cae8 branch: 2.7 parent: 95177:1c19778123a3 user: Serhiy Storchaka storchaka@gmail.com date: Tue Mar 24 23:23:42 2015 +0200 files: Lib/_pyio.py Lib/test/test_io.py Misc/NEWS Modules/_io/bufferedio.c description: Issue #21802: The reader in BufferedRWPair now is closed even when closing writer failed in BufferedRWPair.close(). diff -r 1c19778123a3 -r dcf25060cae8 Lib/_pyio.py --- a/Lib/_pyio.py Tue Mar 24 22:27:50 2015 +0200 +++ b/Lib/_pyio.py Tue Mar 24 23:23:42 2015 +0200 @@ -1216,8 +1216,10 @@ return self.writer.flush() def close(self): - self.writer.close() - self.reader.close() + try: + self.writer.close() + finally: + self.reader.close() def isatty(self): return self.reader.isatty() or self.writer.isatty() diff -r 1c19778123a3 -r dcf25060cae8 Lib/test/test_io.py --- a/Lib/test/test_io.py Tue Mar 24 22:27:50 2015 +0200 +++ b/Lib/test/test_io.py Tue Mar 24 23:23:42 2015 +0200 @@ -1495,6 +1495,51 @@ pair.close() self.assertTrue(pair.closed) + def test_reader_close_error_on_close(self): + def reader_close(): + reader_non_existing + reader = self.MockRawIO() + reader.close = reader_close + writer = self.MockRawIO() + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('reader_non_existing', str(err.exception)) + self.assertTrue(pair.closed) + self.assertFalse(reader.closed) + self.assertTrue(writer.closed) + + def test_writer_close_error_on_close(self): + def writer_close(): + writer_non_existing + reader = self.MockRawIO() + writer = self.MockRawIO() + writer.close = writer_close + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('writer_non_existing', str(err.exception)) + self.assertFalse(pair.closed) + self.assertTrue(reader.closed) + self.assertFalse(writer.closed) + + def test_reader_writer_close_error_on_close(self): + def reader_close(): + reader_non_existing + def writer_close(): + writer_non_existing + reader = self.MockRawIO() + reader.close = reader_close + writer = self.MockRawIO() + writer.close = writer_close + pair = self.tp(reader, writer) + with self.assertRaises(NameError) as err: + pair.close() + self.assertIn('reader_non_existing', str(err.exception)) + self.assertFalse(pair.closed) + self.assertFalse(reader.closed) + self.assertFalse(writer.closed) + def test_isatty(self): class SelectableIsAtty(MockRawIO): def __init__(self, isatty): diff -r 1c19778123a3 -r dcf25060cae8 Misc/NEWS --- a/Misc/NEWS Tue Mar 24 22:27:50 2015 +0200 +++ b/Misc/NEWS Tue Mar 24 23:23:42 2015 +0200 @@ -21,6 +21,9 @@ Library ------- +- Issue #21802: The reader in BufferedRWPair now is closed even when closing + writer failed in BufferedRWPair.close(). + - Issue #23671: string.Template now allows to specify the "self" parameter as keyword argument. string.Formatter now allows to specify the "self" and the "format_string" parameters as keyword arguments. diff -r 1c19778123a3 -r dcf25060cae8 Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Tue Mar 24 22:27:50 2015 +0200 +++ b/Modules/_io/bufferedio.c Tue Mar 24 23:23:42 2015 +0200 @@ -2200,12 +2200,25 @@ static PyObject * bufferedrwpair_close(rwpair *self, PyObject *args) { + PyObject *exc = NULL, *val, *tb; PyObject *ret = _forward_call(self->writer, "close", args); if (ret == NULL) - return NULL; - Py_DECREF(ret); - - return _forward_call(self->reader, "close", args); + PyErr_Fetch(&exc, &val, &tb); + else + Py_DECREF(ret); + ret = _forward_call(self->reader, "close", args); + if (exc != NULL) { + if (ret != NULL) { + Py_CLEAR(ret); + PyErr_Restore(exc, val, tb); + } + else { + Py_DECREF(exc); + Py_XDECREF(val); + Py_XDECREF(tb); + } + } + return ret; } static PyObject * /storchaka@gmail.com