1
1
import code
2
- import Queue
3
2
import signal
4
3
import sys
5
- import threading
4
+ import greenlet
6
5
import logging
7
6
8
7
class SigintHappened (object ):
@@ -16,54 +15,51 @@ class CodeRunner(object):
16
15
def __init__ (self , interp = None , stuff_a_refresh_request = lambda :None ):
17
16
self .interp = interp or code .InteractiveInterpreter ()
18
17
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
22
20
self .stuff_a_refresh_request = stuff_a_refresh_request
23
21
self .code_is_waiting = False
24
22
self .sigint_happened = False
25
23
self .orig_sigint_handler = None
26
24
27
25
@property
28
26
def running (self ):
29
- return self .source and self .code_thread
27
+ return self .source and self .code_greenlet
30
28
31
29
def load_code (self , source ):
32
30
"""Prep code to be run"""
33
31
self .source = source
34
- self .code_thread = None
32
+ self .code_greenlet = None
35
33
36
34
def _unload_code (self ):
37
35
"""Called when done running code"""
38
36
self .source = None
39
- self .code_thread = None
37
+ self .code_greenlet = None
40
38
self .code_is_waiting = False
41
39
42
40
def run_code (self , for_code = None ):
43
41
"""Returns Truthy values if code finishes, False otherwise
44
42
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
46
44
if source code is complete, returns "done"
47
45
if source code is incomplete, returns "unfinished"
48
46
"""
49
- if self .code_thread is None :
47
+ if self .code_greenlet is None :
50
48
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 )
53
50
self .orig_sigint_handler = signal .getsignal (signal .SIGINT )
54
51
signal .signal (signal .SIGINT , self .sigint_handler )
55
- self .code_thread . start ()
52
+ request = self .code_greenlet . switch ()
56
53
else :
57
54
assert self .code_is_waiting
58
55
self .code_is_waiting = False
59
56
signal .signal (signal .SIGINT , self .sigint_handler )
60
57
if self .sigint_happened :
61
58
self .sigint_happened = False
62
- self .responses_for_code_thread . put (SigintHappened )
59
+ request = self .code_greenlet . switch (SigintHappened )
63
60
else :
64
- self .responses_for_code_thread . put (for_code )
61
+ request = self .code_greenlet . switch (for_code )
65
62
66
- request = self .requests_from_code_thread .get ()
67
63
if request in ['wait' , 'refresh' ]:
68
64
self .code_is_waiting = True
69
65
if request == 'refresh' :
@@ -78,10 +74,10 @@ def run_code(self, for_code=None):
78
74
self ._unload_code ()
79
75
raise SystemExitFromCodeThread ()
80
76
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 )
82
78
83
79
def sigint_handler (self , * args ):
84
- if threading . current_thread () is self .code_thread :
80
+ if greenlet . getcurrent () is self .code_greenlet :
85
81
logging .debug ('sigint while running user code!' )
86
82
raise KeyboardInterrupt ()
87
83
else :
@@ -92,25 +88,22 @@ def _blocking_run_code(self):
92
88
try :
93
89
unfinished = self .interp .runsource (self .source )
94
90
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'
98
93
99
94
def wait_and_get_value (self ):
100
95
"""Return the argument passed in to .run_code(for_code)
101
96
102
97
Nothing means calls to run_code must be...
103
98
"""
104
- self .requests_from_code_thread .put ('wait' )
105
- value = self .responses_for_code_thread .get ()
99
+ value = self .main_greenlet .switch ('wait' )
106
100
if value is SigintHappened :
107
101
raise KeyboardInterrupt ()
108
102
return value
109
103
110
104
def refresh_and_get_value (self ):
111
105
"""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' )
114
107
if value is SigintHappened :
115
108
raise KeyboardInterrupt ()
116
109
return value
0 commit comments