##// END OF EJS Templates
inspect_reply messages have 'oname', not 'name'...
MinRK -
Show More
@@ -1,356 +1,356 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 content = msg['content']
106 106 content.pop('banner', None)
107 107 for key in ('language_version', 'protocol_version'):
108 108 if key in content:
109 109 content[key] = _version_str_to_list(content[key])
110 110 if content.pop('implementation', '') == 'ipython' \
111 111 and 'implementation_version' in content:
112 112 content['ipython_version'] = content.pop('implmentation_version')
113 113 content.pop('implementation_version', None)
114 114 content.setdefault("implmentation", content['language'])
115 115 return msg
116 116
117 117 def execute_request(self, msg):
118 118 content = msg['content']
119 119 content.setdefault('user_variables', [])
120 120 return msg
121 121
122 122 def execute_reply(self, msg):
123 123 content = msg['content']
124 124 content.setdefault('user_variables', {})
125 125 # TODO: handle payloads
126 126 return msg
127 127
128 128 def complete_request(self, msg):
129 129 content = msg['content']
130 130 code = content['code']
131 131 cursor_pos = content['cursor_pos']
132 132 line, cursor_pos = code_to_line(code, cursor_pos)
133 133
134 134 new_content = msg['content'] = {}
135 135 new_content['text'] = ''
136 136 new_content['line'] = line
137 137 new_content['block'] = None
138 138 new_content['cursor_pos'] = cursor_pos
139 139 return msg
140 140
141 141 def complete_reply(self, msg):
142 142 content = msg['content']
143 143 cursor_start = content.pop('cursor_start')
144 144 cursor_end = content.pop('cursor_end')
145 145 match_len = cursor_end - cursor_start
146 146 content['matched_text'] = content['matches'][0][:match_len]
147 147 content.pop('metadata', None)
148 148 return msg
149 149
150 150 def object_info_request(self, msg):
151 151 content = msg['content']
152 152 code = content['code']
153 153 cursor_pos = content['cursor_pos']
154 154 line, _ = code_to_line(code, cursor_pos)
155 155
156 156 new_content = msg['content'] = {}
157 157 new_content['oname'] = token_at_cursor(code, cursor_pos)
158 158 new_content['detail_level'] = content['detail_level']
159 159 return msg
160 160
161 161 def object_info_reply(self, msg):
162 162 """inspect_reply can't be easily backward compatible"""
163 msg['content'] = {'found' : False, 'name' : 'unknown'}
163 msg['content'] = {'found' : False, 'oname' : 'unknown'}
164 164 return msg
165 165
166 166 # iopub channel
167 167
168 168 def stream(self, msg):
169 169 content = msg['content']
170 170 content['data'] = content.pop('text')
171 171 return msg
172 172
173 173 def display_data(self, msg):
174 174 content = msg['content']
175 175 content.setdefault("source", "display")
176 176 data = content['data']
177 177 if 'application/json' in data:
178 178 try:
179 179 data['application/json'] = json.dumps(data['application/json'])
180 180 except Exception:
181 181 # warn?
182 182 pass
183 183 return msg
184 184
185 185 # stdin channel
186 186
187 187 def input_request(self, msg):
188 188 msg['content'].pop('password', None)
189 189 return msg
190 190
191 191
192 192 class V4toV5(Adapter):
193 193 """Convert msg spec V4 to V5"""
194 194 version = '5.0'
195 195
196 196 # invert message renames above
197 197 msg_type_map = {v:k for k,v in V5toV4.msg_type_map.items()}
198 198
199 199 def update_header(self, msg):
200 200 msg['header']['version'] = self.version
201 201 return msg
202 202
203 203 # shell channel
204 204
205 205 def kernel_info_reply(self, msg):
206 206 content = msg['content']
207 207 for key in ('language_version', 'protocol_version', 'ipython_version'):
208 208 if key in content:
209 209 content[key] = ".".join(map(str, content[key]))
210 210
211 211 if content['language'].startswith('python') and 'ipython_version' in content:
212 212 content['implementation'] = 'ipython'
213 213 content['implementation_version'] = content.pop('ipython_version')
214 214
215 215 content['banner'] = ''
216 216 return msg
217 217
218 218 def execute_request(self, msg):
219 219 content = msg['content']
220 220 user_variables = content.pop('user_variables', [])
221 221 user_expressions = content.setdefault('user_expressions', {})
222 222 for v in user_variables:
223 223 user_expressions[v] = v
224 224 return msg
225 225
226 226 def execute_reply(self, msg):
227 227 content = msg['content']
228 228 user_expressions = content.setdefault('user_expressions', {})
229 229 user_variables = content.pop('user_variables', {})
230 230 if user_variables:
231 231 user_expressions.update(user_variables)
232 232
233 233 # Pager payloads became a mime bundle
234 234 for payload in content.get('payload', []):
235 235 if payload.get('source', None) == 'page' and ('text' in payload):
236 236 if 'data' not in payload:
237 237 payload['data'] = {}
238 238 payload['data']['text/plain'] = payload.pop('text')
239 239
240 240 return msg
241 241
242 242 def complete_request(self, msg):
243 243 old_content = msg['content']
244 244
245 245 new_content = msg['content'] = {}
246 246 new_content['code'] = old_content['line']
247 247 new_content['cursor_pos'] = old_content['cursor_pos']
248 248 return msg
249 249
250 250 def complete_reply(self, msg):
251 251 # complete_reply needs more context than we have to get cursor_start and end.
252 252 # use special value of `-1` to indicate to frontend that it should be at
253 253 # the current cursor position.
254 254 content = msg['content']
255 255 new_content = msg['content'] = {'status' : 'ok'}
256 256 new_content['matches'] = content['matches']
257 257 new_content['cursor_start'] = -len(content['matched_text'])
258 258 new_content['cursor_end'] = None
259 259 new_content['metadata'] = {}
260 260 return msg
261 261
262 262 def inspect_request(self, msg):
263 263 content = msg['content']
264 264 name = content['oname']
265 265
266 266 new_content = msg['content'] = {}
267 267 new_content['code'] = name
268 268 new_content['cursor_pos'] = len(name)
269 269 new_content['detail_level'] = content['detail_level']
270 270 return msg
271 271
272 272 def inspect_reply(self, msg):
273 273 """inspect_reply can't be easily backward compatible"""
274 274 content = msg['content']
275 275 new_content = msg['content'] = {'status' : 'ok'}
276 276 found = new_content['found'] = content['found']
277 new_content['name'] = content['name']
277 new_content['name'] = content['oname']
278 278 new_content['data'] = data = {}
279 279 new_content['metadata'] = {}
280 280 if found:
281 281 lines = []
282 282 for key in ('call_def', 'init_definition', 'definition'):
283 283 if content.get(key, False):
284 284 lines.append(content[key])
285 285 break
286 286 for key in ('call_docstring', 'init_docstring', 'docstring'):
287 287 if content.get(key, False):
288 288 lines.append(content[key])
289 289 break
290 290 if not lines:
291 291 lines.append("<empty docstring>")
292 292 data['text/plain'] = '\n'.join(lines)
293 293 return msg
294 294
295 295 # iopub channel
296 296
297 297 def stream(self, msg):
298 298 content = msg['content']
299 299 content['text'] = content.pop('data')
300 300 return msg
301 301
302 302 def display_data(self, msg):
303 303 content = msg['content']
304 304 content.pop("source", None)
305 305 data = content['data']
306 306 if 'application/json' in data:
307 307 try:
308 308 data['application/json'] = json.loads(data['application/json'])
309 309 except Exception:
310 310 # warn?
311 311 pass
312 312 return msg
313 313
314 314 # stdin channel
315 315
316 316 def input_request(self, msg):
317 317 msg['content'].setdefault('password', False)
318 318 return msg
319 319
320 320
321 321
322 322 def adapt(msg, to_version=kernel_protocol_version_info[0]):
323 323 """Adapt a single message to a target version
324 324
325 325 Parameters
326 326 ----------
327 327
328 328 msg : dict
329 329 An IPython message.
330 330 to_version : int, optional
331 331 The target major version.
332 332 If unspecified, adapt to the current version for IPython.
333 333
334 334 Returns
335 335 -------
336 336
337 337 msg : dict
338 338 An IPython message appropriate in the new version.
339 339 """
340 340 header = msg['header']
341 341 if 'version' in header:
342 342 from_version = int(header['version'].split('.')[0])
343 343 else:
344 344 # assume last version before adding the key to the header
345 345 from_version = 4
346 346 adapter = adapters.get((from_version, to_version), None)
347 347 if adapter is None:
348 348 return msg
349 349 return adapter(msg)
350 350
351 351
352 352 # one adapter per major version from,to
353 353 adapters = {
354 354 (5,4) : V5toV4(),
355 355 (4,5) : V4toV5(),
356 356 }
@@ -1,334 +1,334 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 'name' : 'foo',
158 'oname' : '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 168 self.assertEqual(sorted(v5c), [ 'data', 'found', 'metadata', 'name', 'status'])
169 169 text = v5c['data']['text/plain']
170 170 self.assertEqual(text, '\n'.join([v4c['definition'], v4c['docstring']]))
171 171
172 172 # iopub channel
173 173
174 174 def test_display_data(self):
175 175 jsondata = dict(a=5)
176 176 msg = self.msg("display_data", {
177 177 'data' : {
178 178 'text/plain' : 'some text',
179 179 'application/json' : json.dumps(jsondata)
180 180 },
181 181 'metadata' : {'text/plain' : { 'key' : 'value' }},
182 182 })
183 183 v4, v5 = self.adapt(msg)
184 184 v4c = v4['content']
185 185 v5c = v5['content']
186 186 self.assertEqual(v5c['metadata'], v4c['metadata'])
187 187 self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain'])
188 188 self.assertEqual(v5c['data']['application/json'], jsondata)
189 189
190 190 # stdin channel
191 191
192 192 def test_input_request(self):
193 193 msg = self.msg('input_request', {'prompt': "$>"})
194 194 v4, v5 = self.adapt(msg)
195 195 self.assertEqual(v5['content']['prompt'], v4['content']['prompt'])
196 196 self.assertFalse(v5['content']['password'])
197 197
198 198
199 199 class V5toV4TestCase(AdapterTest):
200 200 from_version = 5
201 201 to_version = 4
202 202
203 203 def msg(self, msg_type, content):
204 204 return self.session.msg(msg_type, content)
205 205
206 206 def test_same_version(self):
207 207 msg = self.msg("execute_result",
208 208 content={'status' : 'ok'}
209 209 )
210 210 original, adapted = self.adapt(msg, self.from_version)
211 211
212 212 self.assertEqual(original, adapted)
213 213
214 214 def test_no_adapt(self):
215 215 msg = self.msg("input_reply", {'value' : 'some text'})
216 216 v5, v4 = self.adapt(msg)
217 217 self.assertNotIn('version', v4['header'])
218 218 v5['header'].pop('version')
219 219 self.assertEqual(v4, v5)
220 220
221 221 def test_rename_type(self):
222 222 for v5_type, v4_type in [
223 223 ('execute_result', 'pyout'),
224 224 ('execute_input', 'pyin'),
225 225 ('error', 'pyerr'),
226 226 ]:
227 227 msg = self.msg(v5_type, {'key' : 'value'})
228 228 v5, v4 = self.adapt(msg)
229 229 self.assertEqual(v4['header']['msg_type'], v4_type)
230 230 nt.assert_not_in('version', v4['header'])
231 231 self.assertEqual(v4['content'], v5['content'])
232 232
233 233 def test_execute_request(self):
234 234 msg = self.msg("execute_request", {
235 235 'code' : 'a=5',
236 236 'silent' : False,
237 237 'user_expressions' : {'a' : 'apple'},
238 238 })
239 239 v5, v4 = self.adapt(msg)
240 240 self.assertEqual(v4['header']['msg_type'], v5['header']['msg_type'])
241 241 v4c = v4['content']
242 242 v5c = v5['content']
243 243 self.assertEqual(v4c['user_variables'], [])
244 244 self.assertEqual(v5c['code'], v4c['code'])
245 245
246 246 def test_complete_request(self):
247 247 msg = self.msg("complete_request", {
248 248 'code' : 'def foo():\n'
249 249 ' a.is\n'
250 250 'foo()',
251 251 'cursor_pos': 19,
252 252 })
253 253 v5, v4 = self.adapt(msg)
254 254 v4c = v4['content']
255 255 v5c = v5['content']
256 256 self.assertNotIn('code', v4c)
257 257 self.assertEqual(v4c['line'], v5c['code'].splitlines(True)[1])
258 258 self.assertEqual(v4c['cursor_pos'], 8)
259 259 self.assertEqual(v4c['text'], '')
260 260 self.assertEqual(v4c['block'], None)
261 261
262 262 def test_complete_reply(self):
263 263 msg = self.msg("complete_reply", {
264 264 'cursor_start' : 10,
265 265 'cursor_end' : 14,
266 266 'matches' : ['a.isalnum',
267 267 'a.isalpha',
268 268 'a.isdigit',
269 269 'a.islower',
270 270 ],
271 271 'metadata' : {},
272 272 })
273 273 v5, v4 = self.adapt(msg)
274 274 v4c = v4['content']
275 275 v5c = v5['content']
276 276 self.assertEqual(v4c['matched_text'], 'a.is')
277 277 self.assertEqual(v4c['matches'], v5c['matches'])
278 278
279 279 def test_inspect_request(self):
280 280 msg = self.msg("inspect_request", {
281 281 'code' : 'def foo():\n'
282 282 ' apple\n'
283 283 'bar()',
284 284 'cursor_pos': 18,
285 285 'detail_level' : 1,
286 286 })
287 287 v5, v4 = self.adapt(msg)
288 288 self.assertEqual(v4['header']['msg_type'], 'object_info_request')
289 289 v4c = v4['content']
290 290 v5c = v5['content']
291 291 self.assertEqual(v4c['oname'], 'apple')
292 292 self.assertEqual(v5c['detail_level'], v4c['detail_level'])
293 293
294 294 def test_inspect_reply(self):
295 295 msg = self.msg("inspect_reply", {
296 296 'name' : 'foo',
297 297 'found' : True,
298 298 'data' : {'text/plain' : 'some text'},
299 299 'metadata' : {},
300 300 })
301 301 v5, v4 = self.adapt(msg)
302 302 self.assertEqual(v4['header']['msg_type'], 'object_info_reply')
303 303 v4c = v4['content']
304 304 v5c = v5['content']
305 self.assertEqual(sorted(v4c), ['found', 'name'])
305 self.assertEqual(sorted(v4c), ['found', 'oname'])
306 306 self.assertEqual(v4c['found'], False)
307 307
308 308 # iopub channel
309 309
310 310 def test_display_data(self):
311 311 jsondata = dict(a=5)
312 312 msg = self.msg("display_data", {
313 313 'data' : {
314 314 'text/plain' : 'some text',
315 315 'application/json' : jsondata,
316 316 },
317 317 'metadata' : {'text/plain' : { 'key' : 'value' }},
318 318 })
319 319 v5, v4 = self.adapt(msg)
320 320 v4c = v4['content']
321 321 v5c = v5['content']
322 322 self.assertEqual(v5c['metadata'], v4c['metadata'])
323 323 self.assertEqual(v5c['data']['text/plain'], v4c['data']['text/plain'])
324 324 self.assertEqual(v4c['data']['application/json'], json.dumps(jsondata))
325 325
326 326 # stdin channel
327 327
328 328 def test_input_request(self):
329 329 msg = self.msg('input_request', {'prompt': "$>", 'password' : True})
330 330 v5, v4 = self.adapt(msg)
331 331 self.assertEqual(v5['content']['prompt'], v4['content']['prompt'])
332 332 self.assertNotIn('password', v4['content'])
333 333
334 334
General Comments 0
You need to be logged in to leave comments. Login now