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