From d77c46e7e4585f2884036724db948c8a8456db32 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 30 May 2026 02:37:43 +0900 Subject: [PATCH 1/4] Use _winapi for _pyrepl console handles and waits --- Lib/_pyrepl/windows_console.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index c1f9a19545d35fd..70ff7273fb0a2fc 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -53,10 +53,10 @@ from .windows_eventqueue import EventQueue try: - from ctypes import get_last_error, WinDLL, windll, WinError # type: ignore[attr-defined] + from ctypes import get_last_error, WinDLL, WinError # type: ignore[attr-defined] except: # Keep MyPy happy off Windows - from ctypes import CDLL as WinDLL, cdll as windll + from ctypes import CDLL as WinDLL def get_last_error() -> int: return 42 @@ -796,11 +796,11 @@ class INPUT_RECORD(Structure): STD_OUTPUT_HANDLE = -11 if sys.platform == "win32": + import _winapi + _KERNEL32 = WinDLL("kernel32", use_last_error=True) - GetStdHandle = windll.kernel32.GetStdHandle - GetStdHandle.argtypes = [DWORD] - GetStdHandle.restype = HANDLE + GetStdHandle = _winapi.GetStdHandle GetConsoleScreenBufferInfo = _KERNEL32.GetConsoleScreenBufferInfo GetConsoleScreenBufferInfo.argtypes = [ @@ -836,9 +836,7 @@ class INPUT_RECORD(Structure): FlushConsoleInputBuffer.argtypes = [HANDLE] FlushConsoleInputBuffer.restype = BOOL - WaitForSingleObject = _KERNEL32.WaitForSingleObject - WaitForSingleObject.argtypes = [HANDLE, DWORD] - WaitForSingleObject.restype = DWORD + WaitForSingleObject = _winapi.WaitForSingleObject OutHandle = GetStdHandle(STD_OUTPUT_HANDLE) InHandle = GetStdHandle(STD_INPUT_HANDLE) From 8d3ef984d5e3a1d368c0111698972f7654cc2c0d Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 30 May 2026 02:45:42 +0900 Subject: [PATCH 2/4] Use _winapi calls directly in _pyrepl --- Lib/_pyrepl/windows_console.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 70ff7273fb0a2fc..4d04b9bf75755a4 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -696,7 +696,7 @@ def wait_for_event(self, timeout: float | None) -> bool: timeout = INFINITE else: timeout = int(timeout) - ret = WaitForSingleObject(InHandle, timeout) + ret = _winapi.WaitForSingleObject(InHandle, timeout) if ret == WAIT_FAILED: raise WinError(get_last_error()) elif ret == WAIT_TIMEOUT: @@ -800,8 +800,6 @@ class INPUT_RECORD(Structure): _KERNEL32 = WinDLL("kernel32", use_last_error=True) - GetStdHandle = _winapi.GetStdHandle - GetConsoleScreenBufferInfo = _KERNEL32.GetConsoleScreenBufferInfo GetConsoleScreenBufferInfo.argtypes = [ HANDLE, @@ -836,22 +834,18 @@ class INPUT_RECORD(Structure): FlushConsoleInputBuffer.argtypes = [HANDLE] FlushConsoleInputBuffer.restype = BOOL - WaitForSingleObject = _winapi.WaitForSingleObject - - OutHandle = GetStdHandle(STD_OUTPUT_HANDLE) - InHandle = GetStdHandle(STD_INPUT_HANDLE) + OutHandle = _winapi.GetStdHandle(STD_OUTPUT_HANDLE) + InHandle = _winapi.GetStdHandle(STD_INPUT_HANDLE) else: def _win_only(*args, **kwargs): raise NotImplementedError("Windows only") - GetStdHandle = _win_only GetConsoleScreenBufferInfo = _win_only ScrollConsoleScreenBuffer = _win_only GetConsoleMode = _win_only SetConsoleMode = _win_only ReadConsoleInput = _win_only FlushConsoleInputBuffer = _win_only - WaitForSingleObject = _win_only OutHandle = 0 InHandle = 0 From 4dfefb8195e7851d54edde55bb8616432d5f39db Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 30 May 2026 02:55:38 +0900 Subject: [PATCH 3/4] Move _winapi import with other imports --- Lib/_pyrepl/windows_console.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index 4d04b9bf75755a4..cd58b5676da814f 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -66,6 +66,11 @@ def __init__(self, err: int | None, descr: str | None = None) -> None: self.err = err self.descr = descr +try: + import _winapi +except ImportError: + _winapi = None + # declare nt optional to allow None assignment on other platforms nt: types.ModuleType | None try: @@ -696,6 +701,7 @@ def wait_for_event(self, timeout: float | None) -> bool: timeout = INFINITE else: timeout = int(timeout) + assert _winapi is not None # to make mypy happy ret = _winapi.WaitForSingleObject(InHandle, timeout) if ret == WAIT_FAILED: raise WinError(get_last_error()) @@ -796,8 +802,7 @@ class INPUT_RECORD(Structure): STD_OUTPUT_HANDLE = -11 if sys.platform == "win32": - import _winapi - + assert _winapi is not None # to make mypy happy _KERNEL32 = WinDLL("kernel32", use_last_error=True) GetConsoleScreenBufferInfo = _KERNEL32.GetConsoleScreenBufferInfo From 3ff96aee08a34a9f282821e775c9508d2fc7ae86 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 30 May 2026 03:00:39 +0900 Subject: [PATCH 4/4] Fix mypy for _winapi usage in _pyrepl --- Lib/_pyrepl/windows_console.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py index cd58b5676da814f..ba16542f61c9863 100644 --- a/Lib/_pyrepl/windows_console.py +++ b/Lib/_pyrepl/windows_console.py @@ -66,6 +66,7 @@ def __init__(self, err: int | None, descr: str | None = None) -> None: self.err = err self.descr = descr +_winapi: types.ModuleType | None try: import _winapi except ImportError: @@ -702,7 +703,9 @@ def wait_for_event(self, timeout: float | None) -> bool: else: timeout = int(timeout) assert _winapi is not None # to make mypy happy - ret = _winapi.WaitForSingleObject(InHandle, timeout) + ret = _winapi.WaitForSingleObject( # type: ignore[attr-defined] + InHandle, timeout + ) if ret == WAIT_FAILED: raise WinError(get_last_error()) elif ret == WAIT_TIMEOUT: