4
4
import contextlib
5
5
import inspect
6
6
import sys
7
- import types
8
7
import warnings
9
8
from code import InteractiveConsole
9
+ from types import CodeType , FunctionType , FrameType
10
+ from typing import Callable
10
11
11
12
import outcome
12
13
@@ -19,6 +20,16 @@ class SuppressDecorator(contextlib.ContextDecorator, contextlib.suppress):
19
20
pass
20
21
21
22
23
+ @SuppressDecorator (KeyboardInterrupt )
24
+ @trio .lowlevel .disable_ki_protection
25
+ def terminal_newline () -> None :
26
+ import fcntl
27
+ import termios
28
+
29
+ # Fake up a newline char as if user had typed it at the terminal
30
+ fcntl .ioctl (sys .stdin , termios .TIOCSTI , b"\n " )
31
+
32
+
22
33
@final
23
34
class TrioInteractiveConsole (InteractiveConsole ):
24
35
# code.InteractiveInterpreter defines locals as Mapping[str, Any]
@@ -31,8 +42,8 @@ def __init__(self, repl_locals: dict[str, object] | None = None) -> None:
31
42
self .token : trio .lowlevel .TrioToken | None = None
32
43
self .compile .compiler .flags |= ast .PyCF_ALLOW_TOP_LEVEL_AWAIT
33
44
34
- def runcode (self , code : types . CodeType ) -> None :
35
- func = types . FunctionType (code , self .locals )
45
+ def runcode (self , code : CodeType ) -> None :
46
+ func = FunctionType (code , self .locals )
36
47
if inspect .iscoroutinefunction (func ):
37
48
result = trio .from_thread .run (outcome .acapture , func )
38
49
else :
@@ -79,24 +90,19 @@ def raw_input(self, prompt: str = "") -> str:
79
90
80
91
interrupted = False
81
92
82
- if self .token is None :
83
- self .token = trio .from_thread .run_sync (trio .lowlevel .current_trio_token )
84
-
85
- @SuppressDecorator (KeyboardInterrupt )
86
- @trio .lowlevel .disable_ki_protection
87
- def newline ():
88
- import fcntl
89
- import termios
93
+ def install_handler () -> (
94
+ Callable [[int , FrameType | None ], None ] | int | None
95
+ ):
96
+ def handler (sig : int , frame : FrameType | None ) -> None :
97
+ nonlocal interrupted
98
+ interrupted = True
99
+ token .run_sync_soon (terminal_newline , idempotent = True )
90
100
91
- # Fake up a newline char as if user had typed it at
92
- fcntl .ioctl (sys .stdin , termios .TIOCSTI , b"\n " )
101
+ token = trio .lowlevel .current_trio_token ()
93
102
94
- def handler (sig : int , frame : types .FrameType | None ) -> None :
95
- nonlocal interrupted
96
- interrupted = True
97
- self .token .run_sync_soon (newline , idempotent = True )
103
+ return signal (SIGINT , handler )
98
104
99
- prev_handler = trio .from_thread .run_sync (signal , SIGINT , handler )
105
+ prev_handler = trio .from_thread .run_sync (install_handler )
100
106
try :
101
107
return input (prompt )
102
108
finally :
0 commit comments