https://github.com/python/cpython/commit/91b48868a82821c1cbfd2245212699b57d3a24c7
commit: 91b48868a82821c1cbfd2245212699b57d3a24c7
branch: main
author: Chris Eibl <[email protected]>
committer: ambv <[email protected]>
date: 2025-05-25T15:17:43+02:00
summary:
GH-130328: Speedup pasting in legacy console on Windows (gh-133728)
files:
A Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst
M Lib/_pyrepl/commands.py
M Lib/_pyrepl/windows_console.py
M Lib/test/test_pyrepl/test_unix_console.py
M Lib/test/test_pyrepl/test_windows_console.py
diff --git a/Lib/_pyrepl/commands.py b/Lib/_pyrepl/commands.py
index 2354fbb2ec2c1e..50c824995d85b8 100644
--- a/Lib/_pyrepl/commands.py
+++ b/Lib/_pyrepl/commands.py
@@ -370,6 +370,13 @@ def do(self) -> None:
r = self.reader
text = self.event * r.get_arg()
r.insert(text)
+ if r.paste_mode:
+ data = ""
+ ev = r.console.getpending()
+ data += ev.data
+ if data:
+ r.insert(data)
+ r.last_refresh_cache.invalidated = True
class insert_nl(EditCommand):
@@ -484,7 +491,6 @@ def do(self) -> None:
data = ""
start = time.time()
while done not in data:
- self.reader.console.wait(100)
ev = self.reader.console.getpending()
data += ev.data
trace(
diff --git a/Lib/_pyrepl/windows_console.py b/Lib/_pyrepl/windows_console.py
index 95749198b3b2f9..c56dcd6d7dd434 100644
--- a/Lib/_pyrepl/windows_console.py
+++ b/Lib/_pyrepl/windows_console.py
@@ -419,10 +419,7 @@ 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 and not self.wait(timeout=0):
- return None
-
+ def _read_input(self) -> INPUT_RECORD | None:
rec = INPUT_RECORD()
read = DWORD()
if not ReadConsoleInput(InHandle, rec, 1, read):
@@ -431,14 +428,10 @@ def _read_input(self, block: bool = True) -> INPUT_RECORD
| None:
return rec
def _read_input_bulk(
- self, block: bool, n: int
+ self, n: int
) -> tuple[ctypes.Array[INPUT_RECORD], int]:
rec = (n * INPUT_RECORD)()
read = DWORD()
-
- if not block and not self.wait(timeout=0):
- return rec, 0
-
if not ReadConsoleInput(InHandle, rec, n, read):
raise WinError(GetLastError())
@@ -449,8 +442,11 @@ def get_event(self, block: bool = True) -> Event | None:
and there is no event pending, otherwise waits for the
completion of an event."""
+ if not block and not self.wait(timeout=0):
+ return None
+
while self.event_queue.empty():
- rec = self._read_input(block)
+ rec = self._read_input()
if rec is None:
return None
@@ -551,12 +547,20 @@ def getpending(self) -> Event:
if e2:
e.data += e2.data
- recs, rec_count = self._read_input_bulk(False, 1024)
+ recs, rec_count = self._read_input_bulk(1024)
for i in range(rec_count):
rec = recs[i]
+ # In case of a legacy console, we do not only receive a keydown
+ # event, but also a keyup event - and for uppercase letters
+ # an additional SHIFT_PRESSED event.
if rec and rec.EventType == KEY_EVENT:
key_event = rec.Event.KeyEvent
+ if not key_event.bKeyDown:
+ continue
ch = key_event.uChar.UnicodeChar
+ if ch == "\x00":
+ # ignore SHIFT_PRESSED and special keys
+ continue
if ch == "\r":
ch += "\n"
e.data += ch
diff --git a/Lib/test/test_pyrepl/test_unix_console.py
b/Lib/test/test_pyrepl/test_unix_console.py
index c447b310c49a06..b3f7dc028fe210 100644
--- a/Lib/test/test_pyrepl/test_unix_console.py
+++ b/Lib/test/test_pyrepl/test_unix_console.py
@@ -20,6 +20,7 @@
def unix_console(events, **kwargs):
console = UnixConsole()
console.get_event = MagicMock(side_effect=events)
+ console.getpending = MagicMock(return_value=Event("key", ""))
height = kwargs.get("height", 25)
width = kwargs.get("width", 80)
diff --git a/Lib/test/test_pyrepl/test_windows_console.py
b/Lib/test/test_pyrepl/test_windows_console.py
index e7bab226b31ddf..a52ae96a83ddde 100644
--- a/Lib/test/test_pyrepl/test_windows_console.py
+++ b/Lib/test/test_pyrepl/test_windows_console.py
@@ -35,6 +35,7 @@ class WindowsConsoleTests(TestCase):
def console(self, events, **kwargs) -> Console:
console = WindowsConsole()
console.get_event = MagicMock(side_effect=events)
+ console.getpending = MagicMock(return_value=Event("key", ""))
console.wait = MagicMock()
console._scroll = MagicMock()
console._hide_cursor = MagicMock()
diff --git
a/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst
b/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst
new file mode 100644
index 00000000000000..00b556c6a336ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-05-09-09-10-34.gh-issue-130328.s9h4By.rst
@@ -0,0 +1,2 @@
+Speedup pasting in ``PyREPL`` on Windows in a legacy console. Patch 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]