summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2015-03-24 21:23:28 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2015-03-24 21:23:28 (GMT)
commit8be6be427d7af54cd2dcc5f7c8f73ec2a1e2dfcc (patch)
tree8ad1b6881ee6f462f15143f863c09243fc199888
parenta54aae068325551bcc70c151b483f1b38ca0c687 (diff)
parent7665be6087d879a96c4238684b2dfc642c67e60c (diff)
downloadcpython-8be6be427d7af54cd2dcc5f7c8f73ec2a1e2dfcc.zip
cpython-8be6be427d7af54cd2dcc5f7c8f73ec2a1e2dfcc.tar.gz
cpython-8be6be427d7af54cd2dcc5f7c8f73ec2a1e2dfcc.tar.bz2
Issue #21802: The reader in BufferedRWPair now is closed even when closing
writer failed in BufferedRWPair.close().
-rw-r--r--Lib/_pyio.py6
-rw-r--r--Lib/test/test_io.py47
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_io/bufferedio.c14
4 files changed, 64 insertions, 6 deletions
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index f1611a4..1df44cc 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -1291,8 +1291,10 @@ class BufferedRWPair(BufferedIOBase):
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 --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index e5c6073..6a41ae6 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1649,6 +1649,53 @@ class BufferedRWPairTest(unittest.TestCase):
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.assertIsInstance(err.exception.__context__, NameError)
+ self.assertIn('writer_non_existing', str(err.exception.__context__))
+ self.assertFalse(pair.closed)
+ self.assertFalse(reader.closed)
+ self.assertFalse(writer.closed)
+
def test_isatty(self):
class SelectableIsAtty(MockRawIO):
def __init__(self, isatty):
diff --git a/Misc/NEWS b/Misc/NEWS
index c148998..b85eeaf 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,9 @@ Core and Builtins
Library
-------
+- Issue #21802: The reader in BufferedRWPair now is closed even when closing
+ writer failed in BufferedRWPair.close().
+
- Issue #23622: Unknown escapes in regular expressions that consist of ``'\'``
and ASCII letter now raise a deprecation warning and will be forbidden in
Python 3.6.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 358a94d..ea9f533 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -2413,12 +2413,18 @@ bufferedrwpair_writable(rwpair *self, PyObject *args)
static PyObject *
bufferedrwpair_close(rwpair *self, PyObject *args)
{
+ PyObject *exc = NULL, *val, *tb;
PyObject *ret = _forward_call(self->writer, &PyId_close, args);
if (ret == NULL)
- return NULL;
- Py_DECREF(ret);
-
- return _forward_call(self->reader, &PyId_close, args);
+ PyErr_Fetch(&exc, &val, &tb);
+ else
+ Py_DECREF(ret);
+ ret = _forward_call(self->reader, &PyId_close, args);
+ if (exc != NULL) {
+ _PyErr_ChainExceptions(exc, val, tb);
+ Py_CLEAR(ret);
+ }
+ return ret;
}
static PyObject *