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
33
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.
67
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.
1011"""
1112
1213import code
1617
1718logger = logging .getLogger (__name__ )
1819
20+
1921class SigintHappened (object ):
2022 """If this class is returned, a SIGINT happened while the main greenlet"""
2123
24+
2225class 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"""
2428
2529
2630class RequestFromCodeGreenlet (object ):
2731 """Message from the code greenlet"""
2832
33+
2934class Wait (RequestFromCodeGreenlet ):
3035 """Running code would like the main loop to run for a bit"""
3136
37+
3238class Refresh (RequestFromCodeGreenlet ):
3339 """Running code would like the main loop to refresh the display"""
3440
41+
3542class Done (RequestFromCodeGreenlet ):
3643 """Running code is done running"""
3744
45+
3846class Unfinished (RequestFromCodeGreenlet ):
3947 """Source code wasn't executed because it wasn't fully formed"""
4048
49+
4150class SystemExitRequest (RequestFromCodeGreenlet ):
4251 """Running code raised a SystemExit"""
4352
53+
4454class CodeRunner (object ):
4555 """Runs user code in an interpreter.
4656
@@ -67,31 +77,35 @@ class CodeRunner(object):
6777 just passes whatever is passed in to run_code(for_code) to the
6878 code greenlet
6979 """
70- def __init__ (self , interp = None , request_refresh = lambda :None ):
80+ def __init__ (self , interp = None , request_refresh = lambda : None ):
7181 """
7282 interp is an interpreter object to use. By default a new one is
7383 created.
7484
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.
7787 """
7888 self .interp = interp or code .InteractiveInterpreter ()
7989 self .source = None
8090 self .main_greenlet = greenlet .getcurrent ()
8191 self .code_greenlet = None
8292 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
8597 self .orig_sigint_handler = None
8698
8799 @property
88100 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"""
90103 return self .source and self .code_greenlet
91104
92105 def load_code (self , source ):
93106 """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"
95109 self .source = source
96110 self .code_greenlet = None
97111
@@ -126,7 +140,8 @@ def run_code(self, for_code=None):
126140
127141 logger .debug ('request received from code was %r' , request )
128142 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 )
130145 if request in [Wait , Refresh ]:
131146 self .code_is_waiting = True
132147 if request == Refresh :
@@ -142,12 +157,14 @@ def run_code(self, for_code=None):
142157 raise SystemExitFromCodeGreenlet ()
143158
144159 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"""
146162 if greenlet .getcurrent () is self .code_greenlet :
147163 logger .debug ('sigint while running user code!' )
148164 raise KeyboardInterrupt ()
149165 else :
150- logger .debug ('sigint while fulfilling code request sigint handler running!' )
166+ logger .debug ('sigint while fulfilling code request sigint handler '
167+ 'running!' )
151168 self .sigint_happened_in_main_greenlet = True
152169
153170 def _blocking_run_code (self ):
@@ -170,18 +187,22 @@ def request_from_main_greenlet(self, force_refresh=False):
170187 raise KeyboardInterrupt ()
171188 return value
172189
190+
173191class FakeOutput (object ):
174192 def __init__ (self , coderunner , on_write ):
175193 self .coderunner = coderunner
176194 self .on_write = on_write
195+
177196 def write (self , * args , ** kwargs ):
178197 self .on_write (* args , ** kwargs )
179198 return self .coderunner .request_from_main_greenlet (force_refresh = True )
199+
180200 def writelines (self , l ):
181201 for s in l :
182202 self .write (s )
203+
183204 def flush (self ):
184205 pass
206+
185207 def isatty (self ):
186208 return True
187-
0 commit comments