Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (révision 67973) +++ Python/pythonrun.c (copie de travail) @@ -84,6 +84,7 @@ int Py_FrozenFlag; /* Needed by getpath.c */ int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ +int Py_UnbufferedStdoutFlag = 0; /* Unbuffered binary std{out,err} */ /* PyModule_GetWarningsModule is no longer necessary as of 2.6 since _warnings is builtin. This API should not be used. */ @@ -259,7 +260,7 @@ if (install_sigs) initsigs(); /* Signal handling stuff, including initintr() */ - + /* Initialize warnings. */ _PyWarnings_Init(); if (PySys_HasWarnOptions()) { @@ -724,6 +725,49 @@ } } +static PyObject* +create_stdio(int fd, char* name, char* encoding, char* errors) +{ + PyObject *io = NULL, *buf = NULL, *stream = NULL, *mode = NULL; + + if (!Py_UnbufferedStdoutFlag) { + return PyFile_FromFd(fd, name, "w", + -1, + encoding, errors, "\n", 0); + } + + io = PyImport_ImportModule("io"); + if (io == NULL) + goto error; + + buf = PyObject_CallMethod(io, "open", "isiOOOi", + fd, "wb", 0, + Py_None, Py_None, Py_None, 0); + if (buf == NULL) + goto error; + + stream = PyObject_CallMethod(io, "TextIOWrapper", "OsssO", + buf, encoding, errors, + "\n", Py_True); + Py_CLEAR(io); + Py_CLEAR(buf); + if (stream == NULL) + goto error; + + mode = PyUnicode_FromString("w"); + if (!mode || PyObject_SetAttrString(stream, "mode", mode) < 0) + goto error; + Py_CLEAR(mode); + return stream; + +error: + Py_XDECREF(io); + Py_XDECREF(buf); + Py_XDECREF(stream); + Py_XDECREF(mode); + return NULL; +} + /* Initialize sys.stdin, stdout, stderr and builtins.open */ static int initstdio(void) @@ -790,7 +834,7 @@ #endif } else { - if (!(std = PyFile_FromFd(fd, "", "r", -1, encoding, + if (!(std = PyFile_FromFd(fd, "", "r", -1, encoding, errors, "\n", 0))) { goto error; } @@ -810,8 +854,7 @@ #endif } else { - if (!(std = PyFile_FromFd(fd, "", "w", -1, encoding, - errors, "\n", 0))) { + if (!(std = create_stdio(fd, "", encoding, errors))) { goto error; } } /* if (fd < 0) */ @@ -831,8 +874,7 @@ #endif } else { - if (!(std = PyFile_FromFd(fd, "", "w", -1, encoding, - "backslashreplace", "\n", 0))) { + if (!(std = create_stdio(fd, "", encoding, "backslashreplace"))) { goto error; } } /* if (fd < 0) */ @@ -2036,7 +2078,7 @@ alloca(PYOS_STACK_MARGIN * sizeof(void*)); return 0; } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? - EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { int errcode = _resetstkoflw(); if (errcode == 0) Index: Include/pydebug.h =================================================================== --- Include/pydebug.h (révision 67973) +++ Include/pydebug.h (copie de travail) @@ -18,6 +18,7 @@ PyAPI_DATA(int) Py_DivisionWarningFlag; PyAPI_DATA(int) Py_DontWriteBytecodeFlag; PyAPI_DATA(int) Py_NoUserSiteDirectory; +PyAPI_DATA(int) Py_UnbufferedStdoutFlag; /* this is a wrapper around getenv() that pays attention to Py_IgnoreEnvironmentFlag. It should be used for getting variables like Index: Lib/test/test_cmd_line.py =================================================================== --- Lib/test/test_cmd_line.py (révision 67973) +++ Lib/test/test_cmd_line.py (copie de travail) @@ -142,7 +142,24 @@ self.exit_code('-c', command), 0) + def test_unbuffered(self): + # Test expected operation of the '-u' switch + for stream in ('stdout', 'stderr'): + # Binary is unbuffered + code = ("import os, sys; sys.%s.buffer.write(b'x'); os._exit(0)" + % stream) + data, rc = self.start_python_and_exit_code('-u', '-c', code) + self.assertEqual(rc, 0) + self.assertEqual(data, b'x', "binary %s not unbuffered" % stream) + # Text is line-buffered + code = ("import os, sys; sys.%s.write('x\\n'); os._exit(0)" + % stream) + data, rc = self.start_python_and_exit_code('-u', '-c', code) + self.assertEqual(rc, 0) + self.assertEqual(data.strip(), b'x', + "text %s not line-buffered" % stream) + def test_main(): test.support.run_unittest(CmdLineTest) test.support.reap_children() Index: Modules/main.c =================================================================== --- Modules/main.c (révision 67973) +++ Modules/main.c (copie de travail) @@ -292,7 +292,6 @@ wchar_t *module = NULL; FILE *fp = stdin; char *p; - int unbuffered = 0; int skipfirstline = 0; int stdin_is_interactive = 0; int help = 0; @@ -374,7 +373,7 @@ break; case 'u': - unbuffered++; + Py_UnbufferedStdoutFlag++; saw_unbuffered_flag = 1; break; @@ -423,7 +422,7 @@ Py_InspectFlag = 1; if (!saw_unbuffered_flag && (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') - unbuffered = 1; + Py_UnbufferedStdoutFlag = 1; if (!Py_NoUserSiteDirectory && (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0') @@ -444,7 +443,7 @@ stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0); - if (unbuffered) { + if (Py_UnbufferedStdoutFlag) { #if defined(MS_WINDOWS) || defined(__CYGWIN__) _setmode(fileno(stdin), O_BINARY); _setmode(fileno(stdout), O_BINARY);