jenkins-bot has submitted this change and it was merged.
Change subject: [FIX] Win32 UI: Ignore fileno if not supported ......................................................................
[FIX] Win32 UI: Ignore fileno if not supported
On some environments, like IDLE, getting the fileno of a std stream raises an UnsupportedOperation error.
Backport from core dd808ca6e0a5eaa25c10316041aa2f975a94df5a
Change-Id: I1557fe83ffb06c2702042ab4d68af04a0398781b Signed-off-by: xqt info@gno.de Bug: T99368 --- M userinterfaces/win32_unicode.py 1 file changed, 68 insertions(+), 56 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/userinterfaces/win32_unicode.py b/userinterfaces/win32_unicode.py index ae00ef6..65027b2 100644 --- a/userinterfaces/win32_unicode.py +++ b/userinterfaces/win32_unicode.py @@ -1,25 +1,25 @@ -# Stdout, stderr and argv support: +"""Stdout, stderr and argv support for unicode.""" ############################################## # Support for unicode in windows cmd.exe -# Posted on Stack Overflow [1], available under CC-BY-SA [2] -# +# Posted on Stack Overflow [1], available under CC-BY-SA 3.0 [2] +# # Question: "Windows cmd encoding change causes Python crash" [3] by Alex [4], # Answered [5] by David-Sarah Hopwood [6]. # -# [1] http://stackoverflow.com -# [2] http://creativecommons.org/licenses/by-sa/3.0/ -# [3] http://stackoverflow.com/questions/878972 -# [4] http://stackoverflow.com/users/85185 -# [4] http://stackoverflow.com/a/3259271/118671 -# [5] http://stackoverflow.com/users/393146 +# [1] https://stackoverflow.com +# [2] https://creativecommons.org/licenses/by-sa/3.0/ +# [3] https://stackoverflow.com/questions/878972 +# [4] https://stackoverflow.com/users/85185 +# [4] https://stackoverflow.com/a/3259271/118671 +# [5] https://stackoverflow.com/users/393146 # ################################################ # -# stdin support added by Merlijn van Deen valhallasw@gmail.com, march 2012 -# Licensed under both CC-BY-SA as the MIT license. +# stdin support added by Merlijn van Deen valhallasw@gmail.com, March 2012 +# Licensed under both CC-BY-SA and the MIT license. # ################################################ - +from io import UnsupportedOperation import sys stdin = sys.stdin stdout = sys.stdout @@ -27,8 +27,8 @@ argv = sys.argv if sys.platform == "win32": import codecs - from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int, \ - create_unicode_buffer + from ctypes import WINFUNCTYPE, windll, POINTER + from ctypes import byref, c_int, create_unicode_buffer from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR try: from ctypes.wintypes import LPVOID @@ -51,50 +51,53 @@ # This also fixes http://bugs.python.org/issue1602. # Credit to Michael Kaplan http://blogs.msdn.com/b/michkap/archive/2010/04/07/9989346.aspx # and TZOmegaTZIOY - # http://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462. + # https://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462. try: - # http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx + # https://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx # HANDLE WINAPI GetStdHandle(DWORD nStdHandle); # returns INVALID_HANDLE_VALUE, NULL, or a valid handle # - # http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx + # https://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx # DWORD WINAPI GetFileType(DWORD hFile); # - # http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx + # https://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32)) STD_INPUT_HANDLE = DWORD(-10) STD_OUTPUT_HANDLE = DWORD(-11) - STD_ERROR_HANDLE = DWORD(-12) + STD_ERROR_HANDLE = DWORD(-12) GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", windll.kernel32)) - FILE_TYPE_CHAR = 0x0002 + FILE_TYPE_CHAR = 0x0002 FILE_TYPE_REMOTE = 0x8000 - GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD)) \ - (("GetConsoleMode", windll.kernel32)) + GetConsoleMode = (WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD)) + (('GetConsoleMode', windll.kernel32))) INVALID_HANDLE_VALUE = DWORD(-1).value
def not_a_console(handle): if handle == INVALID_HANDLE_VALUE or handle is None: return True - return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR - or GetConsoleMode(handle, byref(DWORD())) == 0) + return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR or + GetConsoleMode(handle, byref(DWORD())) == 0)
- old_stdin_fileno = None - old_stdout_fileno = None - old_stderr_fileno = None + def old_fileno(std_name): + # some environments like IDLE don't support the fileno operation + # handle those like std streams which don't have fileno at all + std = getattr(sys, 'std{0}'.format(std_name)) + if hasattr(std, 'fileno'): + try: + return std.fileno() + except UnsupportedOperation: + pass
- if hasattr(sys.stdin, 'fileno'): - old_stdin_fileno = sys.stdin.fileno() - if hasattr(sys.stdout, 'fileno'): - old_stdout_fileno = sys.stdout.fileno() - if hasattr(sys.stderr, 'fileno'): - old_stderr_fileno = sys.stderr.fileno() + old_stdin_fileno = old_fileno('in') + old_stdout_fileno = old_fileno('out') + old_stderr_fileno = old_fileno('err')
- STDIN_FILENO = 0 + STDIN_FILENO = 0 STDOUT_FILENO = 1 STDERR_FILENO = 2 - real_stdin = (old_stdin_fileno == STDIN_FILENO) + real_stdin = (old_stdin_fileno == STDIN_FILENO) real_stdout = (old_stdout_fileno == STDOUT_FILENO) real_stderr = (old_stderr_fileno == STDERR_FILENO)
@@ -102,7 +105,7 @@ hStdin = GetStdHandle(STD_INPUT_HANDLE) if not_a_console(hStdin): real_stdin = False - + if real_stdout: hStdout = GetStdHandle(STD_OUTPUT_HANDLE) if not_a_console(hStdout): @@ -114,34 +117,40 @@ real_stderr = False
if real_stdin: - ReadConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPVOID, DWORD, POINTER(DWORD), \ + ReadConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPVOID, DWORD, POINTER(DWORD), LPVOID)(("ReadConsoleW", windll.kernel32)) - + class UnicodeInput: + + """Unicode terminal input class.""" + def __init__(self, hConsole, name, bufsize=1024): self._hConsole = hConsole self.bufsize = bufsize self.buffer = create_unicode_buffer(bufsize) self.name = name self.encoding = 'utf-8' - + def readline(self): - maxnum = DWORD(self.bufsize-1) + maxnum = DWORD(self.bufsize - 1) numrecv = DWORD(0) result = ReadConsoleW(self._hConsole, self.buffer, maxnum, byref(numrecv), None) if not result: raise Exception("stdin failure") return self.buffer.value[:numrecv.value].encode(self.encoding) - +
if real_stdout or real_stderr: # BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars, # LPDWORD lpCharsWritten, LPVOID lpReserved);
- WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), \ + WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), LPVOID)(("WriteConsoleW", windll.kernel32))
class UnicodeOutput: + + """Unicode terminal output class.""" + def __init__(self, hConsole, stream, fileno, name): self._hConsole = hConsole self._stream = stream @@ -155,16 +164,19 @@
def isatty(self): return False + def close(self): # don't really close the handle, that would only cause problems self.closed = True + def fileno(self): return self._fileno + def flush(self): if self._hConsole is None: try: self._stream.flush() - except Exception, e: + except Exception as e: _complain("%s.flush: %r from %r" % (self.name, e, self._stream)) raise @@ -183,7 +195,7 @@ n = DWORD(0) # There is a shorter-than-documented limitation on the # length of the string passed to WriteConsoleW (see - # http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232. + # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232. retval = WriteConsoleW(self._hConsole, text, min(remaining, 10000), byref(n), None) @@ -191,9 +203,10 @@ raise IOError("WriteConsoleW returned %r, n.value = %r" % (retval, n.value)) remaining -= n.value - if remaining == 0: break + if remaining == 0: + break text = text[n.value:] - except Exception, e: + except Exception as e: _complain("%s.write: %r" % (self.name, e)) raise
@@ -201,36 +214,35 @@ try: for line in lines: self.write(line) - except Exception, e: + except Exception as e: _complain("%s.writelines: %r" % (self.name, e)) raise
if real_stdin: - stdin = UnicodeInput(hStdin, name='<Unicode console stdin>') + stdin = UnicodeInput(hStdin, name='<Unicode console stdin>')
if real_stdout: stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO, - '<Unicode console stdout>') + '<Unicode console stdout>') else: stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno, - '<Unicode redirected stdout>') + '<Unicode redirected stdout>')
if real_stderr: stderr = UnicodeOutput(hStderr, None, STDERR_FILENO, - '<Unicode console stderr>') + '<Unicode console stderr>') else: stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno, - '<Unicode redirected stderr>') - except Exception, e: + '<Unicode redirected stderr>') + except Exception as e: _complain("exception %r while fixing up sys.stdout and sys.stderr" % (e,)) -
# While we're at it, let's unmangle the command-line arguments:
# This works around http://bugs.python.org/issue2128. GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) - CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int)) \ - (("CommandLineToArgvW", windll.shell32)) + CommandLineToArgvW = (WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int)) + (('CommandLineToArgvW', windll.shell32)))
argc = c_int(0) argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
pywikibot-commits@lists.wikimedia.org