11import code
2- import Queue
32import signal
43import sys
5- import threading
4+ import greenlet
65import logging
76
87class SigintHappened (object ):
@@ -16,54 +15,51 @@ class CodeRunner(object):
1615 def __init__ (self , interp = None , stuff_a_refresh_request = lambda :None ):
1716 self .interp = interp or code .InteractiveInterpreter ()
1817 self .source = None
19- self .code_thread = None
20- self .requests_from_code_thread = Queue .Queue (maxsize = 1 )
21- self .responses_for_code_thread = Queue .Queue (maxsize = 1 )
18+ self .main_greenlet = greenlet .getcurrent ()
19+ self .code_greenlet = None
2220 self .stuff_a_refresh_request = stuff_a_refresh_request
2321 self .code_is_waiting = False
2422 self .sigint_happened = False
2523 self .orig_sigint_handler = None
2624
2725 @property
2826 def running (self ):
29- return self .source and self .code_thread
27+ return self .source and self .code_greenlet
3028
3129 def load_code (self , source ):
3230 """Prep code to be run"""
3331 self .source = source
34- self .code_thread = None
32+ self .code_greenlet = None
3533
3634 def _unload_code (self ):
3735 """Called when done running code"""
3836 self .source = None
39- self .code_thread = None
37+ self .code_greenlet = None
4038 self .code_is_waiting = False
4139
4240 def run_code (self , for_code = None ):
4341 """Returns Truthy values if code finishes, False otherwise
4442
45- if for_code is provided, send that value to the code thread
43+ if for_code is provided, send that value to the code greenlet
4644 if source code is complete, returns "done"
4745 if source code is incomplete, returns "unfinished"
4846 """
49- if self .code_thread is None :
47+ if self .code_greenlet is None :
5048 assert self .source is not None
51- self .code_thread = threading .Thread (target = self ._blocking_run_code , name = 'codethread' )
52- self .code_thread .daemon = True
49+ self .code_greenlet = greenlet .greenlet (self ._blocking_run_code )
5350 self .orig_sigint_handler = signal .getsignal (signal .SIGINT )
5451 signal .signal (signal .SIGINT , self .sigint_handler )
55- self .code_thread . start ()
52+ request = self .code_greenlet . switch ()
5653 else :
5754 assert self .code_is_waiting
5855 self .code_is_waiting = False
5956 signal .signal (signal .SIGINT , self .sigint_handler )
6057 if self .sigint_happened :
6158 self .sigint_happened = False
62- self .responses_for_code_thread . put (SigintHappened )
59+ request = self .code_greenlet . switch (SigintHappened )
6360 else :
64- self .responses_for_code_thread . put (for_code )
61+ request = self .code_greenlet . switch (for_code )
6562
66- request = self .requests_from_code_thread .get ()
6763 if request in ['wait' , 'refresh' ]:
6864 self .code_is_waiting = True
6965 if request == 'refresh' :
@@ -78,10 +74,10 @@ def run_code(self, for_code=None):
7874 self ._unload_code ()
7975 raise SystemExitFromCodeThread ()
8076 else :
81- raise ValueError ("Not a valid request_from_code_thread value: %r" % request )
77+ raise ValueError ("Not a valid value from code greenlet : %r" % request )
8278
8379 def sigint_handler (self , * args ):
84- if threading . current_thread () is self .code_thread :
80+ if greenlet . getcurrent () is self .code_greenlet :
8581 logging .debug ('sigint while running user code!' )
8682 raise KeyboardInterrupt ()
8783 else :
@@ -92,25 +88,22 @@ def _blocking_run_code(self):
9288 try :
9389 unfinished = self .interp .runsource (self .source )
9490 except SystemExit :
95- self .requests_from_code_thread .put ('SystemExit' )
96- return
97- self .requests_from_code_thread .put ('unfinished' if unfinished else 'done' )
91+ return 'SystemExit'
92+ return 'unfinished' if unfinished else 'done'
9893
9994 def wait_and_get_value (self ):
10095 """Return the argument passed in to .run_code(for_code)
10196
10297 Nothing means calls to run_code must be...
10398 """
104- self .requests_from_code_thread .put ('wait' )
105- value = self .responses_for_code_thread .get ()
99+ value = self .main_greenlet .switch ('wait' )
106100 if value is SigintHappened :
107101 raise KeyboardInterrupt ()
108102 return value
109103
110104 def refresh_and_get_value (self ):
111105 """Returns the argument passed in to .run_code(for_code) """
112- self .requests_from_code_thread .put ('refresh' )
113- value = self .responses_for_code_thread .get ()
106+ value = self .main_greenlet .switch ('refresh' )
114107 if value is SigintHappened :
115108 raise KeyboardInterrupt ()
116109 return value
0 commit comments