OLD | NEW |
---|---|
(Empty) | |
1 """A simple shell that uses the IPython messaging system.""" | |
Sam Clegg
2014/02/18 23:39:31
Copyright
| |
2 | |
3 import json | |
4 import logging | |
5 import sys | |
6 | |
7 import IPython | |
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC | |
9 from IPython.utils.traitlets import Type, Dict, Instance | |
10 from IPython.core.displayhook import DisplayHook | |
11 from IPython.utils.jsonutil import json_clean, encode_images | |
12 from IPython.core.displaypub import DisplayPublisher | |
13 from IPython.config.configurable import Configurable | |
14 | |
15 # module defined in shell.cc for communicating via pepper API | |
16 import ppmessage | |
17 | |
18 def sendMessage(socket_name, msg_type, parent_header=None, content=None): | |
19 if parent_header is None: | |
20 parent_header = {} | |
21 if content is None: | |
22 content = {} | |
23 msg = { | |
24 'header': {'msg_type': msg_type}, | |
25 'parent_header': parent_header, | |
26 'content': content | |
27 } | |
28 ppmessage._PostJSONMessage(socket_name, json.dumps(msg)) | |
29 | |
30 class MsgOutStream(object): | |
31 """Class to overrides stderr and stdout.""" | |
32 | |
33 def __init__(self, stream_name): | |
34 self._stream_name = stream_name | |
35 self._parent_header = {} | |
36 | |
37 def SetParentHeader(self, parent_header): | |
38 self._parent_header = parent_header | |
39 | |
40 def close(self): | |
41 pass | |
42 | |
43 def flush(self): | |
44 pass | |
45 | |
46 def write(self, string): | |
47 sendMessage('iopub', 'stream', parent_header=self._parent_header, | |
48 content={'name': self._stream_name, 'data': string}) | |
49 | |
50 def writelines(self, sequence): | |
51 for string in sequence: | |
52 self.write(string) | |
53 | |
54 # override sys.stdout and sys.stderr to broadcast on iopub | |
55 stdout_stream = MsgOutStream('stdout') | |
56 stderr_stream = MsgOutStream('stderr') | |
57 sys_stdout = sys.stdout | |
58 sys_stderr = sys.stderr | |
59 sys.stdout = stdout_stream | |
60 sys.stderr = stderr_stream | |
61 | |
62 | |
63 | |
64 class PepperShellDisplayHook(DisplayHook): | |
65 parent_header = Dict({}) | |
66 | |
67 def set_parent_header(self, parent_header): | |
68 """Set the parent for outbound messages.""" | |
69 self.parent_header = parent_header | |
70 | |
71 def start_displayhook(self): | |
72 self.content = {} | |
73 | |
74 def write_output_prompt(self): | |
75 self.content['execution_count'] = self.prompt_count | |
76 | |
77 def write_format_data(self, format_dict, md_dict=None): | |
78 self.content['data'] = encode_images(format_dict) | |
79 self.content['metadata'] = md_dict | |
80 | |
81 def finish_displayhook(self): | |
82 sys.stdout.flush() | |
83 sys.stderr.flush() | |
84 sendMessage('iopub', 'pyout', parent_header=self.parent_header, | |
85 content=self.content) | |
86 self.content = None | |
87 | |
88 | |
89 class PepperDisplayPublisher(DisplayPublisher): | |
90 parent_header = Dict({}) | |
91 | |
92 def set_parent_header(self, parent_header): | |
93 self.parent_header = parent_header | |
94 | |
95 def _flush_streams(self): | |
96 """flush IO Streams prior to display""" | |
97 sys.stdout.flush() | |
98 sys.stderr.flush() | |
99 | |
100 def publish(self, source, data, metadata=None): | |
101 self._flush_streams() | |
102 if metadata is None: | |
103 metadata = {} | |
104 self._validate_data(source, data, metadata) | |
105 content = {} | |
106 content['source'] = source | |
107 content['data'] = encode_images(data) | |
108 content['metadata'] = metadata | |
109 sendMessage('iopub', 'display_data', content=json_clean(content), | |
110 parent_header=self.parent_header) | |
111 | |
112 def clear_output(self, stdout=True, stderr=True, other=True): | |
113 content = dict(stdout=stdout, stderr=stderr, other=other) | |
114 | |
115 if stdout: | |
116 sys.stdout.write('\r') | |
117 if stderr: | |
118 sys.stderr.write('\r') | |
119 | |
120 self._flush_streams() | |
121 sendMessage('iopub', 'clear_output', content=content, | |
122 parent_header=self.parent_header) | |
123 | |
124 | |
125 class PepperInteractiveShell(InteractiveShell): | |
126 """A subclass of InteractiveShell for the Pepper Messagin API.""" | |
127 displayhook_class = Type(PepperShellDisplayHook) | |
128 display_pub_class = Type(PepperDisplayPublisher) | |
129 @staticmethod | |
130 def enable_gui(gui): | |
131 pass | |
132 | |
133 | |
134 InteractiveShellABC.register(PepperInteractiveShell) | |
135 | |
136 class PepperKernel(Configurable): | |
137 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
138 shell_class = Type(PepperInteractiveShell) | |
139 | |
140 def __init__(self): | |
141 self.shell = self.shell_class.instance(parent=self) | |
142 self.shell.run_cell(""" | |
143 import os | |
144 matplotlib_config_dir = '/mplconfigdir' | |
145 os.environ['XDG_CONFIG_HOME'] = matplotlib_config_dir | |
146 os.environ['TMP'] = '' | |
147 import matplotlib | |
148 import matplotlib.cbook | |
149 """) | |
150 | |
151 execution_count = 1 | |
152 | |
153 shell = PepperKernel().shell | |
154 | |
155 while 1: | |
156 sendMessage('iopub', 'status', content={'execution_state': 'idle'}) | |
157 msg = json.loads(ppmessage._AcquireJSONMessageWait()) | |
158 sendMessage('iopub', 'status', content={'execution_state': 'busy'}) | |
159 | |
160 if not 'header' in msg: | |
161 continue | |
162 request_header = msg['header'] | |
163 if not 'msg_type' in request_header: | |
164 continue | |
165 msg_type = request_header['msg_type'] | |
166 if msg_type == 'execute_request': | |
167 try: | |
168 content = msg[u'content'] | |
169 code = content[u'code'] | |
170 silent = content[u'silent'] | |
171 store_history = content.get(u'store_history', not silent) | |
172 except: | |
173 self.log.error("Got bad msg: ") | |
174 self.log.error("%s", msg) | |
175 continue | |
176 | |
177 # Let output streams know which message the output is for | |
178 stdout_stream.SetParentHeader(request_header) | |
179 stderr_stream.SetParentHeader(request_header) | |
180 shell.displayhook.set_parent_header(request_header) | |
181 shell.display_pub.set_parent_header(request_header) | |
182 | |
183 status = 'ok' | |
184 content = {} | |
185 try: | |
186 shell.run_cell(msg['content']['code'], | |
187 store_history=store_history, | |
188 silent=silent) | |
189 except Exception, ex: | |
190 status = 'error' | |
191 logging.exception('Exception occured while running cell') | |
192 | |
193 content = {'status': status, | |
194 'execution_count': execution_count} | |
195 | |
196 if status == 'ok': | |
197 content['payload'] = [] | |
198 content['user_variables'] = {} | |
199 content['user_expressions'] = {} | |
200 elif status == 'error': | |
201 content['ename'] = type(ex).__name__ | |
202 content['evalue'] = str(ex) | |
203 content['traceback'] = [] | |
204 | |
205 execution_count += 1 | |
206 if status == 'error': | |
207 sendMessage('iopub', 'pyerr', parent_header=request_header, | |
208 content={ | |
209 'execution_count': execution_count, | |
210 'ename': type(ex).__name__, | |
211 'evalue': str(ex), | |
212 'traceback': [] | |
213 } | |
214 ) | |
215 sendMessage('shell', 'execute_reply', parent_header=request_header, | |
216 content=content) | |
217 elif msg_type == 'complete_request': | |
218 c = msg['content'] | |
219 try: | |
220 cpos = int(c['cursor_pos']) | |
221 except: | |
222 cpos = len(c['text']) | |
223 if cpos == 0: | |
224 cpos = len(c['line']) | |
225 txt, matches = shell.complete(c['text'], c['line'], cpos) | |
226 sendMessage('shell', 'complete_reply', | |
227 parent_header = request_header, | |
228 content = { | |
229 'matches': matches, | |
230 'matched_text': txt, | |
231 'status': 'ok' | |
232 }) | |
233 elif msg_type == 'restart': | |
234 # break out of this loop, ending this program. | |
235 # The main event loop in shell.cc will then | |
236 # run this program again. | |
237 break | |
238 elif msg_type == 'kill': | |
239 # Raise an exception so that the function | |
240 # running this script will return -1, resulting | |
241 # in no restart of this script. | |
242 raise RuntimeError | |
OLD | NEW |