jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/769693 )
Change subject: [cleanup] no longer use win32_unicode for Python 3.6+
......................................................................
[cleanup] no longer use win32_unicode for Python 3.6+
This reverts revert 13f59c7f18593601a6635d2f94ad3066b7bec0a3.
- flash target in UI._print if necessary. This has to be done if the
after a text is processed with UI._print and before a color is changed
- get console_handle to set color attribute in Win32UI.encounter_color
- define isatty() for Python 3.5 to keep the old behaviour
- update and simplify tests
- remove unused utils.FakeModule
- ignore win32_unicode.py from coverage
Bug: T303373
Bug: T283808
Bug: T281042
Change-Id: Icd3f45a8a907bf2c4a11da68e25339b79de11eaf
---
M .codecov.yml
M pywikibot/userinterfaces/terminal_interface_base.py
M pywikibot/userinterfaces/terminal_interface_win32.py
M pywikibot/userinterfaces/win32_unicode.py
M tests/ui_tests.py
M tests/utils.py
6 files changed, 47 insertions(+), 73 deletions(-)
Approvals:
Chris Maynor: Looks good to me, but someone else must approve
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/.codecov.yml b/.codecov.yml
index 3314ceb..b19bd5e 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -17,6 +17,7 @@
- pywikibot/backports.py
- pywikibot/daemonize.py
- pywikibot/families/__init__.py
+ - pywikibot/userinterfaces/win32_unicode.py
- scripts/archive/
- scripts/userscripts/
- scripts/maintenance/colors.py
diff --git a/pywikibot/userinterfaces/terminal_interface_base.py
b/pywikibot/userinterfaces/terminal_interface_base.py
index 21c4c87..b855863 100755
--- a/pywikibot/userinterfaces/terminal_interface_base.py
+++ b/pywikibot/userinterfaces/terminal_interface_base.py
@@ -190,8 +190,13 @@
if current_color != next_color and colorized:
# set the new color, but only if they change
+ # flush first to enable color change on Windows (T283808)
+ target_stream.flush()
self.encounter_color(color_stack[-1], target_stream)
+ # finally flush stream to show the text, required for Windows (T303373)
+ target_stream.flush()
+
def output(self, text, targetStream=None) -> None:
"""Forward text to cache and flush if output is not locked.
diff --git a/pywikibot/userinterfaces/terminal_interface_win32.py
b/pywikibot/userinterfaces/terminal_interface_win32.py
index 1a0ef51..20d4b12 100755
--- a/pywikibot/userinterfaces/terminal_interface_win32.py
+++ b/pywikibot/userinterfaces/terminal_interface_win32.py
@@ -6,7 +6,8 @@
#
import ctypes
-from pywikibot.userinterfaces import terminal_interface_base, win32_unicode
+from pywikibot.tools import PYTHON_VERSION
+from pywikibot.userinterfaces import terminal_interface_base
windowsColors = {
@@ -37,16 +38,18 @@
def __init__(self) -> None:
"""Initializer."""
super().__init__()
- (stdin, stdout, stderr, argv) = win32_unicode.get_unicode_console()
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
- self.argv = argv
- self.encoding = 'utf-8'
+ if PYTHON_VERSION == (3, 5): # issue1602 solved in Python 3.6
+ from pywikibot.userinterfaces import win32_unicode
+ stdin, stdout, stderr, argv = win32_unicode.get_unicode_console()
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ self.argv = argv
+ self.encoding = 'utf-8'
def support_color(self, target_stream):
"""Return whether the target stream supports actually color."""
- return getattr(target_stream, '_hConsole', None) is not None
+ return target_stream.isatty()
def encounter_color(self, color, target_stream) -> None:
"""Set the new color."""
@@ -55,8 +58,21 @@
# Merge foreground/backgroung color if needed.
if bg is not None:
windows_color = windowsColors[bg] << 4 | windows_color
- ctypes.windll.kernel32.SetConsoleTextAttribute(
- target_stream._hConsole, windows_color)
+
+ if target_stream == self.stdin:
+ addr = -10
+ elif target_stream == self.stdout:
+ addr = -11
+ elif target_stream == self.stderr:
+ addr = -12
+ else:
+ super().encounter_color(color, target_stream)
+
+ from ctypes.wintypes import DWORD, HANDLE
+ get_handle = ctypes.WINFUNCTYPE(HANDLE, DWORD)(
+ ('GetStdHandle', ctypes.windll.kernel32))
+ handle = get_handle(DWORD(addr))
+ ctypes.windll.kernel32.SetConsoleTextAttribute(handle, windows_color)
def _raw_input(self):
data = self.stdin.readline()
diff --git a/pywikibot/userinterfaces/win32_unicode.py
b/pywikibot/userinterfaces/win32_unicode.py
index ae7c1f5..75008a4 100755
--- a/pywikibot/userinterfaces/win32_unicode.py
+++ b/pywikibot/userinterfaces/win32_unicode.py
@@ -153,6 +153,10 @@
_complain('{}.writelines: {!r}'.format(self.name, e))
raise
+ def isatty(self):
+ """Return True if the stream is interactive."""
+ return self._hConsole is not None
+
def old_fileno(std_name):
"""Return the fileno or None if that doesn't work."""
diff --git a/tests/ui_tests.py b/tests/ui_tests.py
index 8e78ea3..c9d8109 100644
--- a/tests/ui_tests.py
+++ b/tests/ui_tests.py
@@ -31,7 +31,6 @@
)
from pywikibot.userinterfaces.transliteration import NON_LATIN_DIGITS, _trans
from tests.aspects import TestCase, TestCaseBase
-from tests.utils import FakeModule
class Stream:
@@ -487,7 +486,10 @@
"""Base class for test cases requiring that colorized output is active."""
+ net = False
+
expect_color = True
+ expected = 'Hello world you!'
def setUp(self):
"""Force colorized_output to True."""
@@ -500,16 +502,6 @@
pywikibot.config.colorized_output = self._old_config
super().tearDown()
-
-class FakeUnixTest(FakeUIColorizedTestBase, FakeUITest):
-
- """Test case to allow doing colorized Unix tests in any environment."""
-
- net = False
-
- expected = 'Hello world you!'
- ui_class = terminal_interface_unix.UnixUI
-
def _encounter_color(self, color, target_stream):
"""Verify that the written data, color and stream are correct."""
self.assertIs(target_stream, self.stream)
@@ -520,6 +512,13 @@
sum(e[1] for e in self._colors[:self._index]))
+class FakeUnixTest(FakeUIColorizedTestBase, FakeUITest):
+
+ """Test case to allow doing colorized Unix tests in any environment."""
+
+ ui_class = terminal_interface_unix.UnixUI
+
+
class FakeWin32Test(FakeUIColorizedTestBase, FakeUITest):
"""
@@ -530,54 +529,21 @@
import these will be unpatched.
"""
- net = False
-
- expected = 'Hello world you!'
ui_class = terminal_interface_win32.Win32UI
def setUp(self):
"""Patch the ctypes import and initialize a stream and UI instance."""
super().setUp()
- self._orig_ctypes = terminal_interface_win32.ctypes
- ctypes = FakeModule.create_dotted('ctypes.windll.kernel32')
- ctypes.windll.kernel32.SetConsoleTextAttribute = self._handle_setattr
- terminal_interface_win32.ctypes = ctypes
- self.stream._hConsole = object()
-
- def tearDown(self):
- """Unpatch the ctypes import and check that all colors were used."""
- terminal_interface_win32.ctypes = self._orig_ctypes
- super().tearDown()
-
- def _encounter_color(self, color, target_stream):
- """Call the original method."""
- self._orig_encounter_color(color, target_stream)
-
- def _handle_setattr(self, handle, attribute):
- """Dummy method to handle SetConsoleTextAttribute."""
- self.assertIs(handle, self.stream._hConsole)
- color = self._colors[self._index][0]
- self._index += 1
- color = terminal_interface_win32.windowsColors[color]
- self.assertEqual(attribute, color)
- self.assertLength(self.stream.getvalue(),
- sum(e[1] for e in self._colors[:self._index]))
+ self.stream.isatty = lambda: self.expect_color
class FakeWin32UncolorizedTest(FakeWin32Test):
"""Test case to allow doing uncolorized Win32 tests in any environment."""
- net = False
-
expected = 'Hello world you! ***'
expect_color = False
- def setUp(self):
- """Change the local stream's console to None to disable colors."""
- super().setUp()
- self.stream._hConsole = None
-
if __name__ == '__main__': # pragma: no cover
with suppress(SystemExit):
diff --git a/tests/utils.py b/tests/utils.py
index 5731aae..35f3372 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -11,7 +11,6 @@
import warnings
from contextlib import contextmanager
from subprocess import PIPE, Popen, TimeoutExpired
-from types import ModuleType
import pywikibot
from pywikibot import config
@@ -60,23 +59,6 @@
return False
-class FakeModule(ModuleType):
-
- """An empty fake module."""
-
- @classmethod
- def create_dotted(cls, name):
- """Create a chain of modules based on the name separated by periods."""
- modules = name.split('.')
- mod = None
- for mod_name in modules[::-1]:
- module = cls(str(mod_name))
- if mod:
- setattr(module, mod.__name__, mod)
- mod = module
- return mod
-
-
class WarningSourceSkipContextManager(warnings.catch_warnings):
"""
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/769693
To unsubscribe, or for help writing mail filters, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Icd3f45a8a907bf2c4a11da68e25339b79de11eaf
Gerrit-Change-Number: 769693
Gerrit-PatchSet: 8
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Chris Maynor <[email protected]>
Gerrit-Reviewer: JJMC89 <[email protected]>
Gerrit-Reviewer: Meno25 <[email protected]>
Gerrit-Reviewer: Merlijn van Deen <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]