]> granicus.if.org Git - python/commitdiff
Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 9 Jun 2014 06:13:04 +0000 (09:13 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Mon, 9 Jun 2014 06:13:04 +0000 (09:13 +0300)
Lib/test/test_io.py
Misc/NEWS
Modules/_io/bufferedio.c
Modules/_io/textio.c

index ef1e05622bb95c4854290b3121a268d1f95e80d3..a94b85aae3c4f9c57ae10aeda423a06d7b34c039 100644 (file)
@@ -792,9 +792,27 @@ class CommonBufferedTests:
         with self.assertRaises(OSError) as err: # exception not swallowed
             b.close()
         self.assertEqual(err.exception.args, ('close',))
+        self.assertIsInstance(err.exception.__context__, OSError)
         self.assertEqual(err.exception.__context__.args, ('flush',))
         self.assertFalse(b.closed)
 
+    def test_nonnormalized_close_error_on_close(self):
+        # Issue #21677
+        raw = self.MockRawIO()
+        def bad_flush():
+            raise non_existing_flush
+        def bad_close():
+            raise non_existing_close
+        raw.close = bad_close
+        b = self.tp(raw)
+        b.flush = bad_flush
+        with self.assertRaises(NameError) as err: # exception not swallowed
+            b.close()
+        self.assertIn('non_existing_close', str(err.exception))
+        self.assertIsInstance(err.exception.__context__, NameError)
+        self.assertIn('non_existing_flush', str(err.exception.__context__))
+        self.assertFalse(b.closed)
+
     def test_multi_close(self):
         raw = self.MockRawIO()
         b = self.tp(raw)
@@ -2576,6 +2594,39 @@ class TextIOWrapperTest(unittest.TestCase):
         self.assertRaises(OSError, txt.close) # exception not swallowed
         self.assertTrue(txt.closed)
 
+    def test_close_error_on_close(self):
+        buffer = self.BytesIO(self.testdata)
+        def bad_flush():
+            raise OSError('flush')
+        def bad_close():
+            raise OSError('close')
+        buffer.close = bad_close
+        txt = self.TextIOWrapper(buffer, encoding="ascii")
+        txt.flush = bad_flush
+        with self.assertRaises(OSError) as err: # exception not swallowed
+            txt.close()
+        self.assertEqual(err.exception.args, ('close',))
+        self.assertIsInstance(err.exception.__context__, OSError)
+        self.assertEqual(err.exception.__context__.args, ('flush',))
+        self.assertFalse(txt.closed)
+
+    def test_nonnormalized_close_error_on_close(self):
+        # Issue #21677
+        buffer = self.BytesIO(self.testdata)
+        def bad_flush():
+            raise non_existing_flush
+        def bad_close():
+            raise non_existing_close
+        buffer.close = bad_close
+        txt = self.TextIOWrapper(buffer, encoding="ascii")
+        txt.flush = bad_flush
+        with self.assertRaises(NameError) as err: # exception not swallowed
+            txt.close()
+        self.assertIn('non_existing_close', str(err.exception))
+        self.assertIsInstance(err.exception.__context__, NameError)
+        self.assertIn('non_existing_flush', str(err.exception.__context__))
+        self.assertFalse(txt.closed)
+
     def test_multi_close(self):
         txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii")
         txt.close()
index 6979b2f107cd16e84938756680f79a890926b71e..6185590dacfaf671c4c38daceadf75fb6c4a54dc 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -22,6 +22,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
+
 - Issue #11709: Fix the pydoc.help function to not fail when sys.stdin is not a
   valid file.
 
index 7494646342ee642cc8a5fe6edc64cdad45680ba9..d0e92e5f7f129f9fcb4520e965701eb8ba25589e 100644 (file)
@@ -549,6 +549,7 @@ buffered_close(buffered *self, PyObject *args)
         }
         else {
             PyObject *val2;
+            PyErr_NormalizeException(&exc, &val, &tb);
             Py_DECREF(exc);
             Py_XDECREF(tb);
             PyErr_Fetch(&exc, &val2, &tb);
index ba5789d3c73b09d49f571c507afdf843420fbc55..55392b435f283a688ee43cb6cd21d1fcda5a5f98 100644 (file)
@@ -2614,6 +2614,7 @@ textiowrapper_close(textio *self, PyObject *args)
             }
             else {
                 PyObject *val2;
+                PyErr_NormalizeException(&exc, &val, &tb);
                 Py_DECREF(exc);
                 Py_XDECREF(tb);
                 PyErr_Fetch(&exc, &val2, &tb);