mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
[3.13] gh-120221: Support KeyboardInterrupt in asyncio REPL (GH-123795) (#123799)
This switches the main pyrepl event loop to always be non-blocking so that it
can listen to incoming interruptions from other threads.
This also resolves invalid display of exceptions from other threads
(gh-123178).
This also fixes freezes with pasting and an active input hook.
(cherry picked from commit 033510e11d
)
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
66b15381f1
commit
5c3078d6e5
8 changed files with 133 additions and 21 deletions
|
@ -36,8 +36,7 @@ from .trace import trace
|
|||
|
||||
# types
|
||||
Command = commands.Command
|
||||
if False:
|
||||
from .types import Callback, SimpleContextManager, KeySpec, CommandName
|
||||
from .types import Callback, SimpleContextManager, KeySpec, CommandName
|
||||
|
||||
|
||||
def disp_str(buffer: str) -> tuple[str, list[int]]:
|
||||
|
@ -247,6 +246,7 @@ class Reader:
|
|||
lxy: tuple[int, int] = field(init=False)
|
||||
scheduled_commands: list[str] = field(default_factory=list)
|
||||
can_colorize: bool = False
|
||||
threading_hook: Callback | None = None
|
||||
|
||||
## cached metadata to speed up screen refreshes
|
||||
@dataclass
|
||||
|
@ -722,6 +722,24 @@ class Reader:
|
|||
self.console.finish()
|
||||
self.finish()
|
||||
|
||||
def run_hooks(self) -> None:
|
||||
threading_hook = self.threading_hook
|
||||
if threading_hook is None and 'threading' in sys.modules:
|
||||
from ._threading_handler import install_threading_hook
|
||||
install_threading_hook(self)
|
||||
if threading_hook is not None:
|
||||
try:
|
||||
threading_hook()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
input_hook = self.console.input_hook
|
||||
if input_hook:
|
||||
try:
|
||||
input_hook()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def handle1(self, block: bool = True) -> bool:
|
||||
"""Handle a single event. Wait as long as it takes if block
|
||||
is true (the default), otherwise return False if no event is
|
||||
|
@ -732,16 +750,13 @@ class Reader:
|
|||
self.dirty = True
|
||||
|
||||
while True:
|
||||
input_hook = self.console.input_hook
|
||||
if input_hook:
|
||||
input_hook()
|
||||
# We use the same timeout as in readline.c: 100ms
|
||||
while not self.console.wait(100):
|
||||
input_hook()
|
||||
event = self.console.get_event(block=False)
|
||||
else:
|
||||
event = self.console.get_event(block)
|
||||
if not event: # can only happen if we're not blocking
|
||||
# We use the same timeout as in readline.c: 100ms
|
||||
self.run_hooks()
|
||||
self.console.wait(100)
|
||||
event = self.console.get_event(block=False)
|
||||
if not event:
|
||||
if block:
|
||||
continue
|
||||
return False
|
||||
|
||||
translate = True
|
||||
|
@ -763,8 +778,7 @@ class Reader:
|
|||
if cmd is None:
|
||||
if block:
|
||||
continue
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
self.do_cmd(cmd)
|
||||
return True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue