Issue #13444: When stdout has been closed explicitly, we should not attempt to flush it at shutdown and print an error.

This also adds a test for issue #5319, whose resolution introduced the issue.
This commit is contained in:
Antoine Pitrou 2011-11-26 22:02:29 +01:00
commit 5604ef3e36
3 changed files with 40 additions and 2 deletions

View file

@ -266,6 +266,25 @@ class CmdLineTest(unittest.TestCase):
self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError') self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError')
self.assertEqual(b'', out) self.assertEqual(b'', out)
def test_stdout_flush_at_shutdown(self):
# Issue #5319: if stdout.flush() fails at shutdown, an error should
# be printed out.
code = """if 1:
import os, sys
sys.stdout.write('x')
os.close(sys.stdout.fileno())"""
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(b'', out)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception OSError: .* ignored')
def test_closed_stdout(self):
# Issue #13444: if stdout has been explicitly closed, we should
# not attempt to flush it at shutdown.
code = "import sys; sys.stdout.close()"
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(b'', err)
def test_main(): def test_main():
test.support.run_unittest(CmdLineTest) test.support.run_unittest(CmdLineTest)

View file

@ -395,6 +395,9 @@ Core and Builtins
Library Library
------- -------
- Issue #13444: When stdout has been closed explicitly, we should not attempt
to flush it at shutdown and print an error.
- Issue #12567: The curses module uses Unicode functions for Unicode arguments - Issue #12567: The curses module uses Unicode functions for Unicode arguments
when it is linked to the ncurses library. It encodes also Unicode strings to when it is linked to the ncurses library. It encodes also Unicode strings to
the locale encoding instead of UTF-8. the locale encoding instead of UTF-8.

View file

@ -348,6 +348,22 @@ extern void dump_counts(FILE*);
/* Flush stdout and stderr */ /* Flush stdout and stderr */
static int
file_is_closed(PyObject *fobj)
{
int r;
PyObject *tmp = PyObject_GetAttrString(fobj, "closed");
if (tmp == NULL) {
PyErr_Clear();
return 0;
}
r = PyObject_IsTrue(tmp);
Py_DECREF(tmp);
if (r < 0)
PyErr_Clear();
return r > 0;
}
static void static void
flush_std_files(void) flush_std_files(void)
{ {
@ -356,7 +372,7 @@ flush_std_files(void)
PyObject *tmp; PyObject *tmp;
_Py_IDENTIFIER(flush); _Py_IDENTIFIER(flush);
if (fout != NULL && fout != Py_None) { if (fout != NULL && fout != Py_None && !file_is_closed(fout)) {
tmp = _PyObject_CallMethodId(fout, &PyId_flush, ""); tmp = _PyObject_CallMethodId(fout, &PyId_flush, "");
if (tmp == NULL) if (tmp == NULL)
PyErr_WriteUnraisable(fout); PyErr_WriteUnraisable(fout);
@ -364,7 +380,7 @@ flush_std_files(void)
Py_DECREF(tmp); Py_DECREF(tmp);
} }
if (ferr != NULL && ferr != Py_None) { if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) {
tmp = _PyObject_CallMethodId(ferr, &PyId_flush, ""); tmp = _PyObject_CallMethodId(ferr, &PyId_flush, "");
if (tmp == NULL) if (tmp == NULL)
PyErr_Clear(); PyErr_Clear();