mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	GH-130328: pasting in new REPL is slow on Windows (GH-132884)
This commit is contained in:
		
							parent
							
								
									ae37f3d3c0
								
							
						
					
					
						commit
						acb222ce8f
					
				
					 2 changed files with 28 additions and 21 deletions
				
			
		|  | @ -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,11 +416,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: | ||||
|             events = DWORD() | ||||
|             if not GetNumberOfConsoleInputEvents(InHandle, events): | ||||
|                 raise WinError(GetLastError()) | ||||
|             if not events.value: | ||||
|         if not block and not self.wait(timeout=0): | ||||
|             return None | ||||
| 
 | ||||
|         rec = INPUT_RECORD() | ||||
|  | @ -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: | ||||
|         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 | ||||
|             time.sleep(0.01) | ||||
|         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 | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| Speedup pasting in ``PyREPL`` on Windows. Fix by Chris Eibl. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Chris Eibl
						Chris Eibl