##// END OF EJS Templates
more detail in oinfo tests
MinRK -
Show More
@@ -1,422 +1,427 b''
1 1 """Test suite for our zeromq-based messaging specification.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2010-2011 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING.txt, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import re
11 11 import sys
12 12 import time
13 13 from subprocess import PIPE
14 14 from Queue import Empty
15 15
16 16 import nose.tools as nt
17 17
18 18 from ..blockingkernelmanager import BlockingKernelManager
19 19
20 20
21 21 from IPython.testing import decorators as dec
22 22 from IPython.utils import io
23 23 from IPython.utils.traitlets import (
24 24 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum,
25 25 )
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Global setup and utilities
29 29 #-----------------------------------------------------------------------------
30 30
31 31 def setup():
32 32 global KM
33 33 KM = BlockingKernelManager()
34 34
35 35 KM.start_kernel(stdout=PIPE, stderr=PIPE)
36 36 KM.start_channels()
37 37
38 38
39 39 def teardown():
40 40 KM.stop_channels()
41 41 KM.shutdown_kernel()
42 42
43 43
44 44 def flush_channels():
45 45 """flush any messages waiting on the queue"""
46 46 for channel in (KM.shell_channel, KM.sub_channel):
47 47 while True:
48 48 try:
49 49 msg = channel.get_msg(block=True, timeout=0.1)
50 50 except Empty:
51 51 break
52 52 else:
53 53 validate_message(msg)
54 54
55 55
56 56 def execute(code='', **kwargs):
57 57 """wrapper for doing common steps for validating an execution request"""
58 58 shell = KM.shell_channel
59 59 sub = KM.sub_channel
60 60
61 61 msg_id = shell.execute(code=code, **kwargs)
62 62 reply = shell.get_msg(timeout=2)
63 63 validate_message(reply, 'execute_reply', msg_id)
64 64 busy = sub.get_msg(timeout=2)
65 65 validate_message(busy, 'status', msg_id)
66 66 nt.assert_equals(busy['content']['execution_state'], 'busy')
67 67
68 68 if not kwargs.get('silent'):
69 69 pyin = sub.get_msg(timeout=2)
70 70 validate_message(pyin, 'pyin', msg_id)
71 71 nt.assert_equals(pyin['content']['code'], code)
72 72
73 73 return msg_id, reply['content']
74 74
75 75 #-----------------------------------------------------------------------------
76 76 # MSG Spec References
77 77 #-----------------------------------------------------------------------------
78 78
79 79
80 80 class Reference(HasTraits):
81 81
82 82 def check(self, d):
83 83 """validate a dict against our traits"""
84 84 for key in self.trait_names():
85 85 yield nt.assert_true(key in d, "Missing key: %r, should be found in %s" % (key, d))
86 86 # FIXME: always allow None, probably not a good idea
87 87 if d[key] is None:
88 88 continue
89 89 try:
90 90 setattr(self, key, d[key])
91 91 except TraitError as e:
92 92 yield nt.assert_true(False, str(e))
93 93
94 94
95 95 class RMessage(Reference):
96 96 msg_id = Unicode()
97 97 msg_type = Unicode()
98 98 header = Dict()
99 99 parent_header = Dict()
100 100 content = Dict()
101 101
102 102 class RHeader(Reference):
103 103 msg_id = Unicode()
104 104 msg_type = Unicode()
105 105 session = Unicode()
106 106 username = Unicode()
107 107
108 108 class RContent(Reference):
109 109 status = Enum((u'ok', u'error'))
110 110
111 111
112 112 class ExecuteReply(Reference):
113 113 execution_count = Integer()
114 114 status = Enum((u'ok', u'error'))
115 115
116 116 def check(self, d):
117 117 for tst in Reference.check(self, d):
118 118 yield tst
119 119 if d['status'] == 'ok':
120 120 for tst in ExecuteReplyOkay().check(d):
121 121 yield tst
122 122 elif d['status'] == 'error':
123 123 for tst in ExecuteReplyError().check(d):
124 124 yield tst
125 125
126 126
127 127 class ExecuteReplyOkay(Reference):
128 128 payload = List(Dict)
129 129 user_variables = Dict()
130 130 user_expressions = Dict()
131 131
132 132
133 133 class ExecuteReplyError(Reference):
134 134 ename = Unicode()
135 135 evalue = Unicode()
136 136 traceback = List(Unicode)
137 137
138 138
139 139 class OInfoReply(Reference):
140 140 name = Unicode()
141 141 found = Bool()
142 142 ismagic = Bool()
143 143 isalias = Bool()
144 144 namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
145 145 type_name = Unicode()
146 146 string_form = Unicode()
147 147 base_class = Unicode()
148 148 length = Integer()
149 149 file = Unicode()
150 150 definition = Unicode()
151 151 argspec = Dict()
152 152 init_definition = Unicode()
153 153 docstring = Unicode()
154 154 init_docstring = Unicode()
155 155 class_docstring = Unicode()
156 156 call_def = Unicode()
157 157 call_docstring = Unicode()
158 158 source = Unicode()
159 159
160 160 def check(self, d):
161 161 for tst in Reference.check(self, d):
162 162 yield tst
163 163 if d['argspec'] is not None:
164 164 for tst in ArgSpec().check(d['argspec']):
165 165 yield tst
166 166
167 167
168 168 class ArgSpec(Reference):
169 169 args = List(Unicode)
170 170 varargs = Unicode()
171 171 varkw = Unicode()
172 172 defaults = List()
173 173
174 174
175 175 class Status(Reference):
176 176 execution_state = Enum((u'busy', u'idle'))
177 177
178 178
179 179 class CompleteReply(Reference):
180 180 matches = List(Unicode)
181 181
182 182
183 183 # IOPub messages
184 184
185 185 class PyIn(Reference):
186 186 code = Unicode()
187 187 execution_count = Integer()
188 188
189 189
190 190 PyErr = ExecuteReplyError
191 191
192 192
193 193 class Stream(Reference):
194 194 name = Enum((u'stdout', u'stderr'))
195 195 data = Unicode()
196 196
197 197
198 198 mime_pat = re.compile(r'\w+/\w+')
199 199
200 200 class DisplayData(Reference):
201 201 source = Unicode()
202 202 metadata = Dict()
203 203 data = Dict()
204 204 def _data_changed(self, name, old, new):
205 205 for k,v in new.iteritems():
206 206 nt.assert_true(mime_pat.match(k))
207 207 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
208 208
209 209
210 210 references = {
211 211 'execute_reply' : ExecuteReply(),
212 212 'object_info_reply' : OInfoReply(),
213 213 'status' : Status(),
214 214 'complete_reply' : CompleteReply(),
215 215 'pyin' : PyIn(),
216 216 'pyerr' : PyErr(),
217 217 'stream' : Stream(),
218 218 'display_data' : DisplayData(),
219 219 }
220 220
221 221
222 222 def validate_message(msg, msg_type=None, parent=None):
223 223 """validate a message"""
224 224 RMessage().check(msg)
225 225 if msg_type:
226 226 yield nt.assert_equals(msg['msg_type'], msg_type)
227 227 if parent:
228 228 yield nt.assert_equal(msg['parent_header']['msg_id'], parent)
229 229 content = msg['content']
230 230 ref = references[msg['msg_type']]
231 231 for tst in ref.check(content):
232 232 yield tst
233 233
234 234
235 235 #-----------------------------------------------------------------------------
236 236 # Tests
237 237 #-----------------------------------------------------------------------------
238 238
239 239 # Shell channel
240 240
241 241 @dec.parametric
242 242 def test_execute():
243 243 flush_channels()
244 244
245 245 shell = KM.shell_channel
246 246 msg_id = shell.execute(code='x=1')
247 247 reply = shell.get_msg(timeout=2)
248 248 for tst in validate_message(reply, 'execute_reply', msg_id):
249 249 yield tst
250 250
251 251
252 252 @dec.parametric
253 253 def test_execute_silent():
254 254 flush_channels()
255 255 msg_id, reply = execute(code='x=1', silent=True)
256 256
257 257 # flush status=idle
258 258 status = KM.sub_channel.get_msg(timeout=2)
259 259 for tst in validate_message(status, 'status', msg_id):
260 260 yield tst
261 261 nt.assert_equals(status['content']['execution_state'], 'idle')
262 262
263 263 yield nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
264 264 count = reply['execution_count']
265 265
266 266 msg_id, reply = execute(code='x=2', silent=True)
267 267
268 268 # flush status=idle
269 269 status = KM.sub_channel.get_msg(timeout=2)
270 270 for tst in validate_message(status, 'status', msg_id):
271 271 yield tst
272 272 yield nt.assert_equals(status['content']['execution_state'], 'idle')
273 273
274 274 yield nt.assert_raises(Empty, KM.sub_channel.get_msg, timeout=0.1)
275 275 count_2 = reply['execution_count']
276 276 yield nt.assert_equals(count_2, count)
277 277
278 278
279 279 @dec.parametric
280 280 def test_execute_error():
281 281 flush_channels()
282 282
283 283 msg_id, reply = execute(code='1/0')
284 284 yield nt.assert_equals(reply['status'], 'error')
285 285 yield nt.assert_equals(reply['ename'], 'ZeroDivisionError')
286 286
287 287 pyerr = KM.sub_channel.get_msg(timeout=2)
288 288 for tst in validate_message(pyerr, 'pyerr', msg_id):
289 289 yield tst
290 290
291 291
292 292 def test_execute_inc():
293 293 """execute request should increment execution_count"""
294 294 flush_channels()
295 295
296 296 msg_id, reply = execute(code='x=1')
297 297 count = reply['execution_count']
298 298
299 299 flush_channels()
300 300
301 301 msg_id, reply = execute(code='x=2')
302 302 count_2 = reply['execution_count']
303 303 nt.assert_equals(count_2, count+1)
304 304
305 305
306 306 def test_user_variables():
307 307 flush_channels()
308 308
309 309 msg_id, reply = execute(code='x=1', user_variables=['x'])
310 310 user_variables = reply['user_variables']
311 311 nt.assert_equals(user_variables, {u'x' : u'1'})
312 312
313 313
314 314 def test_user_expressions():
315 315 flush_channels()
316 316
317 317 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
318 318 user_expressions = reply['user_expressions']
319 319 nt.assert_equals(user_expressions, {u'foo' : u'2'})
320 320
321 321
322 322 @dec.parametric
323 323 def test_oinfo():
324 324 flush_channels()
325 325
326 326 shell = KM.shell_channel
327 327
328 328 msg_id = shell.object_info('a')
329 329 reply = shell.get_msg(timeout=2)
330 330 for tst in validate_message(reply, 'object_info_reply', msg_id):
331 331 yield tst
332 332
333 333
334 334 @dec.parametric
335 335 def test_oinfo_found():
336 336 flush_channels()
337 337
338 338 shell = KM.shell_channel
339 339
340 340 msg_id, reply = execute(code='a=5')
341 341
342 342 msg_id = shell.object_info('a')
343 343 reply = shell.get_msg(timeout=2)
344 344 for tst in validate_message(reply, 'object_info_reply', msg_id):
345 345 yield tst
346 346 content = reply['content']
347 347 yield nt.assert_true(content['found'])
348 argspec = content['argspec']
349 yield nt.assert_true(argspec is None, "didn't expect argspec dict, got %r" % argspec)
348 350
349 351
350 352 @dec.parametric
351 353 def test_oinfo_detail():
352 354 flush_channels()
353 355
354 356 shell = KM.shell_channel
355 357
356 358 msg_id, reply = execute(code='ip=get_ipython()')
357 359
358 360 msg_id = shell.object_info('ip.object_inspect', detail_level=2)
359 361 reply = shell.get_msg(timeout=2)
360 362 for tst in validate_message(reply, 'object_info_reply', msg_id):
361 363 yield tst
362 364 content = reply['content']
363 365 yield nt.assert_true(content['found'])
366 argspec = content['argspec']
367 yield nt.assert_true(isinstance(argspec, dict), "expected non-empty argspec dict, got %r" % argspec)
368 yield nt.assert_equals(argspec['defaults'], [0])
364 369
365 370
366 371 @dec.parametric
367 372 def test_oinfo_not_found():
368 373 flush_channels()
369 374
370 375 shell = KM.shell_channel
371 376
372 377 msg_id = shell.object_info('dne')
373 378 reply = shell.get_msg(timeout=2)
374 379 for tst in validate_message(reply, 'object_info_reply', msg_id):
375 380 yield tst
376 381 content = reply['content']
377 382 yield nt.assert_false(content['found'])
378 383
379 384
380 385 @dec.parametric
381 386 def test_complete():
382 387 flush_channels()
383 388
384 389 shell = KM.shell_channel
385 390
386 391 msg_id, reply = execute(code="alpha = albert = 5")
387 392
388 393 msg_id = shell.complete('al', 'al', 2)
389 394 reply = shell.get_msg(timeout=2)
390 395 for tst in validate_message(reply, 'complete_reply', msg_id):
391 396 yield tst
392 397 matches = reply['content']['matches']
393 398 for name in ('alpha', 'albert'):
394 399 yield nt.assert_true(name in matches, "Missing match: %r" % name)
395 400
396 401
397 402 @dec.parametric
398 403 def test_stream():
399 404 flush_channels()
400 405
401 406 msg_id, reply = execute("print('hi')")
402 407
403 408 stdout = KM.sub_channel.get_msg(timeout=2)
404 409 for tst in validate_message(stdout, 'stream', msg_id):
405 410 yield tst
406 411 content = stdout['content']
407 412 yield nt.assert_equals(content['name'], u'stdout')
408 413 yield nt.assert_equals(content['data'], u'hi\n')
409 414
410 415
411 416 @dec.parametric
412 417 def test_display_data():
413 418 flush_channels()
414 419
415 420 msg_id, reply = execute("from IPython.core.display import display; display(1)")
416 421
417 422 display = KM.sub_channel.get_msg(timeout=2)
418 423 for tst in validate_message(display, 'display_data', parent=msg_id):
419 424 yield tst
420 425 data = display['content']['data']
421 426 yield nt.assert_equals(data['text/plain'], u'1')
422 427
General Comments 0
You need to be logged in to leave comments. Login now