##// END OF EJS Templates
name isn't part of inspect_reply...
Min RK -
Show More
@@ -1,374 +1,373 b''
1 1 """Adapters for IPython msg spec versions."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import json
7 7
8 8 from IPython.core.release import kernel_protocol_version_info
9 9 from IPython.utils.tokenutil import token_at_cursor
10 10
11 11
12 12 def code_to_line(code, cursor_pos):
13 13 """Turn a multiline code block and cursor position into a single line
14 14 and new cursor position.
15 15
16 16 For adapting ``complete_`` and ``object_info_request``.
17 17 """
18 18 if not code:
19 19 return "", 0
20 20 for line in code.splitlines(True):
21 21 n = len(line)
22 22 if cursor_pos > n:
23 23 cursor_pos -= n
24 24 else:
25 25 break
26 26 return line, cursor_pos
27 27
28 28
29 29 class Adapter(object):
30 30 """Base class for adapting messages
31 31
32 32 Override message_type(msg) methods to create adapters.
33 33 """
34 34
35 35 msg_type_map = {}
36 36
37 37 def update_header(self, msg):
38 38 return msg
39 39
40 40 def update_metadata(self, msg):
41 41 return msg
42 42
43 43 def update_msg_type(self, msg):
44 44 header = msg['header']
45 45 msg_type = header['msg_type']
46 46 if msg_type in self.msg_type_map:
47 47 msg['msg_type'] = header['msg_type'] = self.msg_type_map[msg_type]
48 48 return msg
49 49
50 50 def handle_reply_status_error(self, msg):
51 51 """This will be called *instead of* the regular handler
52 52
53 53 on any reply with status != ok
54 54 """
55 55 return msg
56 56
57 57 def __call__(self, msg):
58 58 msg = self.update_header(msg)
59 59 msg = self.update_metadata(msg)
60 60 msg = self.update_msg_type(msg)
61 61 header = msg['header']
62 62
63 63 handler = getattr(self, header['msg_type'], None)
64 64 if handler is None:
65 65 return msg
66 66
67 67 # handle status=error replies separately (no change, at present)
68 68 if msg['content'].get('status', None) in {'error', 'aborted'}:
69 69 return self.handle_reply_status_error(msg)
70 70 return handler(msg)
71 71
72 72 def _version_str_to_list(version):
73 73 """convert a version string to a list of ints
74 74
75 75 non-int segments are excluded
76 76 """
77 77 v = []
78 78 for part in version.split('.'):
79 79 try:
80 80 v.append(int(part))
81 81 except ValueError:
82 82 pass
83 83 return v
84 84
85 85 class V5toV4(Adapter):
86 86 """Adapt msg protocol v5 to v4"""
87 87
88 88 version = '4.1'
89 89
90 90 msg_type_map = {
91 91 'execute_result' : 'pyout',
92 92 'execute_input' : 'pyin',
93 93 'error' : 'pyerr',
94 94 'inspect_request' : 'object_info_request',
95 95 'inspect_reply' : 'object_info_reply',
96 96 }
97 97
98 98 def update_header(self, msg):
99 99 msg['header'].pop('version', None)
100 100 return msg
101 101
102 102 # shell channel
103 103
104 104 def kernel_info_reply(self, msg):
105 105 v4c = {}
106 106 content = msg['content']
107 107 for key in ('language_version', 'protocol_version'):
108 108 if key in content:
109 109 v4c[key] = _version_str_to_list(content[key])
110 110 if content.get('implementation', '') == 'ipython' \
111 111 and 'implementation_version' in content:
112 112 v4c['ipython_version'] = _version_str_to_list(content['implementation_version'])
113 113 language_info = content.get('language_info', {})
114 114 language = language_info.get('name', '')
115 115 v4c.setdefault('language', language)
116 116 if 'version' in language_info:
117 117 v4c.setdefault('language_version', _version_str_to_list(language_info['version']))
118 118 msg['content'] = v4c
119 119 return msg
120 120
121 121 def execute_request(self, msg):
122 122 content = msg['content']
123 123 content.setdefault('user_variables', [])
124 124 return msg
125 125
126 126 def execute_reply(self, msg):
127 127 content = msg['content']
128 128 content.setdefault('user_variables', {})
129 129 # TODO: handle payloads
130 130 return msg
131 131
132 132 def complete_request(self, msg):
133 133 content = msg['content']
134 134 code = content['code']
135 135 cursor_pos = content['cursor_pos']
136 136 line, cursor_pos = code_to_line(code, cursor_pos)
137 137
138 138 new_content = msg['content'] = {}
139 139 new_content['text'] = ''
140 140 new_content['line'] = line
141 141 new_content['block'] = None
142 142 new_content['cursor_pos'] = cursor_pos
143 143 return msg
144 144
145 145 def complete_reply(self, msg):
146 146 content = msg['content']
147 147 cursor_start = content.pop('cursor_start')
148 148 cursor_end = content.pop('cursor_end')
149 149 match_len = cursor_end - cursor_start
150 150 content['matched_text'] = content['matches'][0][:match_len]
151 151 content.pop('metadata', None)
152 152 return msg
153 153
154 154 def object_info_request(self, msg):
155 155 content = msg['content']
156 156 code = content['code']
157 157 cursor_pos = content['cursor_pos']
158 158 line, _ = code_to_line(code, cursor_pos)
159 159
160 160 new_content = msg['content'] = {}
161 161 new_content['oname'] = token_at_cursor(code, cursor_pos)
162 162 new_content['detail_level'] = content['detail_level']
163 163 return msg
164 164
165 165 def object_info_reply(self, msg):
166 166 """inspect_reply can't be easily backward compatible"""
167 167 msg['content'] = {'found' : False, 'oname' : 'unknown'}
168 168 return msg
169 169
170 170 # iopub channel
171 171
172 172 def stream(self, msg):
173 173 content = msg['content']
174 174 content['data'] = content.pop('text')
175 175 return msg
176 176
177 177 def display_data(self, msg):
178 178 content = msg['content']
179 179 content.setdefault("source", "display")
180 180 data = content['data']
181 181 if 'application/json' in data:
182 182 try:
183 183 data['application/json'] = json.dumps(data['application/json'])
184 184 except Exception:
185 185 # warn?
186 186 pass
187 187 return msg
188 188
189 189 # stdin channel
190 190
191 191 def input_request(self, msg):
192 192 msg['content'].pop('password', None)
193 193 return msg
194 194
195 195
196 196 class V4toV5(Adapter):
197 197 """Convert msg spec V4 to V5"""
198 198 version = '5.0'
199 199
200 200 # invert message renames above
201 201 msg_type_map = {v:k for k,v in V5toV4.msg_type_map.items()}
202 202
203 203 def update_header(self, msg):
204 204 msg['header']['version'] = self.version
205 205 return msg
206 206
207 207 # shell channel
208 208
209 209 def kernel_info_reply(self, msg):
210 210 content = msg['content']
211 211 for key in ('protocol_version', 'ipython_version'):
212 212 if key in content:
213 213 content[key] = '.'.join(map(str, content[key]))
214 214
215 215 content.setdefault('protocol_version', '4.1')
216 216
217 217 if content['language'].startswith('python') and 'ipython_version' in content:
218 218 content['implementation'] = 'ipython'
219 219 content['implementation_version'] = content.pop('ipython_version')
220 220
221 221 language = content.pop('language')
222 222 language_info = content.setdefault('language_info', {})
223 223 language_info.setdefault('name', language)
224 224 if 'language_version' in content:
225 225 language_version = '.'.join(map(str, content.pop('language_version')))
226 226 language_info.setdefault('version', language_version)
227 227
228 228 content['banner'] = ''
229 229 return msg
230 230
231 231 def execute_request(self, msg):
232 232 content = msg['content']
233 233 user_variables = content.pop('user_variables', [])
234 234 user_expressions = content.setdefault('user_expressions', {})
235 235 for v in user_variables:
236 236 user_expressions[v] = v
237 237 return msg
238 238
239 239 def execute_reply(self, msg):
240 240 content = msg['content']
241 241 user_expressions = content.setdefault('user_expressions', {})
242 242 user_variables = content.pop('user_variables', {})
243 243 if user_variables:
244 244 user_expressions.update(user_variables)
245 245
246 246 # Pager payloads became a mime bundle
247 247 for payload in content.get('payload', []):
248 248 if payload.get('source', None) == 'page' and ('text' in payload):
249 249 if 'data' not in payload:
250 250 payload['data'] = {}
251 251 payload['data']['text/plain'] = payload.pop('text')
252 252
253 253 return msg
254 254
255 255 def complete_request(self, msg):
256 256 old_content = msg['content']
257 257
258 258 new_content = msg['content'] = {}
259 259 new_content['code'] = old_content['line']
260 260 new_content['cursor_pos'] = old_content['cursor_pos']
261 261 return msg
262 262
263 263 def complete_reply(self, msg):
264 264 # complete_reply needs more context than we have to get cursor_start and end.
265 265 # use special end=null to indicate current cursor position and negative offset
266 266 # for start relative to the cursor.
267 267 # start=None indicates that start == end (accounts for no -0).
268 268 content = msg['content']
269 269 new_content = msg['content'] = {'status' : 'ok'}
270 270 new_content['matches'] = content['matches']
271 271 if content['matched_text']:
272 272 new_content['cursor_start'] = -len(content['matched_text'])
273 273 else:
274 274 # no -0, use None to indicate that start == end
275 275 new_content['cursor_start'] = None
276 276 new_content['cursor_end'] = None
277 277 new_content['metadata'] = {}
278 278 return msg
279 279
280 280 def inspect_request(self, msg):
281 281 content = msg['content']
282 282 name = content['oname']
283 283
284 284 new_content = msg['content'] = {}
285 285 new_content['code'] = name
286 286 new_content['cursor_pos'] = len(name)
287 287 new_content['detail_level'] = content['detail_level']
288 288 return msg
289 289
290 290 def inspect_reply(self, msg):
291 291 """inspect_reply can't be easily backward compatible"""
292 292 content = msg['content']
293 293 new_content = msg['content'] = {'status' : 'ok'}
294 294 found = new_content['found'] = content['found']
295 new_content['name'] = content['oname']
296 295 new_content['data'] = data = {}
297 296 new_content['metadata'] = {}
298 297 if found:
299 298 lines = []
300 299 for key in ('call_def', 'init_definition', 'definition'):
301 300 if content.get(key, False):
302 301 lines.append(content[key])
303 302 break
304 303 for key in ('call_docstring', 'init_docstring', 'docstring'):
305 304 if content.get(key, False):
306 305 lines.append(content[key])
307 306 break
308 307 if not lines:
309 308 lines.append("<empty docstring>")
310 309 data['text/plain'] = '\n'.join(lines)
311 310 return msg
312 311
313 312 # iopub channel
314 313
315 314 def stream(self, msg):
316 315 content = msg['content']
317 316 content['text'] = content.pop('data')
318 317 return msg
319 318
320 319 def display_data(self, msg):
321 320 content = msg['content']
322 321 content.pop("source", None)
323 322 data = content['data']
324 323 if 'application/json' in data:
325 324 try:
326 325 data['application/json'] = json.loads(data['application/json'])
327 326 except Exception:
328 327 # warn?
329 328 pass
330 329 return msg
331 330
332 331 # stdin channel
333 332
334 333 def input_request(self, msg):
335 334 msg['content'].setdefault('password', False)
336 335 return msg
337 336
338 337
339 338
340 339 def adapt(msg, to_version=kernel_protocol_version_info[0]):
341 340 """Adapt a single message to a target version
342 341
343 342 Parameters
344 343 ----------
345 344
346 345 msg : dict
347 346 An IPython message.
348 347 to_version : int, optional
349 348 The target major version.
350 349 If unspecified, adapt to the current version for IPython.
351 350
352 351 Returns
353 352 -------
354 353
355 354 msg : dict
356 355 An IPython message appropriate in the new version.
357 356 """
358 357 header = msg['header']
359 358 if 'version' in header:
360 359 from_version = int(header['version'].split('.')[0])
361 360 else:
362 361 # assume last version before adding the key to the header
363 362 from_version = 4
364 363 adapter = adapters.get((from_version, to_version), None)
365 364 if adapter is None:
366 365 return msg
367 366 return adapter(msg)
368 367
369 368
370 369 # one adapter per major version from,to
371 370 adapters = {
372 371 (5,4) : V5toV4(),
373 372 (4,5) : V4toV5(),
374 373 }
@@ -1,377 +1,393 b''
1 1 """Tests for adapting IPython msg spec versions"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import copy
7 7 import json
8 8 from unittest import TestCase
9 9 import nose.tools as nt
10 10
11 11 from IPython.kernel.adapter import adapt, V4toV5, V5toV4, code_to_line
12 12 from IPython.kernel.zmq.session import Session
13 13
14 14
15 15 def test_default_version():
16 16 s = Session()
17 17 msg = s.msg("msg_type")
18 18 msg['header'].pop('version')
19 19 original = copy.deepcopy(msg)
20 20 adapted = adapt(original)
21 21 nt.assert_equal(adapted['header']['version'], V4toV5.version)
22 22
23 23 def test_code_to_line_no_code():
24 24 line, pos = code_to_line("", 0)
25 25 nt.assert_equal(line, "")
26 26 nt.assert_equal(pos, 0)
27 27
28 28 class AdapterTest(TestCase):
29 29
30 30 def setUp(self):
31 31 self.session = Session()
32 32
33 33 def adapt(self, msg, version=None):
34 34 original = copy.deepcopy(msg)
35 35 adapted = adapt(msg, version or self.to_version)
36 36 return original, adapted
37 37
38 38 def check_header(self, msg):
39 39 pass
40 40
41 41
42 42 class V4toV5TestCase(AdapterTest):
43 43 from_version = 4
44 44 to_version = 5
45 45
46 46 def msg(self, msg_type, content):
47 47 """Create a v4 msg (same as v5, minus version header)"""
48 48 msg = self.session.msg(msg_type, content)
49 49 msg['header'].pop('version')
50 50 return msg
51 51
52 52 def test_same_version(self):
53 53 msg = self.msg("execute_result",
54 54 content={'status' : 'ok'}
55 55 )
56 56 original, adapted = self.adapt(msg, self.from_version)
57 57
58 58 self.assertEqual(original, adapted)
59 59
60 60 def test_no_adapt(self):
61 61 msg = self.msg("input_reply", {'value' : 'some text'})
62 62 v4, v5 = self.adapt(msg)
63 63 self.assertEqual(v5['header']['version'], V4toV5.version)
64 64 v5['header'].pop('version')
65 65 self.assertEqual(v4, v5)
66 66
67 67 def test_rename_type(self):
68 68 for v5_type, v4_type in [
69 69 ('execute_result', 'pyout'),
70 70 ('execute_input', 'pyin'),
71 71 ('error', 'pyerr'),
72 72 ]:
73 73 msg = self.msg(v4_type, {'key' : 'value'})
74 74 v4, v5 = self.adapt(msg)
75 75 self.assertEqual(v5['header']['version'], V4toV5.version)
76 76 self.assertEqual(v5['header']['msg_type'], v5_type)
77 77 self.assertEqual(v4['content'], v5['content'])
78 78
79 79 def test_execute_request(self):
80 80 msg = self.msg("execute_request", {
81 81 'code' : 'a=5',
82 82 'silent' : False,
83 83 'user_expressions' : {'a' : 'apple'},
84 84 'user_variables' : ['b'],
85 85 })
86 86 v4, v5 = self.adapt(msg)
87 87 self.assertEqual(v4['header']['msg_type'], v5['header']['msg_type'])
88 88 v4c = v4['content']
89 89 v5c = v5['content']
90 90 self.assertEqual(v5c['user_expressions'], {'a' : 'apple', 'b': 'b'})
91 91 self.assertNotIn('user_variables', v5c)
92 92 self.assertEqual(v5c['code'], v4c['code'])
93 93
94 94 def test_execute_reply(self):
95 95 msg = self.msg("execute_reply", {
96 96 'status': 'ok',
97 97 'execution_count': 7,
98 98 'user_variables': {'a': 1},
99 99 'user_expressions': {'a+a': 2},
100 100 'payload': [{'source':'page', 'text':'blah'}]
101 101 })
102 102 v4, v5 = self.adapt(msg)
103 103 v5c = v5['content']
104 104 self.assertNotIn('user_variables', v5c)
105 105 self.assertEqual(v5c['user_expressions'], {'a': 1, 'a+a': 2})
106 106 self.assertEqual(v5c['payload'], [{'source': 'page',
107 107 'data': {'text/plain': 'blah'}}
108 108 ])
109 109
110 110 def test_complete_request(self):
111 111 msg = self.msg("complete_request", {
112 112 'text' : 'a.is',
113 113 'line' : 'foo = a.is',
114 114 'block' : None,
115 115 'cursor_pos' : 10,
116 116 })
117 117 v4, v5 = self.adapt(msg)
118 118 v4c = v4['content']
119 119 v5c = v5['content']
120 120 for key in ('text', 'line', 'block'):
121 121 self.assertNotIn(key, v5c)
122 122 self.assertEqual(v5c['cursor_pos'], v4c['cursor_pos'])
123 123 self.assertEqual(v5c['code'], v4c['line'])
124 124
125 125 def test_complete_reply(self):
126 126 msg = self.msg("complete_reply", {
127 127 'matched_text' : 'a.is',
128 128 'matches' : ['a.isalnum',
129 129 'a.isalpha',
130 130 'a.isdigit',
131 131 'a.islower',
132 132 ],
133 133 })
134 134 v4, v5 = self.adapt(msg)
135 135 v4c = v4['content']
136 136 v5c = v5['content']
137 137
138 138 self.assertEqual(v5c['matches'], v4c['matches'])
139 139 self.assertEqual(v5c['metadata'], {})
140 140 self.assertEqual(v5c['cursor_start'], -4)
141 141 self.assertEqual(v5c['cursor_end'], None)
142 142
143 143 def test_object_info_request(self):
144 144 msg = self.msg("object_info_request", {
145 145 'oname' : 'foo',
146 146 'detail_level' : 1,
147 147 })
148 148 v4, v5 = self.adapt(msg)
149 149 self.assertEqual(v5['header']['msg_type'], 'inspect_request')
150 150 v4c = v4['content']
151 151 v5c = v5['content']
152 152 self.assertEqual(v5c['code'], v4c['oname'])
153 153 self.assertEqual(v5c['cursor_pos'], len(v4c['oname']))
154 154 self.assertEqual(v5c['detail_level'], v4c['detail_level'])
155 155
156 156 def test_object_info_reply(self):
157 157 msg = self.msg("object_info_reply", {
158 'oname' : 'foo',
158 'name' : 'foo',
159 159 'found' : True,
160 160 'status' : 'ok',
161 161 'definition' : 'foo(a=5)',
162 162 'docstring' : "the docstring",
163 163 })
164 164 v4, v5 = self.adapt(msg)
165 165 self.assertEqual(v5['header']['msg_type'], 'inspect_reply')
166 166 v4c = v4['content']
167 167 v5c = v5['content']
168 self.assertEqual(sorted(v5c), [ 'data', 'found', 'metadata', 'name', 'status'])
168 self.assertEqual(sorted(v5c), [ 'data', 'found', 'metadata', 'status'])
169 169 text = v5c['data']['text/plain']
170 170 self.assertEqual(text, '\n'.join([v4c['definition'], v4c['docstring']]))
171
171
172 def test_object_info_reply_not_found(self):
173 msg = self.msg("object_info_reply", {
174 'name' : 'foo',
175 'found' : False,
176 })
177 v4, v5 = self.adapt(msg)
178 self.assertEqual(v5['header']['msg_type'], 'inspect_reply')
179 v4c = v4['content']
180 v5c = v5['content']
181 self.assertEqual(v5c, {
182 'status': 'ok',
183 'found': False,
184 'data': {},
185 'metadata': {},
186 })
187
172 188 def test_kernel_info_reply(self):
173 189 msg = self.msg("kernel_info_reply", {
174 190 'language': 'python',
175 191 'language_version': [2,8,0],
176 192 'ipython_version': [1,2,3],
177 193 })
178 194 v4, v5 = self.adapt(msg)
179 195 v4c = v4['content']
180 196 v5c = v5['content']
181 197 self.assertEqual(v5c, {
182 198 'protocol_version': '4.1',
183 199 'implementation': 'ipython',
184 200 'implementation_version': '1.2.3',
185 201 'language_info': {
186 202 'name': 'python',
187 203 'version': '2.8.0',
188 204 },
189 205 'banner' : '',
190 206 })
191 207
192 208 # iopub channel
193 209
194 210 def test_display_data(self):
195 211 jsondata = dict(a=5)
196 212 msg = self.msg("display_data", {
197 213 'data' : {
198 214 'text/plain' : 'some text',
199 215 'application/json' : json.dumps(jsondata)
200 216 },
201 217 'metadata' : {'text/plain' : { 'key' : 'value' }},
202 218 })
203 219 v4, v5 = self.adapt(msg)
204 220 v4c = v4['content']
205 221 v5c = v5['content']
206 222 self.assertEqual(v5c['metadata'], v4c['metadata'])
207 223 self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain'])
208 224 self.assertEqual(v5c['data']['application/json'], jsondata)
209 225
210 226 # stdin channel
211 227
212 228 def test_input_request(self):
213 229 msg = self.msg('input_request', {'prompt': "$>"})
214 230 v4, v5 = self.adapt(msg)
215 231 self.assertEqual(v5['content']['prompt'], v4['content']['prompt'])
216 232 self.assertFalse(v5['content']['password'])
217 233
218 234
219 235 class V5toV4TestCase(AdapterTest):
220 236 from_version = 5
221 237 to_version = 4
222 238
223 239 def msg(self, msg_type, content):
224 240 return self.session.msg(msg_type, content)
225 241
226 242 def test_same_version(self):
227 243 msg = self.msg("execute_result",
228 244 content={'status' : 'ok'}
229 245 )
230 246 original, adapted = self.adapt(msg, self.from_version)
231 247
232 248 self.assertEqual(original, adapted)
233 249
234 250 def test_no_adapt(self):
235 251 msg = self.msg("input_reply", {'value' : 'some text'})
236 252 v5, v4 = self.adapt(msg)
237 253 self.assertNotIn('version', v4['header'])
238 254 v5['header'].pop('version')
239 255 self.assertEqual(v4, v5)
240 256
241 257 def test_rename_type(self):
242 258 for v5_type, v4_type in [
243 259 ('execute_result', 'pyout'),
244 260 ('execute_input', 'pyin'),
245 261 ('error', 'pyerr'),
246 262 ]:
247 263 msg = self.msg(v5_type, {'key' : 'value'})
248 264 v5, v4 = self.adapt(msg)
249 265 self.assertEqual(v4['header']['msg_type'], v4_type)
250 266 nt.assert_not_in('version', v4['header'])
251 267 self.assertEqual(v4['content'], v5['content'])
252 268
253 269 def test_execute_request(self):
254 270 msg = self.msg("execute_request", {
255 271 'code' : 'a=5',
256 272 'silent' : False,
257 273 'user_expressions' : {'a' : 'apple'},
258 274 })
259 275 v5, v4 = self.adapt(msg)
260 276 self.assertEqual(v4['header']['msg_type'], v5['header']['msg_type'])
261 277 v4c = v4['content']
262 278 v5c = v5['content']
263 279 self.assertEqual(v4c['user_variables'], [])
264 280 self.assertEqual(v5c['code'], v4c['code'])
265 281
266 282 def test_complete_request(self):
267 283 msg = self.msg("complete_request", {
268 284 'code' : 'def foo():\n'
269 285 ' a.is\n'
270 286 'foo()',
271 287 'cursor_pos': 19,
272 288 })
273 289 v5, v4 = self.adapt(msg)
274 290 v4c = v4['content']
275 291 v5c = v5['content']
276 292 self.assertNotIn('code', v4c)
277 293 self.assertEqual(v4c['line'], v5c['code'].splitlines(True)[1])
278 294 self.assertEqual(v4c['cursor_pos'], 8)
279 295 self.assertEqual(v4c['text'], '')
280 296 self.assertEqual(v4c['block'], None)
281 297
282 298 def test_complete_reply(self):
283 299 msg = self.msg("complete_reply", {
284 300 'cursor_start' : 10,
285 301 'cursor_end' : 14,
286 302 'matches' : ['a.isalnum',
287 303 'a.isalpha',
288 304 'a.isdigit',
289 305 'a.islower',
290 306 ],
291 307 'metadata' : {},
292 308 })
293 309 v5, v4 = self.adapt(msg)
294 310 v4c = v4['content']
295 311 v5c = v5['content']
296 312 self.assertEqual(v4c['matched_text'], 'a.is')
297 313 self.assertEqual(v4c['matches'], v5c['matches'])
298 314
299 315 def test_inspect_request(self):
300 316 msg = self.msg("inspect_request", {
301 317 'code' : 'def foo():\n'
302 318 ' apple\n'
303 319 'bar()',
304 320 'cursor_pos': 18,
305 321 'detail_level' : 1,
306 322 })
307 323 v5, v4 = self.adapt(msg)
308 324 self.assertEqual(v4['header']['msg_type'], 'object_info_request')
309 325 v4c = v4['content']
310 326 v5c = v5['content']
311 327 self.assertEqual(v4c['oname'], 'apple')
312 328 self.assertEqual(v5c['detail_level'], v4c['detail_level'])
313 329
314 330 def test_inspect_reply(self):
315 331 msg = self.msg("inspect_reply", {
316 332 'name' : 'foo',
317 333 'found' : True,
318 334 'data' : {'text/plain' : 'some text'},
319 335 'metadata' : {},
320 336 })
321 337 v5, v4 = self.adapt(msg)
322 338 self.assertEqual(v4['header']['msg_type'], 'object_info_reply')
323 339 v4c = v4['content']
324 340 v5c = v5['content']
325 341 self.assertEqual(sorted(v4c), ['found', 'oname'])
326 342 self.assertEqual(v4c['found'], False)
327 343
328 344 def test_kernel_info_reply(self):
329 345 msg = self.msg("kernel_info_reply", {
330 346 'protocol_version': '5.0',
331 347 'implementation': 'ipython',
332 348 'implementation_version': '1.2.3',
333 349 'language_info': {
334 350 'name': 'python',
335 351 'version': '2.8.0',
336 352 'mimetype': 'text/x-python',
337 353 },
338 354 'banner' : 'the banner',
339 355 })
340 356 v5, v4 = self.adapt(msg)
341 357 v4c = v4['content']
342 358 v5c = v5['content']
343 359 info = v5c['language_info']
344 360 self.assertEqual(v4c, {
345 361 'protocol_version': [5,0],
346 362 'language': 'python',
347 363 'language_version': [2,8,0],
348 364 'ipython_version': [1,2,3],
349 365 })
350 366
351 367 # iopub channel
352 368
353 369 def test_display_data(self):
354 370 jsondata = dict(a=5)
355 371 msg = self.msg("display_data", {
356 372 'data' : {
357 373 'text/plain' : 'some text',
358 374 'application/json' : jsondata,
359 375 },
360 376 'metadata' : {'text/plain' : { 'key' : 'value' }},
361 377 })
362 378 v5, v4 = self.adapt(msg)
363 379 v4c = v4['content']
364 380 v5c = v5['content']
365 381 self.assertEqual(v5c['metadata'], v4c['metadata'])
366 382 self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain'])
367 383 self.assertEqual(v4c['data']['application/json'], json.dumps(jsondata))
368 384
369 385 # stdin channel
370 386
371 387 def test_input_request(self):
372 388 msg = self.msg('input_request', {'prompt': "$>", 'password' : True})
373 389 v5, v4 = self.adapt(msg)
374 390 self.assertEqual(v5['content']['prompt'], v4['content']['prompt'])
375 391 self.assertNotIn('password', v4['content'])
376 392
377 393
General Comments 0
You need to be logged in to leave comments. Login now