X Tutup
Skip to content

Commit 8e2c0fc

Browse files
use classes instead of strings
1 parent 45d9b9e commit 8e2c0fc

File tree

3 files changed

+51
-28
lines changed

3 files changed

+51
-28
lines changed

bpython/curtsies.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
Terminal = curtsies.terminal.Terminal
1313

1414
from bpython.curtsiesfrontend.repl import Repl
15-
from bpython.curtsiesfrontend.coderunner import SystemExitFromCodeThread
15+
from bpython.curtsiesfrontend.coderunner import SystemExitFromCodeGreenlet
1616
from bpython import args as bpargs
1717
from bpython.translations import _
1818

@@ -65,7 +65,7 @@ def mainloop(config, locals_, banner, interp=None, paste=None):
6565
def process_event(e):
6666
try:
6767
repl.process_event(e)
68-
except SystemExitFromCodeThread:
68+
except SystemExitFromCodeGreenlet:
6969
array, cursor_pos = repl.paint(about_to_exit=True, user_quit=True)
7070
term.render_to_terminal(array, cursor_pos)
7171
raise

bpython/curtsiesfrontend/coderunner.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""For running Python code that could interrupt itself at any time
2-
32
in order to, for example, ask for a read on stdin, or a write on stdout
43
5-
The CodeRunner spawns a greenlet to run code it, and that code can suspend
6-
its own execution to ask the main thread to refresh the display or get information.
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.
6+
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.
710
"""
811

912
import code
@@ -13,17 +16,35 @@
1316
import logging
1417

1518
class SigintHappened(object):
16-
"""If this class is returned, a SIGINT happened while the main thread"""
19+
"""If this class is returned, a SIGINT happened while the main greenlet"""
20+
21+
class SystemExitFromCodeGreenlet(SystemExit):
22+
"""If this class is returned, a SystemExit happened while in the code greenlet"""
23+
24+
25+
class RequestFromCodeGreenlet(object):
26+
"""Message from the code greenlet"""
27+
28+
class Wait(RequestFromCodeGreenlet):
29+
"""Running code would like the main loop to run for a bit"""
1730

18-
class SystemExitFromCodeThread(SystemExit):
19-
"""If this class is returned, a SystemExit happened while in the code thread"""
20-
pass
31+
class Refresh(RequestFromCodeGreenlet):
32+
"""Running code would like the main loop to refresh the display"""
33+
34+
class Done(RequestFromCodeGreenlet):
35+
"""Running code is done running"""
36+
37+
class Unfinished(RequestFromCodeGreenlet):
38+
"""Source code wasn't executed because it wasn't fully formed"""
39+
40+
class SystemExitRequest(RequestFromCodeGreenlet):
41+
"""Running code raised a SystemExit"""
2142

2243
class CodeRunner(object):
2344
"""Runs user code in an interpreter.
2445
2546
Running code requests a refresh by calling refresh_and_get_value(), which
26-
suspends execution of the code and switches back to the main thread
47+
suspends execution of the code and switches back to the main greenlet
2748
2849
After load_code() is called with the source code to be run,
2950
the run_code() method should be called to start running the code.
@@ -37,10 +58,12 @@ class CodeRunner(object):
3758
3859
Once the screen refresh has occurred or the requested user input
3960
has been gathered, run_code() should be called again, passing in any
40-
requested user input. This continues until run_code returns 'done'.
61+
requested user input. This continues until run_code returns Done.
4162
42-
Question: How does the caller of run_code know that user input ought
43-
to be returned?
63+
The code greenlet is responsible for telling the main greenlet
64+
what it wants returned in the next run_code call - CodeRunner
65+
just passes whatever is passed in to run_code(for_code) to the
66+
code greenlet
4467
"""
4568
def __init__(self, interp=None, stuff_a_refresh_request=lambda:None):
4669
"""
@@ -56,7 +79,7 @@ def __init__(self, interp=None, stuff_a_refresh_request=lambda:None):
5679
self.code_greenlet = None
5780
self.stuff_a_refresh_request = stuff_a_refresh_request
5881
self.code_is_waiting = False # waiting for response from main thread
59-
self.sigint_happened = False
82+
self.sigint_happened_in_main_greenlet = False # sigint happened while in main thread
6083
self.orig_sigint_handler = None
6184

6285
@property
@@ -93,27 +116,27 @@ def run_code(self, for_code=None):
93116
assert self.code_is_waiting
94117
self.code_is_waiting = False
95118
signal.signal(signal.SIGINT, self.sigint_handler)
96-
if self.sigint_happened:
97-
self.sigint_happened = False
119+
if self.sigint_happened_in_main_greenlet:
120+
self.sigint_happened_in_main_greenlet = False
98121
request = self.code_greenlet.switch(SigintHappened)
99122
else:
100123
request = self.code_greenlet.switch(for_code)
101124

102-
if request in ['wait', 'refresh']:
125+
if not issubclass(request, RequestFromCodeGreenlet):
126+
raise ValueError("Not a valid value from code greenlet: %r" % request)
127+
if request in [Wait, Refresh]:
103128
self.code_is_waiting = True
104-
if request == 'refresh':
129+
if request == Refresh:
105130
self.stuff_a_refresh_request()
106131
return False
107-
elif request in ['done', 'unfinished']:
132+
elif request in [Done, Unfinished]:
108133
self._unload_code()
109134
signal.signal(signal.SIGINT, self.orig_sigint_handler)
110135
self.orig_sigint_handler = None
111136
return request
112-
elif request in ['SystemExit']: #use the object?
137+
elif request in [SystemExitRequest]:
113138
self._unload_code()
114-
raise SystemExitFromCodeThread()
115-
else:
116-
raise ValueError("Not a valid value from code greenlet: %r" % request)
139+
raise SystemExitFromCodeGreenlet()
117140

118141
def sigint_handler(self, *args):
119142
"""SIGINT handler to use while code is running or request being fufilled"""
@@ -128,22 +151,22 @@ def _blocking_run_code(self):
128151
try:
129152
unfinished = self.interp.runsource(self.source)
130153
except SystemExit:
131-
return 'SystemExit'
132-
return 'unfinished' if unfinished else 'done'
154+
return SystemExitRequest
155+
return Unfinished if unfinished else Done
133156

134157
def wait_and_get_value(self):
135158
"""Return the argument passed in to .run_code(for_code)
136159
137160
Nothing means calls to run_code must be...
138161
"""
139-
value = self.main_greenlet.switch('wait')
162+
value = self.main_greenlet.switch(Wait)
140163
if value is SigintHappened:
141164
raise KeyboardInterrupt()
142165
return value
143166

144167
def refresh_and_get_value(self):
145168
"""Returns the argument passed in to .run_code(for_code) """
146-
value = self.main_greenlet.switch('refresh')
169+
value = self.main_greenlet.switch(Refresh)
147170
if value is SigintHappened:
148171
raise KeyboardInterrupt()
149172
return value

bpython/curtsiesfrontend/repl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def process_event(self, e):
5555
elif e in rl_char_sequences:
5656
self.cursor_offset_in_line, self.current_line = rl_char_sequences[e](self.cursor_offset_in_line, self.current_line)
5757
elif isinstance(e, events.SigIntEvent):
58-
self.coderunner.sigint_happened = True
58+
self.coderunner.sigint_happened_in_main_greenlet = True
5959
self.has_focus = False
6060
self.current_line = ''
6161
self.cursor_offset_in_line = 0

0 commit comments

Comments
 (0)
X Tutup