diff -r 5841920d1ef6 Lib/_win_console.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/_win_console.py Wed Oct 19 22:54:50 2011 +0200 @@ -0,0 +1,147 @@ +import ctypes +import io +import sys +from ctypes import WINFUNCTYPE, windll, POINTER, byref +from ctypes.wintypes import BOOL, HANDLE, DWORD, LPCSTR, LPWSTR, LPVOID + +KERNEL32 = windll.kernel32 + +INVALID_HANDLE_VALUE = DWORD(-1).value +STD_OUTPUT_HANDLE = DWORD(-11) +STD_ERROR_HANDLE = DWORD(-12) +FILE_TYPE_CHAR = 0x0002 +FILE_TYPE_REMOTE = 0x8000 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", KERNEL32)) +GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", KERNEL32)) +GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD)) \ + (("GetConsoleMode", KERNEL32)) +WriteConsoleA = WINFUNCTYPE(BOOL, HANDLE, LPCSTR, DWORD, POINTER(DWORD), \ + LPVOID)(("WriteConsoleA", KERNEL32)) +WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), \ + LPVOID)(("WriteConsoleW", KERNEL32)) + +class BytesConsole(io.RawIOBase): + def __init__(self, hConsole, fileno): + self._fileno = fileno + self.softspace = False + self.mode = 'w' + self._hConsole = hConsole + io.RawIOBase.__init__(self) + + def flush(self): + pass + + def isatty(self): + return True + + def fileno(self): + return self._fileno + + def writable(self): + return True + + def write(self, raw): + written = len(raw) + while raw: + # Issue #11395: the Windows console returns an error (12: not + # enough space error) on writing into stdout if stdout mode is + # binary and the length is greater than 66,000 bytes (or less, + # depending on heap usage). + chunk_len = min(len(raw), 32767) + chunk = raw[:chunk_len] + if not isinstance(chunk, bytes): + chunk = bytes(chunk) + + retval = WriteConsoleA(self._hConsole, + chunk, len(chunk), + None, None) + if retval == 0: + raise IOError("WriteConsoleA returned %r" % retval) + raw = raw[len(chunk):] + return written + +class UnicodeConsole(io.TextIOBase): + def __init__(self, buffer, hConsole, fileno): + io.TextIOBase.__init__(self) + self._fileno = fileno + self.softspace = False + self.mode = 'w' + self._hConsole = hConsole + self.buffer = buffer + self.newline = '\r\n' + + def flush(self): + pass + + def isatty(self): + return True + + def fileno(self): + return self._fileno + + def write(self, text): + text = text.replace('\n', self.newline) + while text: + # Issue #11395: the Windows console returns an error (12: not + # enough space error) on writing into stdout if stdout mode is + # binary and the length is greater than 66,000 bytes (or less, + # depending on heap usage). + chunk_len = min(len(text), 32767) + chunk = text[:chunk_len] + + retval = WriteConsoleW(self._hConsole, + chunk, len(chunk), + None, None) + if retval == 0: + raise IOError("WriteConsoleW returned %r" % retval) + text = text[len(chunk):] + +def is_a_console(handle): + if handle == INVALID_HANDLE_VALUE or handle is None: + return False + if (GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR: + return False + mode = DWORD() + if GetConsoleMode(handle, byref(mode)) == 0: + return False + return True + +def install_unicode_console(): + # Make Unicode console output work independently of the current code page. + Py_UnbufferedStdioFlag = False + + real_stdout = False + if sys.stdout.fileno() == STDOUT_FILENO: + hStdout = GetStdHandle(STD_OUTPUT_HANDLE) + if is_a_console(hStdout): + real_stdout = True + + if real_stdout: + sys.stdout.flush() + raw = BytesConsole(hStdout, STDOUT_FILENO) + if not Py_UnbufferedStdioFlag: + buffer = io.BufferedWriter(raw) # use the default buffer size + else: + buffer = raw + textio = UnicodeConsole(buffer, hStdout, STDOUT_FILENO) + sys.stdout = textio + + real_stderr = False + if sys.stderr.fileno() == STDERR_FILENO: + hStderr = GetStdHandle(STD_ERROR_HANDLE) + if is_a_console(hStderr): + real_stderr = True + + if real_stderr: + sys.stderr.flush() + raw = BytesConsole(hStderr, STDERR_FILENO) + if not Py_UnbufferedStdioFlag: + buffer = io.BufferedWriter(raw) # use the default buffer size + else: + buffer = raw + textio = UnicodeConsole(buffer, hStderr, STDERR_FILENO) + sys.stderr = textio + diff -r 5841920d1ef6 Lib/site.py --- a/Lib/site.py Tue Oct 18 21:46:37 2011 +0200 +++ b/Lib/site.py Wed Oct 19 22:54:50 2011 +0200 @@ -530,6 +530,9 @@ execsitecustomize() if ENABLE_USER_SITE: execusercustomize() + if sys.platform == 'win32': + from _win_console import install_unicode_console + install_unicode_console() # Prevent edition of sys.path when python was started with -S and # site is imported later. diff -r 5841920d1ef6 Modules/_io/fileio.c --- a/Modules/_io/fileio.c Tue Oct 18 21:46:37 2011 +0200 +++ b/Modules/_io/fileio.c Wed Oct 19 22:54:50 2011 +0200 @@ -741,14 +741,7 @@ errno = 0; len = pbuf.len; #if defined(MS_WIN64) || defined(MS_WINDOWS) - if (len > 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } - else if (len > INT_MAX) + if (len > INT_MAX) len = INT_MAX; n = write(self->fd, pbuf.buf, (int)len); #else