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