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