]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #21802: The reader in BufferedRWPair now is closed even when closing
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 24 Mar 2015 21:23:42 +0000 (23:23 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 24 Mar 2015 21:23:42 +0000 (23:23 +0200)
writer failed in BufferedRWPair.close().

Lib/_pyio.py
Lib/test/test_io.py
Misc/NEWS
Modules/_io/bufferedio.c

index 98091eb47b63e2f63fa5ada90b7d1ab20043761d..a7f4301cc1d69695830a46da35114f53ff673ded 100644 (file)
@@ -1216,8 +1216,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()
index baa6965c4a2fa28bdc38aeee74014d4785622009..a361e4c64e9538af59bd044a528462a0f5e73cb1 100644 (file)
@@ -1495,6 +1495,51 @@ 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.assertFalse(pair.closed)
+        self.assertFalse(reader.closed)
+        self.assertFalse(writer.closed)
+
     def test_isatty(self):
         class SelectableIsAtty(MockRawIO):
             def __init__(self, isatty):
index 56eb793c2e2692c081210ef4756f6d84e011fde3..60ad651dc3a3b507c70dddd267375bde9b635dea 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,9 @@ Core and Builtins
 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.
index 28c467865a36ff277e229e461679c8a7ac9e9882..f146958b804b6d8eeaffe75d4e9e335d2dd17eb0 100644 (file)
@@ -2200,12 +2200,25 @@ 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, "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 *