jenkins-bot has submitted this change and it was merged.
Change subject: Reorganise win32_unicode module
......................................................................
Reorganise win32_unicode module
Move all imports and classes to the top of the module,
with all code enclosed in functions, and clean up the
way the unicode objects are obtained by the UI class.
ctypes.wintypes.LPVOID is ctypes.c_void_p on all
supported versions of Python.
Change-Id: I3ebb29b91e99e2652fbd6e02af0e7c491793fe78
---
M pywikibot/userinterfaces/terminal_interface_win32.py
M pywikibot/userinterfaces/win32_unicode.py
2 files changed, 179 insertions(+), 146 deletions(-)
Approvals:
John Vandenberg: Looks good to me, but someone else must approve
XZise: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/userinterfaces/terminal_interface_win32.py
b/pywikibot/userinterfaces/terminal_interface_win32.py
index 2c3107b..43db049 100755
--- a/pywikibot/userinterfaces/terminal_interface_win32.py
+++ b/pywikibot/userinterfaces/terminal_interface_win32.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""User interface for Win32 terminals."""
#
-# (C) Pywikibot team, 2003-2013
+# (C) Pywikibot team, 2003-2015
#
# Distributed under the terms of the MIT license.
#
@@ -11,7 +11,10 @@
import re
-from pywikibot.userinterfaces import terminal_interface_base
+from pywikibot.userinterfaces import (
+ terminal_interface_base,
+ win32_unicode,
+)
try:
import ctypes
@@ -60,7 +63,7 @@
def __init__(self):
"""Constructor."""
Win32BaseUI.__init__(self)
- from .win32_unicode import stdin, stdout, stderr, argv
+ (stdin, stdout, stderr, argv) = win32_unicode.get_unicode_console()
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
diff --git a/pywikibot/userinterfaces/win32_unicode.py
b/pywikibot/userinterfaces/win32_unicode.py
index 63af993..db26ddd 100755
--- a/pywikibot/userinterfaces/win32_unicode.py
+++ b/pywikibot/userinterfaces/win32_unicode.py
@@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-
"""Stdout, stderr and argv support for unicode."""
+#
+# (C) David-Sarah Hopwood, 2010
+# (C) Pywikibot team, 2012-2015
+#
##############################################
# Support for unicode in windows cmd.exe
# Posted on Stack Overflow [1], available under CC-BY-SA 3.0 [2]
@@ -21,12 +25,15 @@
#
################################################
from __future__ import absolute_import, print_function, unicode_literals
-from io import UnsupportedOperation
+
+import codecs
import sys
-stdin = sys.stdin
-stdout = sys.stdout
-stderr = sys.stderr
-argv = sys.argv
+
+from ctypes import byref, c_int, create_unicode_buffer
+from ctypes import c_void_p as LPVOID
+from io import UnsupportedOperation
+
+OSWIN32 = (sys.platform == "win32")
if sys.version_info[0] > 2:
unicode = str
@@ -34,33 +41,175 @@
else:
PY3 = False
-if sys.platform == "win32":
- import codecs
+stdin = sys.stdin
+stdout = sys.stdout
+stderr = sys.stderr
+argv = sys.argv
+
+original_stderr = sys.stderr
+
+if OSWIN32:
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
- except ImportError:
- from ctypes import c_void_p as LPVOID
- original_stderr = sys.stderr
+try:
+ ReadConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPVOID, DWORD, POINTER(DWORD),
+ LPVOID)(("ReadConsoleW", windll.kernel32))
+ WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD),
+ LPVOID)(("WriteConsoleW", windll.kernel32))
+except NameError:
+ ReadConsoleW = WriteConsoleW = None
- # If any exception occurs in this code, we'll probably try to print it on
stderr,
- # which makes for frustrating debugging if stderr is directed to our wrapper.
- # So be paranoid about catching errors and reporting them to original_stderr,
- # so that we can at least see them.
- def _complain(message):
- print(isinstance(message, str) and message or repr(message),
file=original_stderr)
+class UnicodeInput:
+
+ """Unicode terminal input class."""
+
+ def __init__(self, hConsole, name, bufsize=1024):
+ """Initialize the input stream."""
+ self._hConsole = hConsole
+ self.bufsize = bufsize
+ self.buffer = create_unicode_buffer(bufsize)
+ self.name = name
+ self.encoding = 'utf-8'
+
+ def readline(self):
+ """Read one line from the input."""
+ 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")
+ data = self.buffer.value[:numrecv.value]
+ if not PY3:
+ return data.encode(self.encoding)
+ else:
+ return data
+
+
+class UnicodeOutput:
+
+ """Unicode terminal output class."""
+
+ def __init__(self, hConsole, stream, fileno, name):
+ """Initialize the output stream."""
+ self._hConsole = hConsole
+ self._stream = stream
+ self._fileno = fileno
+ self.closed = False
+ self.softspace = False
+ self.mode = 'w'
+ self.encoding = 'utf-8'
+ self.name = name
+ self.flush()
+
+ def isatty(self):
+ """Return whether it's a tty."""
+ return False
+
+ def close(self):
+ """Set the stream to be closed."""
+ # don't really close the handle, that would only cause problems
+ self.closed = True
+
+ def fileno(self):
+ """Return the fileno."""
+ return self._fileno
+
+ def flush(self):
+ """Flush the stream."""
+ if self._hConsole is None:
+ try:
+ self._stream.flush()
+ except Exception as e:
+ _complain("%s.flush: %r from %r"
+ % (self.name, e, self._stream))
+ raise
+
+ def write(self, text):
+ """Write the text to the output."""
+ try:
+ if self._hConsole is None:
+ if isinstance(text, unicode):
+ text = text.encode('utf-8')
+ self._stream.write(text)
+ else:
+ if not isinstance(text, unicode):
+ text = bytes(text).decode('utf-8')
+ remaining = len(text)
+ while remaining > 0:
+ n = DWORD(0)
+ # There is a shorter-than-documented limitation on the
+ # length of the string passed to WriteConsoleW (see
+ # <https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
+ retval = WriteConsoleW(self._hConsole, text,
+ min(remaining, 10000),
+ byref(n), None)
+ if retval == 0 or n.value == 0:
+ raise IOError("WriteConsoleW returned %r, n.value =
%r"
+ % (retval, n.value))
+ remaining -= n.value
+ if remaining == 0:
+ break
+ text = text[n.value:]
+ except Exception as e:
+ _complain("%s.write: %r" % (self.name, e))
+ raise
+
+ def writelines(self, lines):
+ """Write a list of lines by using write."""
+ try:
+ for line in lines:
+ self.write(line)
+ except Exception as e:
+ _complain("%s.writelines: %r" % (self.name, e))
+ raise
+
+
+def old_fileno(std_name):
+ """Return the fileno or None if that doesn't
work."""
+ # 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 any exception occurs in this code, we'll probably try to print it on stderr,
+# which makes for frustrating debugging if stderr is directed to our wrapper.
+# So be paranoid about catching errors and reporting them to original_stderr,
+# so that we can at least see them.
+def _complain(message):
+ print(isinstance(message, str) and message or repr(message), file=original_stderr)
+
+
+def register_cp65001():
+ """Register codecs cp65001 as utf-8."""
# Work around <http://bugs.python.org/issue6058>.
codecs.register(lambda name: name == 'cp65001' and
codecs.lookup('utf-8') or None)
+
+def get_unicode_console():
+ """
+ Get Unicode console objects.
+
+ @return: stdin, stdout, stderr, argv
+ @rtype: tuple
+ """
# Make Unicode console output work independently of the current code page.
# 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
#
<https://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.
+
+ global stdin, stdout, stderr, argv
+
+ if not OSWIN32:
+ return stdin, stdout, stderr, argv
+
try:
# <https://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
# HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
@@ -90,17 +239,6 @@
return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR or
GetConsoleMode(handle, byref(DWORD())) == 0)
- def old_fileno(std_name):
- """Return the fileno or None if that doesn't
work."""
- # 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
-
old_stdin_fileno = old_fileno('in')
old_stdout_fileno = old_fileno('out')
old_stderr_fileno = old_fileno('err')
@@ -127,120 +265,7 @@
if not_a_console(hStderr):
real_stderr = False
- if real_stdin:
- 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):
- """Initialize the input stream."""
- self._hConsole = hConsole
- self.bufsize = bufsize
- self.buffer = create_unicode_buffer(bufsize)
- self.name = name
- self.encoding = 'utf-8'
-
- def readline(self):
- """Read one line from the input."""
- 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")
- data = self.buffer.value[:numrecv.value]
- if not PY3:
- return data.encode(self.encoding)
- else:
- return data
-
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),
- LPVOID)(("WriteConsoleW",
windll.kernel32))
-
- class UnicodeOutput:
-
- """Unicode terminal output class."""
-
- def __init__(self, hConsole, stream, fileno, name):
- """Initialize the output stream."""
- self._hConsole = hConsole
- self._stream = stream
- self._fileno = fileno
- self.closed = False
- self.softspace = False
- self.mode = 'w'
- self.encoding = 'utf-8'
- self.name = name
- self.flush()
-
- def isatty(self):
- """Return whether it's a tty."""
- return False
-
- def close(self):
- """Set the stream to be closed."""
- # don't really close the handle, that would only cause problems
- self.closed = True
-
- def fileno(self):
- """Return the fileno."""
- return self._fileno
-
- def flush(self):
- """Flush the stream."""
- if self._hConsole is None:
- try:
- self._stream.flush()
- except Exception as e:
- _complain("%s.flush: %r from %r"
- % (self.name, e, self._stream))
- raise
-
- def write(self, text):
- """Write the text to the output."""
- try:
- if self._hConsole is None:
- if isinstance(text, unicode):
- text = text.encode('utf-8')
- self._stream.write(text)
- else:
- if not isinstance(text, unicode):
- text = bytes(text).decode('utf-8')
- remaining = len(text)
- while remaining > 0:
- n = DWORD(0)
- # There is a shorter-than-documented limitation on the
- # length of the string passed to WriteConsoleW (see
- #
<https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
- retval = WriteConsoleW(self._hConsole, text,
- min(remaining, 10000),
- byref(n), None)
- if retval == 0 or n.value == 0:
- raise IOError("WriteConsoleW returned %r,
n.value = %r"
- % (retval, n.value))
- remaining -= n.value
- if remaining == 0:
- break
- text = text[n.value:]
- except Exception as e:
- _complain("%s.write: %r" % (self.name, e))
- raise
-
- def writelines(self, lines):
- """Write a list of lines by using
write."""
- try:
- for line in lines:
- self.write(line)
- except Exception as e:
- _complain("%s.writelines: %r" % (self.name, e))
- raise
-
if real_stdin:
stdin = UnicodeInput(hStdin, name='<Unicode console
stdin>')
@@ -294,3 +319,8 @@
if argv == []:
argv = [u'']
+
+ return stdin, stdout, stderr, argv
+
+if OSWIN32:
+ register_cp65001()
--
To view, visit
https://gerrit.wikimedia.org/r/239540
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I3ebb29b91e99e2652fbd6e02af0e7c491793fe78
Gerrit-PatchSet: 3
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot <>