diff -r a442bf076a32 Python/pylifecycle.c --- a/Python/pylifecycle.c Fri Apr 01 21:43:54 2016 +0200 +++ b/Python/pylifecycle.c Fri Apr 01 23:02:57 2016 +0200 @@ -508,6 +508,86 @@ flush_std_files(void) return status; } +/* Test if a standard stream is closed or not. + + If the file has no closed attribute (or getting the attribute raises an + exception), consider that the file is already closed (and ignore the + exception). */ +static int +stdio_is_closed(PyObject *file) +{ + PyObject *res; + int closed; + + if (file == NULL || file == Py_None) { + return 1; + } + + res = PyObject_GetAttrString(file, "closed"); + if (res == NULL) { + PyErr_Clear(); + return 1; + } + + closed = PyObject_IsTrue(res); + Py_DECREF(res); + + if (closed < 0) { + PyErr_Clear(); + return 1; + } + + return closed; +} + +static void +stdio_replace_with_printer(int fd, const char *name, const char *dunder_name) +{ + PyObject *file, *dunder_file; + int closed, dunder_closed; + PyObject *std_file; + + file = PySys_GetObject(name); + dunder_file = PySys_GetObject(dunder_name); + + closed = stdio_is_closed(file); + dunder_closed = stdio_is_closed(dunder_file); + if (closed && dunder_closed) { + return; + } + + std_file = PyFile_NewStdPrinter(fd); + if (std_file == NULL) { + PyErr_Clear(); + return; + } + + Py_XINCREF(file); + Py_XINCREF(dunder_file); + + if (!closed) { + PySys_SetObject(name, std_file); + } + if (!dunder_closed) { + PySys_SetObject(dunder_name, std_file); + } + + if (!closed) { + PyObject *res = PyObject_CallMethod(file, "close", ""); + PyErr_Clear(); + Py_XDECREF(res); + } + if (!dunder_closed) { + PyObject *res = PyObject_CallMethod(dunder_file, "close", ""); + PyErr_Clear(); + Py_XDECREF(res); + } + + Py_XDECREF(file); + Py_XDECREF(dunder_file); + Py_DECREF(std_file); +} + /* Undo the effect of Py_Initialize(). Beware: if multiple interpreter and/or thread states exist, these @@ -582,6 +662,13 @@ Py_FinalizeEx(void) while (PyGC_Collect() > 0) /* nothing */; #endif + + /* Replace sys.stderr, sys.__stderr__, sys.stdout and sys.__stdout__ with + new standard printers if they are different than None and are not + closed. */ + stdio_replace_with_printer(fileno(stderr), "stderr", "__stderr__"); + stdio_replace_with_printer(fileno(stdout), "stdout", "__stdout__"); + /* Destroy all modules */ PyImport_Cleanup();