https://github.com/python/cpython/commit/acb222ce8ff1962b09112accabbcc4ed3d61cf6e
commit: acb222ce8ff1962b09112accabbcc4ed3d61cf6e
branch: main
author: Chris Eibl <138194463+chris-e...@users.noreply.github.com>
committer: ambv <luk...@langa.pl>
date: 2025-04-29T18:03:45+02:00
summary:

GH-130328: pasting in new REPL is slow on Windows (GH-132884)

files:
A Misc/NEWS.d/next/Library/2025-04-24-18-07-49.gh-issue-130328.z7CN8z.rst
M Lib/_pyrepl/windows_console.py

diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py
index 47fd3fd8f8909b..17942c8df0731a 100644
--- a/Lib/_pyrepl/windows_console.py
+++ b/Lib/_pyrepl/windows_console.py
@@ -22,8 +22,6 @@
 import io
 import os
 import sys
-import time
-import msvcrt
 
 import ctypes
 from ctypes.wintypes import (
@@ -44,7 +42,7 @@
 from .windows_eventqueue import EventQueue
 
 try:
-    from ctypes import GetLastError, WinDLL, windll, WinError  # type: 
ignore[attr-defined]
+    from ctypes import get_last_error, GetLastError, WinDLL, windll, WinError  
# type: ignore[attr-defined]
 except:
     # Keep MyPy happy off Windows
     from ctypes import CDLL as WinDLL, cdll as windll
@@ -52,6 +50,9 @@
     def GetLastError() -> int:
         return 42
 
+    def get_last_error() -> int:
+        return 42
+
     class WinError(OSError):  # type: ignore[no-redef]
         def __init__(self, err: int | None, descr: str | None = None) -> None:
             self.err = err
@@ -108,6 +109,12 @@ def __init__(self, err: int | None, descr: str | None = 
None) -> None:
 ALT_ACTIVE = 0x01 | 0x02
 CTRL_ACTIVE = 0x04 | 0x08
 
+WAIT_TIMEOUT = 0x102
+WAIT_FAILED = 0xFFFFFFFF
+
+# from winbase.h
+INFINITE = 0xFFFFFFFF
+
 
 class _error(Exception):
     pass
@@ -409,12 +416,8 @@ def _getscrollbacksize(self) -> int:
         return info.srWindow.Bottom  # type: ignore[no-any-return]
 
     def _read_input(self, block: bool = True) -> INPUT_RECORD | None:
-        if not block:
-            events = DWORD()
-            if not GetNumberOfConsoleInputEvents(InHandle, events):
-                raise WinError(GetLastError())
-            if not events.value:
-                return None
+        if not block and not self.wait(timeout=0):
+            return None
 
         rec = INPUT_RECORD()
         read = DWORD()
@@ -522,14 +525,16 @@ def getpending(self) -> Event:
 
     def wait(self, timeout: float | None) -> bool:
         """Wait for an event."""
-        # Poor man's Windows select loop
-        start_time = time.time()
-        while True:
-            if msvcrt.kbhit(): # type: ignore[attr-defined]
-                return True
-            if timeout and time.time() - start_time > timeout / 1000:
-                return False
-            time.sleep(0.01)
+        if timeout is None:
+            timeout = INFINITE
+        else:
+            timeout = int(timeout)
+        ret = WaitForSingleObject(InHandle, timeout)
+        if ret == WAIT_FAILED:
+            raise WinError(get_last_error())
+        elif ret == WAIT_TIMEOUT:
+            return False
+        return True
 
     def repaint(self) -> None:
         raise NotImplementedError("No repaint support")
@@ -649,14 +654,15 @@ class INPUT_RECORD(Structure):
     ReadConsoleInput.argtypes = [HANDLE, POINTER(INPUT_RECORD), DWORD, 
POINTER(DWORD)]
     ReadConsoleInput.restype = BOOL
 
-    GetNumberOfConsoleInputEvents = _KERNEL32.GetNumberOfConsoleInputEvents
-    GetNumberOfConsoleInputEvents.argtypes = [HANDLE, POINTER(DWORD)]
-    GetNumberOfConsoleInputEvents.restype = BOOL
 
     FlushConsoleInputBuffer = _KERNEL32.FlushConsoleInputBuffer
     FlushConsoleInputBuffer.argtypes = [HANDLE]
     FlushConsoleInputBuffer.restype = BOOL
 
+    WaitForSingleObject = _KERNEL32.WaitForSingleObject
+    WaitForSingleObject.argtypes = [HANDLE, DWORD]
+    WaitForSingleObject.restype = DWORD
+
     OutHandle = GetStdHandle(STD_OUTPUT_HANDLE)
     InHandle = GetStdHandle(STD_INPUT_HANDLE)
 else:
@@ -670,7 +676,7 @@ def _win_only(*args, **kwargs):
     GetConsoleMode = _win_only
     SetConsoleMode = _win_only
     ReadConsoleInput = _win_only
-    GetNumberOfConsoleInputEvents = _win_only
     FlushConsoleInputBuffer = _win_only
+    WaitForSingleObject = _win_only
     OutHandle = 0
     InHandle = 0
diff --git 
a/Misc/NEWS.d/next/Library/2025-04-24-18-07-49.gh-issue-130328.z7CN8z.rst 
b/Misc/NEWS.d/next/Library/2025-04-24-18-07-49.gh-issue-130328.z7CN8z.rst
new file mode 100644
index 00000000000000..f53b2bd3512139
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-04-24-18-07-49.gh-issue-130328.z7CN8z.rst
@@ -0,0 +1 @@
+Speedup pasting in ``PyREPL`` on Windows. Fix by Chris Eibl.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to