https://github.com/python/cpython/commit/acb222ce8ff1962b09112accabbcc4ed3d61cf6e
commit: acb222ce8ff1962b09112accabbcc4ed3d61cf6e
branch: main
author: Chris Eibl <[email protected]>
committer: ambv <[email protected]>
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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]