##// END OF EJS Templates
remove redundant BlockingKernelClient import from test_message_spec
MinRK -
Show More
@@ -1,484 +1,483
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 from IPython.kernel import KernelManager, BlockingKernelClient
18 from IPython.kernel import KernelManager
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, Any,
25 25 )
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Global setup and utilities
29 29 #-----------------------------------------------------------------------------
30 30
31 31 def setup():
32 32 global KM, KC
33 33 KM = KernelManager()
34 KM.client_factory = BlockingKernelClient
35 34 KM.start_kernel(stdout=PIPE, stderr=PIPE)
36 35 KC = KM.client()
37 36 KC.start_channels()
38 37
39 38 # wait for kernel to be ready
40 39 KC.execute("pass")
41 40 KC.get_shell_msg(block=True, timeout=5)
42 41 flush_channels()
43 42
44 43
45 44 def teardown():
46 45 KC.stop_channels()
47 46 KM.shutdown_kernel()
48 47
49 48
50 49 def flush_channels(kc=None):
51 50 """flush any messages waiting on the queue"""
52 51 if kc is None:
53 52 kc = KC
54 53 for channel in (kc.shell_channel, kc.iopub_channel):
55 54 while True:
56 55 try:
57 56 msg = channel.get_msg(block=True, timeout=0.1)
58 57 except Empty:
59 58 break
60 59 else:
61 60 list(validate_message(msg))
62 61
63 62
64 63 def execute(code='', kc=None, **kwargs):
65 64 """wrapper for doing common steps for validating an execution request"""
66 65 msg_id = KC.execute(code=code, **kwargs)
67 66 reply = KC.get_shell_msg(timeout=2)
68 67 list(validate_message(reply, 'execute_reply', msg_id))
69 68 busy = KC.get_iopub_msg(timeout=2)
70 69 list(validate_message(busy, 'status', msg_id))
71 70 nt.assert_equal(busy['content']['execution_state'], 'busy')
72 71
73 72 if not kwargs.get('silent'):
74 73 pyin = KC.get_iopub_msg(timeout=2)
75 74 list(validate_message(pyin, 'pyin', msg_id))
76 75 nt.assert_equal(pyin['content']['code'], code)
77 76
78 77 return msg_id, reply['content']
79 78
80 79 #-----------------------------------------------------------------------------
81 80 # MSG Spec References
82 81 #-----------------------------------------------------------------------------
83 82
84 83
85 84 class Reference(HasTraits):
86 85
87 86 """
88 87 Base class for message spec specification testing.
89 88
90 89 This class is the core of the message specification test. The
91 90 idea is that child classes implement trait attributes for each
92 91 message keys, so that message keys can be tested against these
93 92 traits using :meth:`check` method.
94 93
95 94 """
96 95
97 96 def check(self, d):
98 97 """validate a dict against our traits"""
99 98 for key in self.trait_names():
100 99 yield nt.assert_true(key in d, "Missing key: %r, should be found in %s" % (key, d))
101 100 # FIXME: always allow None, probably not a good idea
102 101 if d[key] is None:
103 102 continue
104 103 try:
105 104 setattr(self, key, d[key])
106 105 except TraitError as e:
107 106 yield nt.assert_true(False, str(e))
108 107
109 108
110 109 class RMessage(Reference):
111 110 msg_id = Unicode()
112 111 msg_type = Unicode()
113 112 header = Dict()
114 113 parent_header = Dict()
115 114 content = Dict()
116 115
117 116 class RHeader(Reference):
118 117 msg_id = Unicode()
119 118 msg_type = Unicode()
120 119 session = Unicode()
121 120 username = Unicode()
122 121
123 122 class RContent(Reference):
124 123 status = Enum((u'ok', u'error'))
125 124
126 125
127 126 class ExecuteReply(Reference):
128 127 execution_count = Integer()
129 128 status = Enum((u'ok', u'error'))
130 129
131 130 def check(self, d):
132 131 for tst in Reference.check(self, d):
133 132 yield tst
134 133 if d['status'] == 'ok':
135 134 for tst in ExecuteReplyOkay().check(d):
136 135 yield tst
137 136 elif d['status'] == 'error':
138 137 for tst in ExecuteReplyError().check(d):
139 138 yield tst
140 139
141 140
142 141 class ExecuteReplyOkay(Reference):
143 142 payload = List(Dict)
144 143 user_variables = Dict()
145 144 user_expressions = Dict()
146 145
147 146
148 147 class ExecuteReplyError(Reference):
149 148 ename = Unicode()
150 149 evalue = Unicode()
151 150 traceback = List(Unicode)
152 151
153 152
154 153 class OInfoReply(Reference):
155 154 name = Unicode()
156 155 found = Bool()
157 156 ismagic = Bool()
158 157 isalias = Bool()
159 158 namespace = Enum((u'builtin', u'magics', u'alias', u'Interactive'))
160 159 type_name = Unicode()
161 160 string_form = Unicode()
162 161 base_class = Unicode()
163 162 length = Integer()
164 163 file = Unicode()
165 164 definition = Unicode()
166 165 argspec = Dict()
167 166 init_definition = Unicode()
168 167 docstring = Unicode()
169 168 init_docstring = Unicode()
170 169 class_docstring = Unicode()
171 170 call_def = Unicode()
172 171 call_docstring = Unicode()
173 172 source = Unicode()
174 173
175 174 def check(self, d):
176 175 for tst in Reference.check(self, d):
177 176 yield tst
178 177 if d['argspec'] is not None:
179 178 for tst in ArgSpec().check(d['argspec']):
180 179 yield tst
181 180
182 181
183 182 class ArgSpec(Reference):
184 183 args = List(Unicode)
185 184 varargs = Unicode()
186 185 varkw = Unicode()
187 186 defaults = List()
188 187
189 188
190 189 class Status(Reference):
191 190 execution_state = Enum((u'busy', u'idle', u'starting'))
192 191
193 192
194 193 class CompleteReply(Reference):
195 194 matches = List(Unicode)
196 195
197 196
198 197 def Version(num, trait=Integer):
199 198 return List(trait, default_value=[0] * num, minlen=num, maxlen=num)
200 199
201 200
202 201 class KernelInfoReply(Reference):
203 202
204 203 protocol_version = Version(2)
205 204 ipython_version = Version(4, Any)
206 205 language_version = Version(3)
207 206 language = Unicode()
208 207
209 208 def _ipython_version_changed(self, name, old, new):
210 209 for v in new:
211 210 nt.assert_true(
212 211 isinstance(v, int) or isinstance(v, basestring),
213 212 'expected int or string as version component, got {0!r}'
214 213 .format(v))
215 214
216 215
217 216 # IOPub messages
218 217
219 218 class PyIn(Reference):
220 219 code = Unicode()
221 220 execution_count = Integer()
222 221
223 222
224 223 PyErr = ExecuteReplyError
225 224
226 225
227 226 class Stream(Reference):
228 227 name = Enum((u'stdout', u'stderr'))
229 228 data = Unicode()
230 229
231 230
232 231 mime_pat = re.compile(r'\w+/\w+')
233 232
234 233 class DisplayData(Reference):
235 234 source = Unicode()
236 235 metadata = Dict()
237 236 data = Dict()
238 237 def _data_changed(self, name, old, new):
239 238 for k,v in new.iteritems():
240 239 nt.assert_true(mime_pat.match(k))
241 240 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
242 241
243 242
244 243 class PyOut(Reference):
245 244 execution_count = Integer()
246 245 data = Dict()
247 246 def _data_changed(self, name, old, new):
248 247 for k,v in new.iteritems():
249 248 nt.assert_true(mime_pat.match(k))
250 249 nt.assert_true(isinstance(v, basestring), "expected string data, got %r" % v)
251 250
252 251
253 252 references = {
254 253 'execute_reply' : ExecuteReply(),
255 254 'object_info_reply' : OInfoReply(),
256 255 'status' : Status(),
257 256 'complete_reply' : CompleteReply(),
258 257 'kernel_info_reply': KernelInfoReply(),
259 258 'pyin' : PyIn(),
260 259 'pyout' : PyOut(),
261 260 'pyerr' : PyErr(),
262 261 'stream' : Stream(),
263 262 'display_data' : DisplayData(),
264 263 }
265 264 """
266 265 Specifications of `content` part of the reply messages.
267 266 """
268 267
269 268
270 269 def validate_message(msg, msg_type=None, parent=None):
271 270 """validate a message
272 271
273 272 This is a generator, and must be iterated through to actually
274 273 trigger each test.
275 274
276 275 If msg_type and/or parent are given, the msg_type and/or parent msg_id
277 276 are compared with the given values.
278 277 """
279 278 RMessage().check(msg)
280 279 if msg_type:
281 280 yield nt.assert_equal(msg['msg_type'], msg_type)
282 281 if parent:
283 282 yield nt.assert_equal(msg['parent_header']['msg_id'], parent)
284 283 content = msg['content']
285 284 ref = references[msg['msg_type']]
286 285 for tst in ref.check(content):
287 286 yield tst
288 287
289 288
290 289 #-----------------------------------------------------------------------------
291 290 # Tests
292 291 #-----------------------------------------------------------------------------
293 292
294 293 # Shell channel
295 294
296 295 @dec.parametric
297 296 def test_execute():
298 297 flush_channels()
299 298
300 299 msg_id = KC.execute(code='x=1')
301 300 reply = KC.get_shell_msg(timeout=2)
302 301 for tst in validate_message(reply, 'execute_reply', msg_id):
303 302 yield tst
304 303
305 304
306 305 @dec.parametric
307 306 def test_execute_silent():
308 307 flush_channels()
309 308 msg_id, reply = execute(code='x=1', silent=True)
310 309
311 310 # flush status=idle
312 311 status = KC.iopub_channel.get_msg(timeout=2)
313 312 for tst in validate_message(status, 'status', msg_id):
314 313 yield tst
315 314 nt.assert_equal(status['content']['execution_state'], 'idle')
316 315
317 316 yield nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
318 317 count = reply['execution_count']
319 318
320 319 msg_id, reply = execute(code='x=2', silent=True)
321 320
322 321 # flush status=idle
323 322 status = KC.iopub_channel.get_msg(timeout=2)
324 323 for tst in validate_message(status, 'status', msg_id):
325 324 yield tst
326 325 yield nt.assert_equal(status['content']['execution_state'], 'idle')
327 326
328 327 yield nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
329 328 count_2 = reply['execution_count']
330 329 yield nt.assert_equal(count_2, count)
331 330
332 331
333 332 @dec.parametric
334 333 def test_execute_error():
335 334 flush_channels()
336 335
337 336 msg_id, reply = execute(code='1/0')
338 337 yield nt.assert_equal(reply['status'], 'error')
339 338 yield nt.assert_equal(reply['ename'], 'ZeroDivisionError')
340 339
341 340 pyerr = KC.iopub_channel.get_msg(timeout=2)
342 341 for tst in validate_message(pyerr, 'pyerr', msg_id):
343 342 yield tst
344 343
345 344
346 345 def test_execute_inc():
347 346 """execute request should increment execution_count"""
348 347 flush_channels()
349 348
350 349 msg_id, reply = execute(code='x=1')
351 350 count = reply['execution_count']
352 351
353 352 flush_channels()
354 353
355 354 msg_id, reply = execute(code='x=2')
356 355 count_2 = reply['execution_count']
357 356 nt.assert_equal(count_2, count+1)
358 357
359 358
360 359 def test_user_variables():
361 360 flush_channels()
362 361
363 362 msg_id, reply = execute(code='x=1', user_variables=['x'])
364 363 user_variables = reply['user_variables']
365 364 nt.assert_equal(user_variables, {u'x' : u'1'})
366 365
367 366
368 367 def test_user_expressions():
369 368 flush_channels()
370 369
371 370 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
372 371 user_expressions = reply['user_expressions']
373 372 nt.assert_equal(user_expressions, {u'foo' : u'2'})
374 373
375 374
376 375 @dec.parametric
377 376 def test_oinfo():
378 377 flush_channels()
379 378
380 379 msg_id = KC.object_info('a')
381 380 reply = KC.get_shell_msg(timeout=2)
382 381 for tst in validate_message(reply, 'object_info_reply', msg_id):
383 382 yield tst
384 383
385 384
386 385 @dec.parametric
387 386 def test_oinfo_found():
388 387 flush_channels()
389 388
390 389 msg_id, reply = execute(code='a=5')
391 390
392 391 msg_id = KC.object_info('a')
393 392 reply = KC.get_shell_msg(timeout=2)
394 393 for tst in validate_message(reply, 'object_info_reply', msg_id):
395 394 yield tst
396 395 content = reply['content']
397 396 yield nt.assert_true(content['found'])
398 397 argspec = content['argspec']
399 398 yield nt.assert_true(argspec is None, "didn't expect argspec dict, got %r" % argspec)
400 399
401 400
402 401 @dec.parametric
403 402 def test_oinfo_detail():
404 403 flush_channels()
405 404
406 405 msg_id, reply = execute(code='ip=get_ipython()')
407 406
408 407 msg_id = KC.object_info('ip.object_inspect', detail_level=2)
409 408 reply = KC.get_shell_msg(timeout=2)
410 409 for tst in validate_message(reply, 'object_info_reply', msg_id):
411 410 yield tst
412 411 content = reply['content']
413 412 yield nt.assert_true(content['found'])
414 413 argspec = content['argspec']
415 414 yield nt.assert_true(isinstance(argspec, dict), "expected non-empty argspec dict, got %r" % argspec)
416 415 yield nt.assert_equal(argspec['defaults'], [0])
417 416
418 417
419 418 @dec.parametric
420 419 def test_oinfo_not_found():
421 420 flush_channels()
422 421
423 422 msg_id = KC.object_info('dne')
424 423 reply = KC.get_shell_msg(timeout=2)
425 424 for tst in validate_message(reply, 'object_info_reply', msg_id):
426 425 yield tst
427 426 content = reply['content']
428 427 yield nt.assert_false(content['found'])
429 428
430 429
431 430 @dec.parametric
432 431 def test_complete():
433 432 flush_channels()
434 433
435 434 msg_id, reply = execute(code="alpha = albert = 5")
436 435
437 436 msg_id = KC.complete('al', 'al', 2)
438 437 reply = KC.get_shell_msg(timeout=2)
439 438 for tst in validate_message(reply, 'complete_reply', msg_id):
440 439 yield tst
441 440 matches = reply['content']['matches']
442 441 for name in ('alpha', 'albert'):
443 442 yield nt.assert_true(name in matches, "Missing match: %r" % name)
444 443
445 444
446 445 @dec.parametric
447 446 def test_kernel_info_request():
448 447 flush_channels()
449 448
450 449 msg_id = KC.kernel_info()
451 450 reply = KC.get_shell_msg(timeout=2)
452 451 for tst in validate_message(reply, 'kernel_info_reply', msg_id):
453 452 yield tst
454 453
455 454
456 455 # IOPub channel
457 456
458 457
459 458 @dec.parametric
460 459 def test_stream():
461 460 flush_channels()
462 461
463 462 msg_id, reply = execute("print('hi')")
464 463
465 464 stdout = KC.iopub_channel.get_msg(timeout=2)
466 465 for tst in validate_message(stdout, 'stream', msg_id):
467 466 yield tst
468 467 content = stdout['content']
469 468 yield nt.assert_equal(content['name'], u'stdout')
470 469 yield nt.assert_equal(content['data'], u'hi\n')
471 470
472 471
473 472 @dec.parametric
474 473 def test_display_data():
475 474 flush_channels()
476 475
477 476 msg_id, reply = execute("from IPython.core.display import display; display(1)")
478 477
479 478 display = KC.iopub_channel.get_msg(timeout=2)
480 479 for tst in validate_message(display, 'display_data', parent=msg_id):
481 480 yield tst
482 481 data = display['content']['data']
483 482 yield nt.assert_equal(data['text/plain'], u'1')
484 483
General Comments 0
You need to be logged in to leave comments. Login now