1
- """For running Python code that could interrupt itself at any time
2
- in order to, for example, ask for a read on stdin, or a write on stdout
1
+ """For running Python code that could interrupt itself at any time in order to,
2
+ for example, ask for a read on stdin, or a write on stdout
3
3
4
- The CodeRunner spawns a greenlet to run code in, and that code can suspend
5
- its own execution to ask the main greenlet to refresh the display or get information.
4
+ The CodeRunner spawns a greenlet to run code in, and that code can suspend its
5
+ own execution to ask the main greenlet to refresh the display or get
6
+ information.
6
7
7
- Greenlets are basically threads that can explicitly switch control to each other.
8
- You can replace the word "greenlet" with "thread" in these docs if that makes more
9
- sense to you.
8
+ Greenlets are basically threads that can explicitly switch control to each
9
+ other. You can replace the word "greenlet" with "thread" in these docs if that
10
+ makes more sense to you.
10
11
"""
11
12
12
13
import code
16
17
17
18
logger = logging .getLogger (__name__ )
18
19
20
+
19
21
class SigintHappened (object ):
20
22
"""If this class is returned, a SIGINT happened while the main greenlet"""
21
23
24
+
22
25
class SystemExitFromCodeGreenlet (SystemExit ):
23
- """If this class is returned, a SystemExit happened while in the code greenlet"""
26
+ """If this class is returned, a SystemExit happened while in the code
27
+ greenlet"""
24
28
25
29
26
30
class RequestFromCodeGreenlet (object ):
27
31
"""Message from the code greenlet"""
28
32
33
+
29
34
class Wait (RequestFromCodeGreenlet ):
30
35
"""Running code would like the main loop to run for a bit"""
31
36
37
+
32
38
class Refresh (RequestFromCodeGreenlet ):
33
39
"""Running code would like the main loop to refresh the display"""
34
40
41
+
35
42
class Done (RequestFromCodeGreenlet ):
36
43
"""Running code is done running"""
37
44
45
+
38
46
class Unfinished (RequestFromCodeGreenlet ):
39
47
"""Source code wasn't executed because it wasn't fully formed"""
40
48
49
+
41
50
class SystemExitRequest (RequestFromCodeGreenlet ):
42
51
"""Running code raised a SystemExit"""
43
52
53
+
44
54
class CodeRunner (object ):
45
55
"""Runs user code in an interpreter.
46
56
@@ -67,31 +77,35 @@ class CodeRunner(object):
67
77
just passes whatever is passed in to run_code(for_code) to the
68
78
code greenlet
69
79
"""
70
- def __init__ (self , interp = None , request_refresh = lambda :None ):
80
+ def __init__ (self , interp = None , request_refresh = lambda : None ):
71
81
"""
72
82
interp is an interpreter object to use. By default a new one is
73
83
created.
74
84
75
- request_refresh is a function that will be called each time
76
- the running code asks for a refresh - to, for example, update the screen.
85
+ request_refresh is a function that will be called each time the running
86
+ code asks for a refresh - to, for example, update the screen.
77
87
"""
78
88
self .interp = interp or code .InteractiveInterpreter ()
79
89
self .source = None
80
90
self .main_greenlet = greenlet .getcurrent ()
81
91
self .code_greenlet = None
82
92
self .request_refresh = request_refresh
83
- self .code_is_waiting = False # waiting for response from main thread
84
- self .sigint_happened_in_main_greenlet = False # sigint happened while in main thread
93
+ # waiting for response from main thread
94
+ self .code_is_waiting = False
95
+ # sigint happened while in main thread
96
+ self .sigint_happened_in_main_greenlet = False
85
97
self .orig_sigint_handler = None
86
98
87
99
@property
88
100
def running (self ):
89
- """Returns greenlet if code has been loaded greenlet has been started"""
101
+ """Returns greenlet if code has been loaded greenlet has been
102
+ started"""
90
103
return self .source and self .code_greenlet
91
104
92
105
def load_code (self , source ):
93
106
"""Prep code to be run"""
94
- assert self .source is None , "you shouldn't load code when some is already running"
107
+ assert self .source is None , "you shouldn't load code when some is " \
108
+ "already running"
95
109
self .source = source
96
110
self .code_greenlet = None
97
111
@@ -126,7 +140,8 @@ def run_code(self, for_code=None):
126
140
127
141
logger .debug ('request received from code was %r' , request )
128
142
if not issubclass (request , RequestFromCodeGreenlet ):
129
- raise ValueError ("Not a valid value from code greenlet: %r" % request )
143
+ raise ValueError ("Not a valid value from code greenlet: %r" %
144
+ request )
130
145
if request in [Wait , Refresh ]:
131
146
self .code_is_waiting = True
132
147
if request == Refresh :
@@ -142,12 +157,14 @@ def run_code(self, for_code=None):
142
157
raise SystemExitFromCodeGreenlet ()
143
158
144
159
def sigint_handler (self , * args ):
145
- """SIGINT handler to use while code is running or request being fulfilled"""
160
+ """SIGINT handler to use while code is running or request being
161
+ fulfilled"""
146
162
if greenlet .getcurrent () is self .code_greenlet :
147
163
logger .debug ('sigint while running user code!' )
148
164
raise KeyboardInterrupt ()
149
165
else :
150
- logger .debug ('sigint while fulfilling code request sigint handler running!' )
166
+ logger .debug ('sigint while fulfilling code request sigint handler '
167
+ 'running!' )
151
168
self .sigint_happened_in_main_greenlet = True
152
169
153
170
def _blocking_run_code (self ):
@@ -170,18 +187,22 @@ def request_from_main_greenlet(self, force_refresh=False):
170
187
raise KeyboardInterrupt ()
171
188
return value
172
189
190
+
173
191
class FakeOutput (object ):
174
192
def __init__ (self , coderunner , on_write ):
175
193
self .coderunner = coderunner
176
194
self .on_write = on_write
195
+
177
196
def write (self , * args , ** kwargs ):
178
197
self .on_write (* args , ** kwargs )
179
198
return self .coderunner .request_from_main_greenlet (force_refresh = True )
199
+
180
200
def writelines (self , l ):
181
201
for s in l :
182
202
self .write (s )
203
+
183
204
def flush (self ):
184
205
pass
206
+
185
207
def isatty (self ):
186
208
return True
187
-
0 commit comments