summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2014-06-09 06:13:04 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2014-06-09 06:13:04 (GMT)
commit8a8f7f983099f172d1f7c25d4fd99f5c0eb14072 (patch)
treeece2ee26d3edfee06c27e325f7aff80cf9c2adfb
parentb1f59cecc97000396604a3852804932512598938 (diff)
downloadcpython-8a8f7f983099f172d1f7c25d4fd99f5c0eb14072.zip
cpython-8a8f7f983099f172d1f7c25d4fd99f5c0eb14072.tar.gz
cpython-8a8f7f983099f172d1f7c25d4fd99f5c0eb14072.tar.bz2
Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
-rw-r--r--Lib/test/test_io.py51
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/_io/bufferedio.c1
-rw-r--r--Modules/_io/textio.c1
4 files changed, 55 insertions, 0 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index ef1e056..a94b85a 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -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()
diff --git a/Misc/NEWS b/Misc/NEWS
index 6979b2f..6185590 100644
--- 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.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 7494646..d0e92e5 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -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);
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index ba5789d..55392b4 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -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);