##// END OF EJS Templates
Merge pull request #4120 from minrk/input-py2...
Thomas Kluyver -
r12336:f87f983a merge
parent child Browse files
Show More
@@ -1,204 +1,252 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 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.kernel import KernelManager
24 from IPython.kernel import KernelManager
25 from IPython.kernel.tests.test_message_spec import execute, flush_channels
25 from IPython.kernel.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
27 from IPython.utils import path, py3compat
28
28
29 #-------------------------------------------------------------------------------
29 #-------------------------------------------------------------------------------
30 # Tests
30 # Tests
31 #-------------------------------------------------------------------------------
31 #-------------------------------------------------------------------------------
32 IPYTHONDIR = None
32 IPYTHONDIR = None
33 save_env = None
33 save_env = None
34 save_get_ipython_dir = None
34 save_get_ipython_dir = None
35
35
36 STARTUP_TIMEOUT = 60
37 TIMEOUT = 15
38
36 def setup():
39 def setup():
37 """setup temporary IPYTHONDIR for tests"""
40 """setup temporary IPYTHONDIR for tests"""
38 global IPYTHONDIR
41 global IPYTHONDIR
39 global save_env
42 global save_env
40 global save_get_ipython_dir
43 global save_get_ipython_dir
41
44
42 IPYTHONDIR = tempfile.mkdtemp()
45 IPYTHONDIR = tempfile.mkdtemp()
43
46
44 save_env = os.environ.copy()
47 save_env = os.environ.copy()
45 os.environ["IPYTHONDIR"] = IPYTHONDIR
48 os.environ["IPYTHONDIR"] = IPYTHONDIR
46
49
47 save_get_ipython_dir = path.get_ipython_dir
50 save_get_ipython_dir = path.get_ipython_dir
48 path.get_ipython_dir = lambda : IPYTHONDIR
51 path.get_ipython_dir = lambda : IPYTHONDIR
49
52
50
53
51 def teardown():
54 def teardown():
52 path.get_ipython_dir = save_get_ipython_dir
55 path.get_ipython_dir = save_get_ipython_dir
53 os.environ = save_env
56 os.environ = save_env
54
57
55 try:
58 try:
56 shutil.rmtree(IPYTHONDIR)
59 shutil.rmtree(IPYTHONDIR)
57 except (OSError, IOError):
60 except (OSError, IOError):
58 # no such file
61 # no such file
59 pass
62 pass
60
63
61
64
62 @contextmanager
65 @contextmanager
63 def new_kernel():
66 def new_kernel():
64 """start a kernel in a subprocess, and wait for it to be ready
67 """start a kernel in a subprocess, and wait for it to be ready
65
68
66 Returns
69 Returns
67 -------
70 -------
68 kernel_manager: connected KernelManager instance
71 kernel_manager: connected KernelManager instance
69 """
72 """
70 KM = KernelManager()
73 KM = KernelManager()
71
74
72 KM.start_kernel(stdout=PIPE, stderr=PIPE)
75 KM.start_kernel(stdout=PIPE, stderr=PIPE)
73 KC = KM.client()
76 KC = KM.client()
74 KC.start_channels()
77 KC.start_channels()
75
78
76 # wait for kernel to be ready
79 # wait for kernel to be ready
77 KC.shell_channel.execute("import sys")
80 KC.shell_channel.execute("import sys")
78 KC.shell_channel.get_msg(block=True, timeout=5)
81 KC.shell_channel.get_msg(block=True, timeout=STARTUP_TIMEOUT)
79 flush_channels(KC)
82 flush_channels(KC)
80 try:
83 try:
81 yield KC
84 yield KC
82 finally:
85 finally:
83 KC.stop_channels()
86 KC.stop_channels()
84 KM.shutdown_kernel()
87 KM.shutdown_kernel()
85
88
86
89
87 def assemble_output(iopub):
90 def assemble_output(iopub):
88 """assemble stdout/err from an execution"""
91 """assemble stdout/err from an execution"""
89 stdout = ''
92 stdout = ''
90 stderr = ''
93 stderr = ''
91 while True:
94 while True:
92 msg = iopub.get_msg(block=True, timeout=1)
95 msg = iopub.get_msg(block=True, timeout=1)
93 msg_type = msg['msg_type']
96 msg_type = msg['msg_type']
94 content = msg['content']
97 content = msg['content']
95 if msg_type == 'status' and content['execution_state'] == 'idle':
98 if msg_type == 'status' and content['execution_state'] == 'idle':
96 # idle message signals end of output
99 # idle message signals end of output
97 break
100 break
98 elif msg['msg_type'] == 'stream':
101 elif msg['msg_type'] == 'stream':
99 if content['name'] == 'stdout':
102 if content['name'] == 'stdout':
100 stdout = stdout + content['data']
103 stdout = stdout + content['data']
101 elif content['name'] == 'stderr':
104 elif content['name'] == 'stderr':
102 stderr = stderr + content['data']
105 stderr = stderr + content['data']
103 else:
106 else:
104 raise KeyError("bad stream: %r" % content['name'])
107 raise KeyError("bad stream: %r" % content['name'])
105 else:
108 else:
106 # other output, ignored
109 # other output, ignored
107 pass
110 pass
108 return stdout, stderr
111 return stdout, stderr
109
112
110
113
111 def _check_mp_mode(kc, expected=False, stream="stdout"):
114 def _check_mp_mode(kc, expected=False, stream="stdout"):
112 execute(kc=kc, code="import sys")
115 execute(kc=kc, code="import sys")
113 flush_channels(kc)
116 flush_channels(kc)
114 msg_id, content = execute(kc=kc, code="print (sys.%s._check_mp_mode())" % stream)
117 msg_id, content = execute(kc=kc, code="print (sys.%s._check_mp_mode())" % stream)
115 stdout, stderr = assemble_output(kc.iopub_channel)
118 stdout, stderr = assemble_output(kc.iopub_channel)
116 nt.assert_equal(eval(stdout.strip()), expected)
119 nt.assert_equal(eval(stdout.strip()), expected)
117
120
118
121
122 # printing tests
123
119 def test_simple_print():
124 def test_simple_print():
120 """simple print statement in kernel"""
125 """simple print statement in kernel"""
121 with new_kernel() as kc:
126 with new_kernel() as kc:
122 iopub = kc.iopub_channel
127 iopub = kc.iopub_channel
123 msg_id, content = execute(kc=kc, code="print ('hi')")
128 msg_id, content = execute(kc=kc, code="print ('hi')")
124 stdout, stderr = assemble_output(iopub)
129 stdout, stderr = assemble_output(iopub)
125 nt.assert_equal(stdout, 'hi\n')
130 nt.assert_equal(stdout, 'hi\n')
126 nt.assert_equal(stderr, '')
131 nt.assert_equal(stderr, '')
127 _check_mp_mode(kc, expected=False)
132 _check_mp_mode(kc, expected=False)
128 print ('hello')
129
133
130
134
131 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
135 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
132 def test_subprocess_print():
136 def test_subprocess_print():
133 """printing from forked mp.Process"""
137 """printing from forked mp.Process"""
134 with new_kernel() as kc:
138 with new_kernel() as kc:
135 iopub = kc.iopub_channel
139 iopub = kc.iopub_channel
136
140
137 _check_mp_mode(kc, expected=False)
141 _check_mp_mode(kc, expected=False)
138 flush_channels(kc)
142 flush_channels(kc)
139 np = 5
143 np = 5
140 code = '\n'.join([
144 code = '\n'.join([
141 "from __future__ import print_function",
145 "from __future__ import print_function",
142 "import multiprocessing as mp",
146 "import multiprocessing as mp",
143 "pool = [mp.Process(target=print, args=('hello', i,)) for i in range(%i)]" % np,
147 "pool = [mp.Process(target=print, args=('hello', i,)) for i in range(%i)]" % np,
144 "for p in pool: p.start()",
148 "for p in pool: p.start()",
145 "for p in pool: p.join()"
149 "for p in pool: p.join()"
146 ])
150 ])
147
151
148 expected = '\n'.join([
152 expected = '\n'.join([
149 "hello %s" % i for i in range(np)
153 "hello %s" % i for i in range(np)
150 ]) + '\n'
154 ]) + '\n'
151
155
152 msg_id, content = execute(kc=kc, code=code)
156 msg_id, content = execute(kc=kc, code=code)
153 stdout, stderr = assemble_output(iopub)
157 stdout, stderr = assemble_output(iopub)
154 nt.assert_equal(stdout.count("hello"), np, stdout)
158 nt.assert_equal(stdout.count("hello"), np, stdout)
155 for n in range(np):
159 for n in range(np):
156 nt.assert_equal(stdout.count(str(n)), 1, stdout)
160 nt.assert_equal(stdout.count(str(n)), 1, stdout)
157 nt.assert_equal(stderr, '')
161 nt.assert_equal(stderr, '')
158 _check_mp_mode(kc, expected=False)
162 _check_mp_mode(kc, expected=False)
159 _check_mp_mode(kc, expected=False, stream="stderr")
163 _check_mp_mode(kc, expected=False, stream="stderr")
160
164
161
165
162 def test_subprocess_noprint():
166 def test_subprocess_noprint():
163 """mp.Process without print doesn't trigger iostream mp_mode"""
167 """mp.Process without print doesn't trigger iostream mp_mode"""
164 with new_kernel() as kc:
168 with new_kernel() as kc:
165 iopub = kc.iopub_channel
169 iopub = kc.iopub_channel
166
170
167 np = 5
171 np = 5
168 code = '\n'.join([
172 code = '\n'.join([
169 "import multiprocessing as mp",
173 "import multiprocessing as mp",
170 "pool = [mp.Process(target=range, args=(i,)) for i in range(%i)]" % np,
174 "pool = [mp.Process(target=range, args=(i,)) for i in range(%i)]" % np,
171 "for p in pool: p.start()",
175 "for p in pool: p.start()",
172 "for p in pool: p.join()"
176 "for p in pool: p.join()"
173 ])
177 ])
174
178
175 msg_id, content = execute(kc=kc, code=code)
179 msg_id, content = execute(kc=kc, code=code)
176 stdout, stderr = assemble_output(iopub)
180 stdout, stderr = assemble_output(iopub)
177 nt.assert_equal(stdout, '')
181 nt.assert_equal(stdout, '')
178 nt.assert_equal(stderr, '')
182 nt.assert_equal(stderr, '')
179
183
180 _check_mp_mode(kc, expected=False)
184 _check_mp_mode(kc, expected=False)
181 _check_mp_mode(kc, expected=False, stream="stderr")
185 _check_mp_mode(kc, expected=False, stream="stderr")
182
186
183
187
184 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
188 @dec.knownfailureif(sys.platform == 'win32', "subprocess prints fail on Windows")
185 def test_subprocess_error():
189 def test_subprocess_error():
186 """error in mp.Process doesn't crash"""
190 """error in mp.Process doesn't crash"""
187 with new_kernel() as kc:
191 with new_kernel() as kc:
188 iopub = kc.iopub_channel
192 iopub = kc.iopub_channel
189
193
190 code = '\n'.join([
194 code = '\n'.join([
191 "import multiprocessing as mp",
195 "import multiprocessing as mp",
192 "p = mp.Process(target=int, args=('hi',))",
196 "p = mp.Process(target=int, args=('hi',))",
193 "p.start()",
197 "p.start()",
194 "p.join()",
198 "p.join()",
195 ])
199 ])
196
200
197 msg_id, content = execute(kc=kc, code=code)
201 msg_id, content = execute(kc=kc, code=code)
198 stdout, stderr = assemble_output(iopub)
202 stdout, stderr = assemble_output(iopub)
199 nt.assert_equal(stdout, '')
203 nt.assert_equal(stdout, '')
200 nt.assert_true("ValueError" in stderr, stderr)
204 nt.assert_true("ValueError" in stderr, stderr)
201
205
202 _check_mp_mode(kc, expected=False)
206 _check_mp_mode(kc, expected=False)
203 _check_mp_mode(kc, expected=False, stream="stderr")
207 _check_mp_mode(kc, expected=False, stream="stderr")
204
208
209
210 # raw_input tests
211
212 def test_raw_input():
213 """test [raw_]input"""
214 with new_kernel() as kc:
215 iopub = kc.iopub_channel
216
217 input_f = "input" if py3compat.PY3 else "raw_input"
218 theprompt = "prompt> "
219 code = 'print({input_f}("{theprompt}"))'.format(**locals())
220 msg_id = kc.execute(code, allow_stdin=True)
221 msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT)
222 nt.assert_equal(msg['header']['msg_type'], u'input_request')
223 content = msg['content']
224 nt.assert_equal(content['prompt'], theprompt)
225 text = "some text"
226 kc.input(text)
227 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
228 nt.assert_equal(reply['content']['status'], 'ok')
229 stdout, stderr = assemble_output(iopub)
230 nt.assert_equal(stdout, text + "\n")
231
232
233 @dec.skipif(py3compat.PY3)
234 def test_eval_input():
235 """test input() on Python 2"""
236 with new_kernel() as kc:
237 iopub = kc.iopub_channel
238
239 input_f = "input" if py3compat.PY3 else "raw_input"
240 theprompt = "prompt> "
241 code = 'print(input("{theprompt}"))'.format(**locals())
242 msg_id = kc.execute(code, allow_stdin=True)
243 msg = kc.get_stdin_msg(block=True, timeout=TIMEOUT)
244 nt.assert_equal(msg['header']['msg_type'], u'input_request')
245 content = msg['content']
246 nt.assert_equal(content['prompt'], theprompt)
247 kc.input("1+1")
248 reply = kc.get_shell_msg(block=True, timeout=TIMEOUT)
249 nt.assert_equal(reply['content']['status'], 'ok')
250 stdout, stderr = assemble_output(iopub)
251 nt.assert_equal(stdout, "2\n")
252
@@ -1,806 +1,811 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports
18 # Standard library imports
19 import __builtin__
19 import __builtin__
20 import sys
20 import sys
21 import time
21 import time
22 import traceback
22 import traceback
23 import logging
23 import logging
24 import uuid
24 import uuid
25
25
26 from datetime import datetime
26 from datetime import datetime
27 from signal import (
27 from signal import (
28 signal, default_int_handler, SIGINT
28 signal, default_int_handler, SIGINT
29 )
29 )
30
30
31 # System library imports
31 # System library imports
32 import zmq
32 import zmq
33 from zmq.eventloop import ioloop
33 from zmq.eventloop import ioloop
34 from zmq.eventloop.zmqstream import ZMQStream
34 from zmq.eventloop.zmqstream import ZMQStream
35
35
36 # Local imports
36 # Local imports
37 from IPython.config.configurable import Configurable
37 from IPython.config.configurable import Configurable
38 from IPython.core.error import StdinNotImplementedError
38 from IPython.core.error import StdinNotImplementedError
39 from IPython.core import release
39 from IPython.core import release
40 from IPython.utils import py3compat
40 from IPython.utils import py3compat
41 from IPython.utils.jsonutil import json_clean
41 from IPython.utils.jsonutil import json_clean
42 from IPython.utils.traitlets import (
42 from IPython.utils.traitlets import (
43 Any, Instance, Float, Dict, List, Set, Integer, Unicode,
43 Any, Instance, Float, Dict, List, Set, Integer, Unicode,
44 Type
44 Type
45 )
45 )
46
46
47 from serialize import serialize_object, unpack_apply_message
47 from serialize import serialize_object, unpack_apply_message
48 from session import Session
48 from session import Session
49 from zmqshell import ZMQInteractiveShell
49 from zmqshell import ZMQInteractiveShell
50
50
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Main kernel class
53 # Main kernel class
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 protocol_version = list(release.kernel_protocol_version_info)
56 protocol_version = list(release.kernel_protocol_version_info)
57 ipython_version = list(release.version_info)
57 ipython_version = list(release.version_info)
58 language_version = list(sys.version_info[:3])
58 language_version = list(sys.version_info[:3])
59
59
60
60
61 class Kernel(Configurable):
61 class Kernel(Configurable):
62
62
63 #---------------------------------------------------------------------------
63 #---------------------------------------------------------------------------
64 # Kernel interface
64 # Kernel interface
65 #---------------------------------------------------------------------------
65 #---------------------------------------------------------------------------
66
66
67 # attribute to override with a GUI
67 # attribute to override with a GUI
68 eventloop = Any(None)
68 eventloop = Any(None)
69 def _eventloop_changed(self, name, old, new):
69 def _eventloop_changed(self, name, old, new):
70 """schedule call to eventloop from IOLoop"""
70 """schedule call to eventloop from IOLoop"""
71 loop = ioloop.IOLoop.instance()
71 loop = ioloop.IOLoop.instance()
72 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
72 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
73
73
74 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
74 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
75 shell_class = Type(ZMQInteractiveShell)
75 shell_class = Type(ZMQInteractiveShell)
76
76
77 session = Instance(Session)
77 session = Instance(Session)
78 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
78 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
79 shell_streams = List()
79 shell_streams = List()
80 control_stream = Instance(ZMQStream)
80 control_stream = Instance(ZMQStream)
81 iopub_socket = Instance(zmq.Socket)
81 iopub_socket = Instance(zmq.Socket)
82 stdin_socket = Instance(zmq.Socket)
82 stdin_socket = Instance(zmq.Socket)
83 log = Instance(logging.Logger)
83 log = Instance(logging.Logger)
84
84
85 user_module = Any()
85 user_module = Any()
86 def _user_module_changed(self, name, old, new):
86 def _user_module_changed(self, name, old, new):
87 if self.shell is not None:
87 if self.shell is not None:
88 self.shell.user_module = new
88 self.shell.user_module = new
89
89
90 user_ns = Dict(default_value=None)
90 user_ns = Dict(default_value=None)
91 def _user_ns_changed(self, name, old, new):
91 def _user_ns_changed(self, name, old, new):
92 if self.shell is not None:
92 if self.shell is not None:
93 self.shell.user_ns = new
93 self.shell.user_ns = new
94 self.shell.init_user_ns()
94 self.shell.init_user_ns()
95
95
96 # identities:
96 # identities:
97 int_id = Integer(-1)
97 int_id = Integer(-1)
98 ident = Unicode()
98 ident = Unicode()
99
99
100 def _ident_default(self):
100 def _ident_default(self):
101 return unicode(uuid.uuid4())
101 return unicode(uuid.uuid4())
102
102
103
103
104 # Private interface
104 # Private interface
105
105
106 # Time to sleep after flushing the stdout/err buffers in each execute
106 # Time to sleep after flushing the stdout/err buffers in each execute
107 # cycle. While this introduces a hard limit on the minimal latency of the
107 # cycle. While this introduces a hard limit on the minimal latency of the
108 # execute cycle, it helps prevent output synchronization problems for
108 # execute cycle, it helps prevent output synchronization problems for
109 # clients.
109 # clients.
110 # Units are in seconds. The minimum zmq latency on local host is probably
110 # Units are in seconds. The minimum zmq latency on local host is probably
111 # ~150 microseconds, set this to 500us for now. We may need to increase it
111 # ~150 microseconds, set this to 500us for now. We may need to increase it
112 # a little if it's not enough after more interactive testing.
112 # a little if it's not enough after more interactive testing.
113 _execute_sleep = Float(0.0005, config=True)
113 _execute_sleep = Float(0.0005, config=True)
114
114
115 # Frequency of the kernel's event loop.
115 # Frequency of the kernel's event loop.
116 # Units are in seconds, kernel subclasses for GUI toolkits may need to
116 # Units are in seconds, kernel subclasses for GUI toolkits may need to
117 # adapt to milliseconds.
117 # adapt to milliseconds.
118 _poll_interval = Float(0.05, config=True)
118 _poll_interval = Float(0.05, config=True)
119
119
120 # If the shutdown was requested over the network, we leave here the
120 # If the shutdown was requested over the network, we leave here the
121 # necessary reply message so it can be sent by our registered atexit
121 # necessary reply message so it can be sent by our registered atexit
122 # handler. This ensures that the reply is only sent to clients truly at
122 # handler. This ensures that the reply is only sent to clients truly at
123 # the end of our shutdown process (which happens after the underlying
123 # the end of our shutdown process (which happens after the underlying
124 # IPython shell's own shutdown).
124 # IPython shell's own shutdown).
125 _shutdown_message = None
125 _shutdown_message = None
126
126
127 # This is a dict of port number that the kernel is listening on. It is set
127 # This is a dict of port number that the kernel is listening on. It is set
128 # by record_ports and used by connect_request.
128 # by record_ports and used by connect_request.
129 _recorded_ports = Dict()
129 _recorded_ports = Dict()
130
130
131 # A reference to the Python builtin 'raw_input' function.
131 # A reference to the Python builtin 'raw_input' function.
132 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
132 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
133 _sys_raw_input = Any()
133 _sys_raw_input = Any()
134 _sys_eval_input = Any()
134
135
135 # set of aborted msg_ids
136 # set of aborted msg_ids
136 aborted = Set()
137 aborted = Set()
137
138
138
139
139 def __init__(self, **kwargs):
140 def __init__(self, **kwargs):
140 super(Kernel, self).__init__(**kwargs)
141 super(Kernel, self).__init__(**kwargs)
141
142
142 # Initialize the InteractiveShell subclass
143 # Initialize the InteractiveShell subclass
143 self.shell = self.shell_class.instance(parent=self,
144 self.shell = self.shell_class.instance(parent=self,
144 profile_dir = self.profile_dir,
145 profile_dir = self.profile_dir,
145 user_module = self.user_module,
146 user_module = self.user_module,
146 user_ns = self.user_ns,
147 user_ns = self.user_ns,
147 )
148 )
148 self.shell.displayhook.session = self.session
149 self.shell.displayhook.session = self.session
149 self.shell.displayhook.pub_socket = self.iopub_socket
150 self.shell.displayhook.pub_socket = self.iopub_socket
150 self.shell.displayhook.topic = self._topic('pyout')
151 self.shell.displayhook.topic = self._topic('pyout')
151 self.shell.display_pub.session = self.session
152 self.shell.display_pub.session = self.session
152 self.shell.display_pub.pub_socket = self.iopub_socket
153 self.shell.display_pub.pub_socket = self.iopub_socket
153 self.shell.data_pub.session = self.session
154 self.shell.data_pub.session = self.session
154 self.shell.data_pub.pub_socket = self.iopub_socket
155 self.shell.data_pub.pub_socket = self.iopub_socket
155
156
156 # TMP - hack while developing
157 # TMP - hack while developing
157 self.shell._reply_content = None
158 self.shell._reply_content = None
158
159
159 # Build dict of handlers for message types
160 # Build dict of handlers for message types
160 msg_types = [ 'execute_request', 'complete_request',
161 msg_types = [ 'execute_request', 'complete_request',
161 'object_info_request', 'history_request',
162 'object_info_request', 'history_request',
162 'kernel_info_request',
163 'kernel_info_request',
163 'connect_request', 'shutdown_request',
164 'connect_request', 'shutdown_request',
164 'apply_request',
165 'apply_request',
165 ]
166 ]
166 self.shell_handlers = {}
167 self.shell_handlers = {}
167 for msg_type in msg_types:
168 for msg_type in msg_types:
168 self.shell_handlers[msg_type] = getattr(self, msg_type)
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
169
170
170 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
171 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
171 self.control_handlers = {}
172 self.control_handlers = {}
172 for msg_type in control_msg_types:
173 for msg_type in control_msg_types:
173 self.control_handlers[msg_type] = getattr(self, msg_type)
174 self.control_handlers[msg_type] = getattr(self, msg_type)
174
175
175 def dispatch_control(self, msg):
176 def dispatch_control(self, msg):
176 """dispatch control requests"""
177 """dispatch control requests"""
177 idents,msg = self.session.feed_identities(msg, copy=False)
178 idents,msg = self.session.feed_identities(msg, copy=False)
178 try:
179 try:
179 msg = self.session.unserialize(msg, content=True, copy=False)
180 msg = self.session.unserialize(msg, content=True, copy=False)
180 except:
181 except:
181 self.log.error("Invalid Control Message", exc_info=True)
182 self.log.error("Invalid Control Message", exc_info=True)
182 return
183 return
183
184
184 self.log.debug("Control received: %s", msg)
185 self.log.debug("Control received: %s", msg)
185
186
186 header = msg['header']
187 header = msg['header']
187 msg_id = header['msg_id']
188 msg_id = header['msg_id']
188 msg_type = header['msg_type']
189 msg_type = header['msg_type']
189
190
190 handler = self.control_handlers.get(msg_type, None)
191 handler = self.control_handlers.get(msg_type, None)
191 if handler is None:
192 if handler is None:
192 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
193 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
193 else:
194 else:
194 try:
195 try:
195 handler(self.control_stream, idents, msg)
196 handler(self.control_stream, idents, msg)
196 except Exception:
197 except Exception:
197 self.log.error("Exception in control handler:", exc_info=True)
198 self.log.error("Exception in control handler:", exc_info=True)
198
199
199 def dispatch_shell(self, stream, msg):
200 def dispatch_shell(self, stream, msg):
200 """dispatch shell requests"""
201 """dispatch shell requests"""
201 # flush control requests first
202 # flush control requests first
202 if self.control_stream:
203 if self.control_stream:
203 self.control_stream.flush()
204 self.control_stream.flush()
204
205
205 idents,msg = self.session.feed_identities(msg, copy=False)
206 idents,msg = self.session.feed_identities(msg, copy=False)
206 try:
207 try:
207 msg = self.session.unserialize(msg, content=True, copy=False)
208 msg = self.session.unserialize(msg, content=True, copy=False)
208 except:
209 except:
209 self.log.error("Invalid Message", exc_info=True)
210 self.log.error("Invalid Message", exc_info=True)
210 return
211 return
211
212
212 header = msg['header']
213 header = msg['header']
213 msg_id = header['msg_id']
214 msg_id = header['msg_id']
214 msg_type = msg['header']['msg_type']
215 msg_type = msg['header']['msg_type']
215
216
216 # Print some info about this message and leave a '--->' marker, so it's
217 # Print some info about this message and leave a '--->' marker, so it's
217 # easier to trace visually the message chain when debugging. Each
218 # easier to trace visually the message chain when debugging. Each
218 # handler prints its message at the end.
219 # handler prints its message at the end.
219 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
220 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
220 self.log.debug(' Content: %s\n --->\n ', msg['content'])
221 self.log.debug(' Content: %s\n --->\n ', msg['content'])
221
222
222 if msg_id in self.aborted:
223 if msg_id in self.aborted:
223 self.aborted.remove(msg_id)
224 self.aborted.remove(msg_id)
224 # is it safe to assume a msg_id will not be resubmitted?
225 # is it safe to assume a msg_id will not be resubmitted?
225 reply_type = msg_type.split('_')[0] + '_reply'
226 reply_type = msg_type.split('_')[0] + '_reply'
226 status = {'status' : 'aborted'}
227 status = {'status' : 'aborted'}
227 md = {'engine' : self.ident}
228 md = {'engine' : self.ident}
228 md.update(status)
229 md.update(status)
229 reply_msg = self.session.send(stream, reply_type, metadata=md,
230 reply_msg = self.session.send(stream, reply_type, metadata=md,
230 content=status, parent=msg, ident=idents)
231 content=status, parent=msg, ident=idents)
231 return
232 return
232
233
233 handler = self.shell_handlers.get(msg_type, None)
234 handler = self.shell_handlers.get(msg_type, None)
234 if handler is None:
235 if handler is None:
235 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
236 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
236 else:
237 else:
237 # ensure default_int_handler during handler call
238 # ensure default_int_handler during handler call
238 sig = signal(SIGINT, default_int_handler)
239 sig = signal(SIGINT, default_int_handler)
239 try:
240 try:
240 handler(stream, idents, msg)
241 handler(stream, idents, msg)
241 except Exception:
242 except Exception:
242 self.log.error("Exception in message handler:", exc_info=True)
243 self.log.error("Exception in message handler:", exc_info=True)
243 finally:
244 finally:
244 signal(SIGINT, sig)
245 signal(SIGINT, sig)
245
246
246 def enter_eventloop(self):
247 def enter_eventloop(self):
247 """enter eventloop"""
248 """enter eventloop"""
248 self.log.info("entering eventloop")
249 self.log.info("entering eventloop")
249 # restore default_int_handler
250 # restore default_int_handler
250 signal(SIGINT, default_int_handler)
251 signal(SIGINT, default_int_handler)
251 while self.eventloop is not None:
252 while self.eventloop is not None:
252 try:
253 try:
253 self.eventloop(self)
254 self.eventloop(self)
254 except KeyboardInterrupt:
255 except KeyboardInterrupt:
255 # Ctrl-C shouldn't crash the kernel
256 # Ctrl-C shouldn't crash the kernel
256 self.log.error("KeyboardInterrupt caught in kernel")
257 self.log.error("KeyboardInterrupt caught in kernel")
257 continue
258 continue
258 else:
259 else:
259 # eventloop exited cleanly, this means we should stop (right?)
260 # eventloop exited cleanly, this means we should stop (right?)
260 self.eventloop = None
261 self.eventloop = None
261 break
262 break
262 self.log.info("exiting eventloop")
263 self.log.info("exiting eventloop")
263
264
264 def start(self):
265 def start(self):
265 """register dispatchers for streams"""
266 """register dispatchers for streams"""
266 self.shell.exit_now = False
267 self.shell.exit_now = False
267 if self.control_stream:
268 if self.control_stream:
268 self.control_stream.on_recv(self.dispatch_control, copy=False)
269 self.control_stream.on_recv(self.dispatch_control, copy=False)
269
270
270 def make_dispatcher(stream):
271 def make_dispatcher(stream):
271 def dispatcher(msg):
272 def dispatcher(msg):
272 return self.dispatch_shell(stream, msg)
273 return self.dispatch_shell(stream, msg)
273 return dispatcher
274 return dispatcher
274
275
275 for s in self.shell_streams:
276 for s in self.shell_streams:
276 s.on_recv(make_dispatcher(s), copy=False)
277 s.on_recv(make_dispatcher(s), copy=False)
277
278
278 # publish idle status
279 # publish idle status
279 self._publish_status('starting')
280 self._publish_status('starting')
280
281
281 def do_one_iteration(self):
282 def do_one_iteration(self):
282 """step eventloop just once"""
283 """step eventloop just once"""
283 if self.control_stream:
284 if self.control_stream:
284 self.control_stream.flush()
285 self.control_stream.flush()
285 for stream in self.shell_streams:
286 for stream in self.shell_streams:
286 # handle at most one request per iteration
287 # handle at most one request per iteration
287 stream.flush(zmq.POLLIN, 1)
288 stream.flush(zmq.POLLIN, 1)
288 stream.flush(zmq.POLLOUT)
289 stream.flush(zmq.POLLOUT)
289
290
290
291
291 def record_ports(self, ports):
292 def record_ports(self, ports):
292 """Record the ports that this kernel is using.
293 """Record the ports that this kernel is using.
293
294
294 The creator of the Kernel instance must call this methods if they
295 The creator of the Kernel instance must call this methods if they
295 want the :meth:`connect_request` method to return the port numbers.
296 want the :meth:`connect_request` method to return the port numbers.
296 """
297 """
297 self._recorded_ports = ports
298 self._recorded_ports = ports
298
299
299 #---------------------------------------------------------------------------
300 #---------------------------------------------------------------------------
300 # Kernel request handlers
301 # Kernel request handlers
301 #---------------------------------------------------------------------------
302 #---------------------------------------------------------------------------
302
303
303 def _make_metadata(self, other=None):
304 def _make_metadata(self, other=None):
304 """init metadata dict, for execute/apply_reply"""
305 """init metadata dict, for execute/apply_reply"""
305 new_md = {
306 new_md = {
306 'dependencies_met' : True,
307 'dependencies_met' : True,
307 'engine' : self.ident,
308 'engine' : self.ident,
308 'started': datetime.now(),
309 'started': datetime.now(),
309 }
310 }
310 if other:
311 if other:
311 new_md.update(other)
312 new_md.update(other)
312 return new_md
313 return new_md
313
314
314 def _publish_pyin(self, code, parent, execution_count):
315 def _publish_pyin(self, code, parent, execution_count):
315 """Publish the code request on the pyin stream."""
316 """Publish the code request on the pyin stream."""
316
317
317 self.session.send(self.iopub_socket, u'pyin',
318 self.session.send(self.iopub_socket, u'pyin',
318 {u'code':code, u'execution_count': execution_count},
319 {u'code':code, u'execution_count': execution_count},
319 parent=parent, ident=self._topic('pyin')
320 parent=parent, ident=self._topic('pyin')
320 )
321 )
321
322
322 def _publish_status(self, status, parent=None):
323 def _publish_status(self, status, parent=None):
323 """send status (busy/idle) on IOPub"""
324 """send status (busy/idle) on IOPub"""
324 self.session.send(self.iopub_socket,
325 self.session.send(self.iopub_socket,
325 u'status',
326 u'status',
326 {u'execution_state': status},
327 {u'execution_state': status},
327 parent=parent,
328 parent=parent,
328 ident=self._topic('status'),
329 ident=self._topic('status'),
329 )
330 )
330
331
331
332
332 def execute_request(self, stream, ident, parent):
333 def execute_request(self, stream, ident, parent):
333 """handle an execute_request"""
334 """handle an execute_request"""
334
335
335 self._publish_status(u'busy', parent)
336 self._publish_status(u'busy', parent)
336
337
337 try:
338 try:
338 content = parent[u'content']
339 content = parent[u'content']
339 code = content[u'code']
340 code = content[u'code']
340 silent = content[u'silent']
341 silent = content[u'silent']
341 store_history = content.get(u'store_history', not silent)
342 store_history = content.get(u'store_history', not silent)
342 except:
343 except:
343 self.log.error("Got bad msg: ")
344 self.log.error("Got bad msg: ")
344 self.log.error("%s", parent)
345 self.log.error("%s", parent)
345 return
346 return
346
347
347 md = self._make_metadata(parent['metadata'])
348 md = self._make_metadata(parent['metadata'])
348
349
349 shell = self.shell # we'll need this a lot here
350 shell = self.shell # we'll need this a lot here
350
351
351 # Replace raw_input. Note that is not sufficient to replace
352 # Replace raw_input. Note that is not sufficient to replace
352 # raw_input in the user namespace.
353 # raw_input in the user namespace.
353 if content.get('allow_stdin', False):
354 if content.get('allow_stdin', False):
354 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
355 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
356 input = lambda prompt='': eval(raw_input(prompt))
355 else:
357 else:
356 raw_input = lambda prompt='' : self._no_raw_input()
358 raw_input = input = lambda prompt='' : self._no_raw_input()
357
359
358 if py3compat.PY3:
360 if py3compat.PY3:
359 self._sys_raw_input = __builtin__.input
361 self._sys_raw_input = __builtin__.input
360 __builtin__.input = raw_input
362 __builtin__.input = raw_input
361 else:
363 else:
362 self._sys_raw_input = __builtin__.raw_input
364 self._sys_raw_input = __builtin__.raw_input
365 self._sys_eval_input = __builtin__.input
363 __builtin__.raw_input = raw_input
366 __builtin__.raw_input = raw_input
367 __builtin__.input = input
364
368
365 # Set the parent message of the display hook and out streams.
369 # Set the parent message of the display hook and out streams.
366 shell.displayhook.set_parent(parent)
370 shell.displayhook.set_parent(parent)
367 shell.display_pub.set_parent(parent)
371 shell.display_pub.set_parent(parent)
368 shell.data_pub.set_parent(parent)
372 shell.data_pub.set_parent(parent)
369 try:
373 try:
370 sys.stdout.set_parent(parent)
374 sys.stdout.set_parent(parent)
371 except AttributeError:
375 except AttributeError:
372 pass
376 pass
373 try:
377 try:
374 sys.stderr.set_parent(parent)
378 sys.stderr.set_parent(parent)
375 except AttributeError:
379 except AttributeError:
376 pass
380 pass
377
381
378 # Re-broadcast our input for the benefit of listening clients, and
382 # Re-broadcast our input for the benefit of listening clients, and
379 # start computing output
383 # start computing output
380 if not silent:
384 if not silent:
381 self._publish_pyin(code, parent, shell.execution_count)
385 self._publish_pyin(code, parent, shell.execution_count)
382
386
383 reply_content = {}
387 reply_content = {}
384 try:
388 try:
385 # FIXME: the shell calls the exception handler itself.
389 # FIXME: the shell calls the exception handler itself.
386 shell.run_cell(code, store_history=store_history, silent=silent)
390 shell.run_cell(code, store_history=store_history, silent=silent)
387 except:
391 except:
388 status = u'error'
392 status = u'error'
389 # FIXME: this code right now isn't being used yet by default,
393 # FIXME: this code right now isn't being used yet by default,
390 # because the run_cell() call above directly fires off exception
394 # because the run_cell() call above directly fires off exception
391 # reporting. This code, therefore, is only active in the scenario
395 # reporting. This code, therefore, is only active in the scenario
392 # where runlines itself has an unhandled exception. We need to
396 # where runlines itself has an unhandled exception. We need to
393 # uniformize this, for all exception construction to come from a
397 # uniformize this, for all exception construction to come from a
394 # single location in the codbase.
398 # single location in the codbase.
395 etype, evalue, tb = sys.exc_info()
399 etype, evalue, tb = sys.exc_info()
396 tb_list = traceback.format_exception(etype, evalue, tb)
400 tb_list = traceback.format_exception(etype, evalue, tb)
397 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
401 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
398 else:
402 else:
399 status = u'ok'
403 status = u'ok'
400 finally:
404 finally:
401 # Restore raw_input.
405 # Restore raw_input.
402 if py3compat.PY3:
406 if py3compat.PY3:
403 __builtin__.input = self._sys_raw_input
407 __builtin__.input = self._sys_raw_input
404 else:
408 else:
405 __builtin__.raw_input = self._sys_raw_input
409 __builtin__.raw_input = self._sys_raw_input
410 __builtin__.input = self._sys_eval_input
406
411
407 reply_content[u'status'] = status
412 reply_content[u'status'] = status
408
413
409 # Return the execution counter so clients can display prompts
414 # Return the execution counter so clients can display prompts
410 reply_content['execution_count'] = shell.execution_count - 1
415 reply_content['execution_count'] = shell.execution_count - 1
411
416
412 # FIXME - fish exception info out of shell, possibly left there by
417 # FIXME - fish exception info out of shell, possibly left there by
413 # runlines. We'll need to clean up this logic later.
418 # runlines. We'll need to clean up this logic later.
414 if shell._reply_content is not None:
419 if shell._reply_content is not None:
415 reply_content.update(shell._reply_content)
420 reply_content.update(shell._reply_content)
416 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
421 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
417 reply_content['engine_info'] = e_info
422 reply_content['engine_info'] = e_info
418 # reset after use
423 # reset after use
419 shell._reply_content = None
424 shell._reply_content = None
420
425
421 if 'traceback' in reply_content:
426 if 'traceback' in reply_content:
422 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
427 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
423
428
424
429
425 # At this point, we can tell whether the main code execution succeeded
430 # At this point, we can tell whether the main code execution succeeded
426 # or not. If it did, we proceed to evaluate user_variables/expressions
431 # or not. If it did, we proceed to evaluate user_variables/expressions
427 if reply_content['status'] == 'ok':
432 if reply_content['status'] == 'ok':
428 reply_content[u'user_variables'] = \
433 reply_content[u'user_variables'] = \
429 shell.user_variables(content.get(u'user_variables', []))
434 shell.user_variables(content.get(u'user_variables', []))
430 reply_content[u'user_expressions'] = \
435 reply_content[u'user_expressions'] = \
431 shell.user_expressions(content.get(u'user_expressions', {}))
436 shell.user_expressions(content.get(u'user_expressions', {}))
432 else:
437 else:
433 # If there was an error, don't even try to compute variables or
438 # If there was an error, don't even try to compute variables or
434 # expressions
439 # expressions
435 reply_content[u'user_variables'] = {}
440 reply_content[u'user_variables'] = {}
436 reply_content[u'user_expressions'] = {}
441 reply_content[u'user_expressions'] = {}
437
442
438 # Payloads should be retrieved regardless of outcome, so we can both
443 # Payloads should be retrieved regardless of outcome, so we can both
439 # recover partial output (that could have been generated early in a
444 # recover partial output (that could have been generated early in a
440 # block, before an error) and clear the payload system always.
445 # block, before an error) and clear the payload system always.
441 reply_content[u'payload'] = shell.payload_manager.read_payload()
446 reply_content[u'payload'] = shell.payload_manager.read_payload()
442 # Be agressive about clearing the payload because we don't want
447 # Be agressive about clearing the payload because we don't want
443 # it to sit in memory until the next execute_request comes in.
448 # it to sit in memory until the next execute_request comes in.
444 shell.payload_manager.clear_payload()
449 shell.payload_manager.clear_payload()
445
450
446 # Flush output before sending the reply.
451 # Flush output before sending the reply.
447 sys.stdout.flush()
452 sys.stdout.flush()
448 sys.stderr.flush()
453 sys.stderr.flush()
449 # FIXME: on rare occasions, the flush doesn't seem to make it to the
454 # FIXME: on rare occasions, the flush doesn't seem to make it to the
450 # clients... This seems to mitigate the problem, but we definitely need
455 # clients... This seems to mitigate the problem, but we definitely need
451 # to better understand what's going on.
456 # to better understand what's going on.
452 if self._execute_sleep:
457 if self._execute_sleep:
453 time.sleep(self._execute_sleep)
458 time.sleep(self._execute_sleep)
454
459
455 # Send the reply.
460 # Send the reply.
456 reply_content = json_clean(reply_content)
461 reply_content = json_clean(reply_content)
457
462
458 md['status'] = reply_content['status']
463 md['status'] = reply_content['status']
459 if reply_content['status'] == 'error' and \
464 if reply_content['status'] == 'error' and \
460 reply_content['ename'] == 'UnmetDependency':
465 reply_content['ename'] == 'UnmetDependency':
461 md['dependencies_met'] = False
466 md['dependencies_met'] = False
462
467
463 reply_msg = self.session.send(stream, u'execute_reply',
468 reply_msg = self.session.send(stream, u'execute_reply',
464 reply_content, parent, metadata=md,
469 reply_content, parent, metadata=md,
465 ident=ident)
470 ident=ident)
466
471
467 self.log.debug("%s", reply_msg)
472 self.log.debug("%s", reply_msg)
468
473
469 if not silent and reply_msg['content']['status'] == u'error':
474 if not silent and reply_msg['content']['status'] == u'error':
470 self._abort_queues()
475 self._abort_queues()
471
476
472 self._publish_status(u'idle', parent)
477 self._publish_status(u'idle', parent)
473
478
474 def complete_request(self, stream, ident, parent):
479 def complete_request(self, stream, ident, parent):
475 txt, matches = self._complete(parent)
480 txt, matches = self._complete(parent)
476 matches = {'matches' : matches,
481 matches = {'matches' : matches,
477 'matched_text' : txt,
482 'matched_text' : txt,
478 'status' : 'ok'}
483 'status' : 'ok'}
479 matches = json_clean(matches)
484 matches = json_clean(matches)
480 completion_msg = self.session.send(stream, 'complete_reply',
485 completion_msg = self.session.send(stream, 'complete_reply',
481 matches, parent, ident)
486 matches, parent, ident)
482 self.log.debug("%s", completion_msg)
487 self.log.debug("%s", completion_msg)
483
488
484 def object_info_request(self, stream, ident, parent):
489 def object_info_request(self, stream, ident, parent):
485 content = parent['content']
490 content = parent['content']
486 object_info = self.shell.object_inspect(content['oname'],
491 object_info = self.shell.object_inspect(content['oname'],
487 detail_level = content.get('detail_level', 0)
492 detail_level = content.get('detail_level', 0)
488 )
493 )
489 # Before we send this object over, we scrub it for JSON usage
494 # Before we send this object over, we scrub it for JSON usage
490 oinfo = json_clean(object_info)
495 oinfo = json_clean(object_info)
491 msg = self.session.send(stream, 'object_info_reply',
496 msg = self.session.send(stream, 'object_info_reply',
492 oinfo, parent, ident)
497 oinfo, parent, ident)
493 self.log.debug("%s", msg)
498 self.log.debug("%s", msg)
494
499
495 def history_request(self, stream, ident, parent):
500 def history_request(self, stream, ident, parent):
496 # We need to pull these out, as passing **kwargs doesn't work with
501 # We need to pull these out, as passing **kwargs doesn't work with
497 # unicode keys before Python 2.6.5.
502 # unicode keys before Python 2.6.5.
498 hist_access_type = parent['content']['hist_access_type']
503 hist_access_type = parent['content']['hist_access_type']
499 raw = parent['content']['raw']
504 raw = parent['content']['raw']
500 output = parent['content']['output']
505 output = parent['content']['output']
501 if hist_access_type == 'tail':
506 if hist_access_type == 'tail':
502 n = parent['content']['n']
507 n = parent['content']['n']
503 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
508 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
504 include_latest=True)
509 include_latest=True)
505
510
506 elif hist_access_type == 'range':
511 elif hist_access_type == 'range':
507 session = parent['content']['session']
512 session = parent['content']['session']
508 start = parent['content']['start']
513 start = parent['content']['start']
509 stop = parent['content']['stop']
514 stop = parent['content']['stop']
510 hist = self.shell.history_manager.get_range(session, start, stop,
515 hist = self.shell.history_manager.get_range(session, start, stop,
511 raw=raw, output=output)
516 raw=raw, output=output)
512
517
513 elif hist_access_type == 'search':
518 elif hist_access_type == 'search':
514 n = parent['content'].get('n')
519 n = parent['content'].get('n')
515 unique = parent['content'].get('unique', False)
520 unique = parent['content'].get('unique', False)
516 pattern = parent['content']['pattern']
521 pattern = parent['content']['pattern']
517 hist = self.shell.history_manager.search(
522 hist = self.shell.history_manager.search(
518 pattern, raw=raw, output=output, n=n, unique=unique)
523 pattern, raw=raw, output=output, n=n, unique=unique)
519
524
520 else:
525 else:
521 hist = []
526 hist = []
522 hist = list(hist)
527 hist = list(hist)
523 content = {'history' : hist}
528 content = {'history' : hist}
524 content = json_clean(content)
529 content = json_clean(content)
525 msg = self.session.send(stream, 'history_reply',
530 msg = self.session.send(stream, 'history_reply',
526 content, parent, ident)
531 content, parent, ident)
527 self.log.debug("Sending history reply with %i entries", len(hist))
532 self.log.debug("Sending history reply with %i entries", len(hist))
528
533
529 def connect_request(self, stream, ident, parent):
534 def connect_request(self, stream, ident, parent):
530 if self._recorded_ports is not None:
535 if self._recorded_ports is not None:
531 content = self._recorded_ports.copy()
536 content = self._recorded_ports.copy()
532 else:
537 else:
533 content = {}
538 content = {}
534 msg = self.session.send(stream, 'connect_reply',
539 msg = self.session.send(stream, 'connect_reply',
535 content, parent, ident)
540 content, parent, ident)
536 self.log.debug("%s", msg)
541 self.log.debug("%s", msg)
537
542
538 def kernel_info_request(self, stream, ident, parent):
543 def kernel_info_request(self, stream, ident, parent):
539 vinfo = {
544 vinfo = {
540 'protocol_version': protocol_version,
545 'protocol_version': protocol_version,
541 'ipython_version': ipython_version,
546 'ipython_version': ipython_version,
542 'language_version': language_version,
547 'language_version': language_version,
543 'language': 'python',
548 'language': 'python',
544 }
549 }
545 msg = self.session.send(stream, 'kernel_info_reply',
550 msg = self.session.send(stream, 'kernel_info_reply',
546 vinfo, parent, ident)
551 vinfo, parent, ident)
547 self.log.debug("%s", msg)
552 self.log.debug("%s", msg)
548
553
549 def shutdown_request(self, stream, ident, parent):
554 def shutdown_request(self, stream, ident, parent):
550 self.shell.exit_now = True
555 self.shell.exit_now = True
551 content = dict(status='ok')
556 content = dict(status='ok')
552 content.update(parent['content'])
557 content.update(parent['content'])
553 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
558 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
554 # same content, but different msg_id for broadcasting on IOPub
559 # same content, but different msg_id for broadcasting on IOPub
555 self._shutdown_message = self.session.msg(u'shutdown_reply',
560 self._shutdown_message = self.session.msg(u'shutdown_reply',
556 content, parent
561 content, parent
557 )
562 )
558
563
559 self._at_shutdown()
564 self._at_shutdown()
560 # call sys.exit after a short delay
565 # call sys.exit after a short delay
561 loop = ioloop.IOLoop.instance()
566 loop = ioloop.IOLoop.instance()
562 loop.add_timeout(time.time()+0.1, loop.stop)
567 loop.add_timeout(time.time()+0.1, loop.stop)
563
568
564 #---------------------------------------------------------------------------
569 #---------------------------------------------------------------------------
565 # Engine methods
570 # Engine methods
566 #---------------------------------------------------------------------------
571 #---------------------------------------------------------------------------
567
572
568 def apply_request(self, stream, ident, parent):
573 def apply_request(self, stream, ident, parent):
569 try:
574 try:
570 content = parent[u'content']
575 content = parent[u'content']
571 bufs = parent[u'buffers']
576 bufs = parent[u'buffers']
572 msg_id = parent['header']['msg_id']
577 msg_id = parent['header']['msg_id']
573 except:
578 except:
574 self.log.error("Got bad msg: %s", parent, exc_info=True)
579 self.log.error("Got bad msg: %s", parent, exc_info=True)
575 return
580 return
576
581
577 self._publish_status(u'busy', parent)
582 self._publish_status(u'busy', parent)
578
583
579 # Set the parent message of the display hook and out streams.
584 # Set the parent message of the display hook and out streams.
580 shell = self.shell
585 shell = self.shell
581 shell.displayhook.set_parent(parent)
586 shell.displayhook.set_parent(parent)
582 shell.display_pub.set_parent(parent)
587 shell.display_pub.set_parent(parent)
583 shell.data_pub.set_parent(parent)
588 shell.data_pub.set_parent(parent)
584 try:
589 try:
585 sys.stdout.set_parent(parent)
590 sys.stdout.set_parent(parent)
586 except AttributeError:
591 except AttributeError:
587 pass
592 pass
588 try:
593 try:
589 sys.stderr.set_parent(parent)
594 sys.stderr.set_parent(parent)
590 except AttributeError:
595 except AttributeError:
591 pass
596 pass
592
597
593 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
598 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
594 # self.iopub_socket.send(pyin_msg)
599 # self.iopub_socket.send(pyin_msg)
595 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
600 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
596 md = self._make_metadata(parent['metadata'])
601 md = self._make_metadata(parent['metadata'])
597 try:
602 try:
598 working = shell.user_ns
603 working = shell.user_ns
599
604
600 prefix = "_"+str(msg_id).replace("-","")+"_"
605 prefix = "_"+str(msg_id).replace("-","")+"_"
601
606
602 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
607 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
603
608
604 fname = getattr(f, '__name__', 'f')
609 fname = getattr(f, '__name__', 'f')
605
610
606 fname = prefix+"f"
611 fname = prefix+"f"
607 argname = prefix+"args"
612 argname = prefix+"args"
608 kwargname = prefix+"kwargs"
613 kwargname = prefix+"kwargs"
609 resultname = prefix+"result"
614 resultname = prefix+"result"
610
615
611 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
616 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
612 # print ns
617 # print ns
613 working.update(ns)
618 working.update(ns)
614 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
619 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
615 try:
620 try:
616 exec code in shell.user_global_ns, shell.user_ns
621 exec code in shell.user_global_ns, shell.user_ns
617 result = working.get(resultname)
622 result = working.get(resultname)
618 finally:
623 finally:
619 for key in ns.iterkeys():
624 for key in ns.iterkeys():
620 working.pop(key)
625 working.pop(key)
621
626
622 result_buf = serialize_object(result,
627 result_buf = serialize_object(result,
623 buffer_threshold=self.session.buffer_threshold,
628 buffer_threshold=self.session.buffer_threshold,
624 item_threshold=self.session.item_threshold,
629 item_threshold=self.session.item_threshold,
625 )
630 )
626
631
627 except:
632 except:
628 # invoke IPython traceback formatting
633 # invoke IPython traceback formatting
629 shell.showtraceback()
634 shell.showtraceback()
630 # FIXME - fish exception info out of shell, possibly left there by
635 # FIXME - fish exception info out of shell, possibly left there by
631 # run_code. We'll need to clean up this logic later.
636 # run_code. We'll need to clean up this logic later.
632 reply_content = {}
637 reply_content = {}
633 if shell._reply_content is not None:
638 if shell._reply_content is not None:
634 reply_content.update(shell._reply_content)
639 reply_content.update(shell._reply_content)
635 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
640 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
636 reply_content['engine_info'] = e_info
641 reply_content['engine_info'] = e_info
637 # reset after use
642 # reset after use
638 shell._reply_content = None
643 shell._reply_content = None
639
644
640 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
645 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
641 ident=self._topic('pyerr'))
646 ident=self._topic('pyerr'))
642 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
647 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
643 result_buf = []
648 result_buf = []
644
649
645 if reply_content['ename'] == 'UnmetDependency':
650 if reply_content['ename'] == 'UnmetDependency':
646 md['dependencies_met'] = False
651 md['dependencies_met'] = False
647 else:
652 else:
648 reply_content = {'status' : 'ok'}
653 reply_content = {'status' : 'ok'}
649
654
650 # put 'ok'/'error' status in header, for scheduler introspection:
655 # put 'ok'/'error' status in header, for scheduler introspection:
651 md['status'] = reply_content['status']
656 md['status'] = reply_content['status']
652
657
653 # flush i/o
658 # flush i/o
654 sys.stdout.flush()
659 sys.stdout.flush()
655 sys.stderr.flush()
660 sys.stderr.flush()
656
661
657 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
662 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
658 parent=parent, ident=ident,buffers=result_buf, metadata=md)
663 parent=parent, ident=ident,buffers=result_buf, metadata=md)
659
664
660 self._publish_status(u'idle', parent)
665 self._publish_status(u'idle', parent)
661
666
662 #---------------------------------------------------------------------------
667 #---------------------------------------------------------------------------
663 # Control messages
668 # Control messages
664 #---------------------------------------------------------------------------
669 #---------------------------------------------------------------------------
665
670
666 def abort_request(self, stream, ident, parent):
671 def abort_request(self, stream, ident, parent):
667 """abort a specifig msg by id"""
672 """abort a specifig msg by id"""
668 msg_ids = parent['content'].get('msg_ids', None)
673 msg_ids = parent['content'].get('msg_ids', None)
669 if isinstance(msg_ids, basestring):
674 if isinstance(msg_ids, basestring):
670 msg_ids = [msg_ids]
675 msg_ids = [msg_ids]
671 if not msg_ids:
676 if not msg_ids:
672 self.abort_queues()
677 self.abort_queues()
673 for mid in msg_ids:
678 for mid in msg_ids:
674 self.aborted.add(str(mid))
679 self.aborted.add(str(mid))
675
680
676 content = dict(status='ok')
681 content = dict(status='ok')
677 reply_msg = self.session.send(stream, 'abort_reply', content=content,
682 reply_msg = self.session.send(stream, 'abort_reply', content=content,
678 parent=parent, ident=ident)
683 parent=parent, ident=ident)
679 self.log.debug("%s", reply_msg)
684 self.log.debug("%s", reply_msg)
680
685
681 def clear_request(self, stream, idents, parent):
686 def clear_request(self, stream, idents, parent):
682 """Clear our namespace."""
687 """Clear our namespace."""
683 self.shell.reset(False)
688 self.shell.reset(False)
684 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
689 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
685 content = dict(status='ok'))
690 content = dict(status='ok'))
686
691
687
692
688 #---------------------------------------------------------------------------
693 #---------------------------------------------------------------------------
689 # Protected interface
694 # Protected interface
690 #---------------------------------------------------------------------------
695 #---------------------------------------------------------------------------
691
696
692 def _wrap_exception(self, method=None):
697 def _wrap_exception(self, method=None):
693 # import here, because _wrap_exception is only used in parallel,
698 # import here, because _wrap_exception is only used in parallel,
694 # and parallel has higher min pyzmq version
699 # and parallel has higher min pyzmq version
695 from IPython.parallel.error import wrap_exception
700 from IPython.parallel.error import wrap_exception
696 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
701 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
697 content = wrap_exception(e_info)
702 content = wrap_exception(e_info)
698 return content
703 return content
699
704
700 def _topic(self, topic):
705 def _topic(self, topic):
701 """prefixed topic for IOPub messages"""
706 """prefixed topic for IOPub messages"""
702 if self.int_id >= 0:
707 if self.int_id >= 0:
703 base = "engine.%i" % self.int_id
708 base = "engine.%i" % self.int_id
704 else:
709 else:
705 base = "kernel.%s" % self.ident
710 base = "kernel.%s" % self.ident
706
711
707 return py3compat.cast_bytes("%s.%s" % (base, topic))
712 return py3compat.cast_bytes("%s.%s" % (base, topic))
708
713
709 def _abort_queues(self):
714 def _abort_queues(self):
710 for stream in self.shell_streams:
715 for stream in self.shell_streams:
711 if stream:
716 if stream:
712 self._abort_queue(stream)
717 self._abort_queue(stream)
713
718
714 def _abort_queue(self, stream):
719 def _abort_queue(self, stream):
715 poller = zmq.Poller()
720 poller = zmq.Poller()
716 poller.register(stream.socket, zmq.POLLIN)
721 poller.register(stream.socket, zmq.POLLIN)
717 while True:
722 while True:
718 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
723 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
719 if msg is None:
724 if msg is None:
720 return
725 return
721
726
722 self.log.info("Aborting:")
727 self.log.info("Aborting:")
723 self.log.info("%s", msg)
728 self.log.info("%s", msg)
724 msg_type = msg['header']['msg_type']
729 msg_type = msg['header']['msg_type']
725 reply_type = msg_type.split('_')[0] + '_reply'
730 reply_type = msg_type.split('_')[0] + '_reply'
726
731
727 status = {'status' : 'aborted'}
732 status = {'status' : 'aborted'}
728 md = {'engine' : self.ident}
733 md = {'engine' : self.ident}
729 md.update(status)
734 md.update(status)
730 reply_msg = self.session.send(stream, reply_type, metadata=md,
735 reply_msg = self.session.send(stream, reply_type, metadata=md,
731 content=status, parent=msg, ident=idents)
736 content=status, parent=msg, ident=idents)
732 self.log.debug("%s", reply_msg)
737 self.log.debug("%s", reply_msg)
733 # We need to wait a bit for requests to come in. This can probably
738 # We need to wait a bit for requests to come in. This can probably
734 # be set shorter for true asynchronous clients.
739 # be set shorter for true asynchronous clients.
735 poller.poll(50)
740 poller.poll(50)
736
741
737
742
738 def _no_raw_input(self):
743 def _no_raw_input(self):
739 """Raise StdinNotImplentedError if active frontend doesn't support
744 """Raise StdinNotImplentedError if active frontend doesn't support
740 stdin."""
745 stdin."""
741 raise StdinNotImplementedError("raw_input was called, but this "
746 raise StdinNotImplementedError("raw_input was called, but this "
742 "frontend does not support stdin.")
747 "frontend does not support stdin.")
743
748
744 def _raw_input(self, prompt, ident, parent):
749 def _raw_input(self, prompt, ident, parent):
745 # Flush output before making the request.
750 # Flush output before making the request.
746 sys.stderr.flush()
751 sys.stderr.flush()
747 sys.stdout.flush()
752 sys.stdout.flush()
748 # flush the stdin socket, to purge stale replies
753 # flush the stdin socket, to purge stale replies
749 while True:
754 while True:
750 try:
755 try:
751 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
756 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
752 except zmq.ZMQError as e:
757 except zmq.ZMQError as e:
753 if e.errno == zmq.EAGAIN:
758 if e.errno == zmq.EAGAIN:
754 break
759 break
755 else:
760 else:
756 raise
761 raise
757
762
758 # Send the input request.
763 # Send the input request.
759 content = json_clean(dict(prompt=prompt))
764 content = json_clean(dict(prompt=prompt))
760 self.session.send(self.stdin_socket, u'input_request', content, parent,
765 self.session.send(self.stdin_socket, u'input_request', content, parent,
761 ident=ident)
766 ident=ident)
762
767
763 # Await a response.
768 # Await a response.
764 while True:
769 while True:
765 try:
770 try:
766 ident, reply = self.session.recv(self.stdin_socket, 0)
771 ident, reply = self.session.recv(self.stdin_socket, 0)
767 except Exception:
772 except Exception:
768 self.log.warn("Invalid Message:", exc_info=True)
773 self.log.warn("Invalid Message:", exc_info=True)
769 except KeyboardInterrupt:
774 except KeyboardInterrupt:
770 # re-raise KeyboardInterrupt, to truncate traceback
775 # re-raise KeyboardInterrupt, to truncate traceback
771 raise KeyboardInterrupt
776 raise KeyboardInterrupt
772 else:
777 else:
773 break
778 break
774 try:
779 try:
775 value = py3compat.unicode_to_str(reply['content']['value'])
780 value = py3compat.unicode_to_str(reply['content']['value'])
776 except:
781 except:
777 self.log.error("Got bad raw_input reply: ")
782 self.log.error("Got bad raw_input reply: ")
778 self.log.error("%s", parent)
783 self.log.error("%s", parent)
779 value = ''
784 value = ''
780 if value == '\x04':
785 if value == '\x04':
781 # EOF
786 # EOF
782 raise EOFError
787 raise EOFError
783 return value
788 return value
784
789
785 def _complete(self, msg):
790 def _complete(self, msg):
786 c = msg['content']
791 c = msg['content']
787 try:
792 try:
788 cpos = int(c['cursor_pos'])
793 cpos = int(c['cursor_pos'])
789 except:
794 except:
790 # If we don't get something that we can convert to an integer, at
795 # If we don't get something that we can convert to an integer, at
791 # least attempt the completion guessing the cursor is at the end of
796 # least attempt the completion guessing the cursor is at the end of
792 # the text, if there's any, and otherwise of the line
797 # the text, if there's any, and otherwise of the line
793 cpos = len(c['text'])
798 cpos = len(c['text'])
794 if cpos==0:
799 if cpos==0:
795 cpos = len(c['line'])
800 cpos = len(c['line'])
796 return self.shell.complete(c['text'], c['line'], cpos)
801 return self.shell.complete(c['text'], c['line'], cpos)
797
802
798 def _at_shutdown(self):
803 def _at_shutdown(self):
799 """Actions taken at shutdown by the kernel, called by python's atexit.
804 """Actions taken at shutdown by the kernel, called by python's atexit.
800 """
805 """
801 # io.rprint("Kernel at_shutdown") # dbg
806 # io.rprint("Kernel at_shutdown") # dbg
802 if self._shutdown_message is not None:
807 if self._shutdown_message is not None:
803 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
808 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
804 self.log.debug("%s", self._shutdown_message)
809 self.log.debug("%s", self._shutdown_message)
805 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
810 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
806
811
@@ -1,271 +1,322 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": "Frontend-Kernel Model"
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "heading",
11 "cell_type": "heading",
12 "level": 1,
12 "level": 1,
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "The Frontend/Kernel Model"
15 "The Frontend/Kernel Model"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "markdown",
19 "cell_type": "markdown",
20 "metadata": {},
20 "metadata": {},
21 "source": [
21 "source": [
22 "The traditional IPython (`ipython`) consists of a single process that combines a terminal based UI with the process that runs the users code.\n",
22 "The traditional IPython (`ipython`) consists of a single process that combines a terminal based UI with the process that runs the users code.\n",
23 "\n",
23 "\n",
24 "While this traditional application still exists, the modern IPython consists of two processes:\n",
24 "While this traditional application still exists, the modern IPython consists of two processes:\n",
25 "\n",
25 "\n",
26 "* Kernel: this is the process that runs the users code.\n",
26 "* Kernel: this is the process that runs the users code.\n",
27 "* Frontend: this is the process that provides the user interface where the user types code and sees results.\n",
27 "* Frontend: this is the process that provides the user interface where the user types code and sees results.\n",
28 "\n",
28 "\n",
29 "IPython currently has 3 frontends:\n",
29 "IPython currently has 3 frontends:\n",
30 "\n",
30 "\n",
31 "* Terminal Console (`ipython console`)\n",
31 "* Terminal Console (`ipython console`)\n",
32 "* Qt Console (`ipython qtconsole`)\n",
32 "* Qt Console (`ipython qtconsole`)\n",
33 "* Notebook (`ipython notebook`)\n",
33 "* Notebook (`ipython notebook`)\n",
34 "\n",
34 "\n",
35 "The Kernel and Frontend communicate over a ZeroMQ/JSON based messaging protocol, which allows multiple Frontends (even of different types) to communicate with a single Kernel. This opens the door for all sorts of interesting things, such as connecting a Console or Qt Console to a Notebook's Kernel. For example, you may want to connect a Qt console to your Notebook's Kernel and use it as a help\n",
35 "The Kernel and Frontend communicate over a ZeroMQ/JSON based messaging protocol, which allows multiple Frontends (even of different types) to communicate with a single Kernel. This opens the door for all sorts of interesting things, such as connecting a Console or Qt Console to a Notebook's Kernel. For example, you may want to connect a Qt console to your Notebook's Kernel and use it as a help\n",
36 "browser, calling `??` on objects in the Qt console (whose pager is more flexible than the\n",
36 "browser, calling `??` on objects in the Qt console (whose pager is more flexible than the\n",
37 "one in the notebook). \n",
37 "one in the notebook). \n",
38 "\n",
38 "\n",
39 "This Notebook describes how you would connect another Frontend to a Kernel that is associated with a Notebook."
39 "This Notebook describes how you would connect another Frontend to a Kernel that is associated with a Notebook."
40 ]
40 ]
41 },
41 },
42 {
42 {
43 "cell_type": "heading",
43 "cell_type": "heading",
44 "level": 2,
44 "level": 2,
45 "metadata": {},
45 "metadata": {},
46 "source": [
46 "source": [
47 "Manual connection"
47 "Manual connection"
48 ]
48 ]
49 },
49 },
50 {
50 {
51 "cell_type": "markdown",
51 "cell_type": "markdown",
52 "metadata": {},
52 "metadata": {},
53 "source": [
53 "source": [
54 "To connect another Frontend to a Kernel manually, you first need to find out the connection information for the Kernel using the `%connect_info` magic:"
54 "To connect another Frontend to a Kernel manually, you first need to find out the connection information for the Kernel using the `%connect_info` magic:"
55 ]
55 ]
56 },
56 },
57 {
57 {
58 "cell_type": "code",
58 "cell_type": "code",
59 "collapsed": false,
59 "collapsed": false,
60 "input": [
60 "input": [
61 "%connect_info"
61 "%connect_info"
62 ],
62 ],
63 "language": "python",
63 "language": "python",
64 "metadata": {},
64 "metadata": {},
65 "outputs": [
65 "outputs": [
66 {
66 {
67 "output_type": "stream",
67 "output_type": "stream",
68 "stream": "stdout",
68 "stream": "stdout",
69 "text": [
69 "text": [
70 "{\n",
70 "{\n",
71 " \"stdin_port\": 52858, \n",
71 " \"stdin_port\": 52858, \n",
72 " \"ip\": \"127.0.0.1\", \n",
72 " \"ip\": \"127.0.0.1\", \n",
73 " \"hb_port\": 52859, \n",
73 " \"hb_port\": 52859, \n",
74 " \"key\": \"7efd45ca-d8a2-41b0-9cea-d9116d0fb883\", \n",
74 " \"key\": \"7efd45ca-d8a2-41b0-9cea-d9116d0fb883\", \n",
75 " \"shell_port\": 52856, \n",
75 " \"shell_port\": 52856, \n",
76 " \"iopub_port\": 52857\n",
76 " \"iopub_port\": 52857\n",
77 "}\n",
77 "}\n",
78 "\n",
78 "\n",
79 "Paste the above JSON into a file, and connect with:\n",
79 "Paste the above JSON into a file, and connect with:\n",
80 " $> ipython <app> --existing <file>\n",
80 " $> ipython <app> --existing <file>\n",
81 "or, if you are local, you can connect with just:\n",
81 "or, if you are local, you can connect with just:\n",
82 " $> ipython <app> --existing kernel-b3bac7c1-8b2c-4536-8082-8d1df24f99ac.json \n",
82 " $> ipython <app> --existing kernel-b3bac7c1-8b2c-4536-8082-8d1df24f99ac.json \n",
83 "or even just:\n",
83 "or even just:\n",
84 " $> ipython <app> --existing \n",
84 " $> ipython <app> --existing \n",
85 "if this is the most recent IPython session you have started.\n"
85 "if this is the most recent IPython session you have started.\n"
86 ]
86 ]
87 }
87 }
88 ],
88 ],
89 "prompt_number": 6
89 "prompt_number": 6
90 },
90 },
91 {
91 {
92 "cell_type": "markdown",
92 "cell_type": "markdown",
93 "metadata": {},
93 "metadata": {},
94 "source": [
94 "source": [
95 "You can see that this magic displays everything you need to connect to this Notebook's Kernel."
95 "You can see that this magic displays everything you need to connect to this Notebook's Kernel."
96 ]
96 ]
97 },
97 },
98 {
98 {
99 "cell_type": "heading",
99 "cell_type": "heading",
100 "level": 2,
100 "level": 2,
101 "metadata": {},
101 "metadata": {},
102 "source": [
102 "source": [
103 "Automatic connection using a new Qt Console"
103 "Automatic connection using a new Qt Console"
104 ]
104 ]
105 },
105 },
106 {
106 {
107 "cell_type": "markdown",
107 "cell_type": "markdown",
108 "metadata": {},
108 "metadata": {},
109 "source": [
109 "source": [
110 "You can also start a new Qt Console connected to your current Kernel by using the `%qtconsole` magic. This will detect the necessary connection\n",
110 "You can also start a new Qt Console connected to your current Kernel by using the `%qtconsole` magic. This will detect the necessary connection\n",
111 "information and start the Qt Console for you automatically."
111 "information and start the Qt Console for you automatically."
112 ]
112 ]
113 },
113 },
114 {
114 {
115 "cell_type": "code",
115 "cell_type": "code",
116 "collapsed": false,
116 "collapsed": false,
117 "input": [
117 "input": [
118 "a = 10"
118 "a = 10"
119 ],
119 ],
120 "language": "python",
120 "language": "python",
121 "metadata": {},
121 "metadata": {},
122 "outputs": [],
122 "outputs": [],
123 "prompt_number": 1
123 "prompt_number": 1
124 },
124 },
125 {
125 {
126 "cell_type": "code",
126 "cell_type": "code",
127 "collapsed": false,
127 "collapsed": false,
128 "input": [
128 "input": [
129 "%qtconsole"
129 "%qtconsole"
130 ],
130 ],
131 "language": "python",
131 "language": "python",
132 "metadata": {},
132 "metadata": {},
133 "outputs": [],
133 "outputs": [],
134 "prompt_number": 2
134 "prompt_number": 2
135 },
135 },
136 {
136 {
137 "cell_type": "heading",
137 "cell_type": "heading",
138 "level": 2,
138 "level": 2,
139 "metadata": {},
139 "metadata": {},
140 "source": [
140 "source": [
141 "The kernel's `raw_input` and `%debug`"
141 "The kernel's `raw_input` and `%debug`"
142 ]
142 ]
143 },
143 },
144 {
144 {
145 "cell_type": "markdown",
145 "cell_type": "markdown",
146 "metadata": {},
146 "metadata": {},
147 "source": [
147 "source": [
148 "The Notebook has added support for `raw_input` and `%debug`, as of 1.0."
148 "The Notebook has added support for `raw_input` and `%debug`, as of 1.0."
149 ]
149 ]
150 },
150 },
151 {
151 {
152 "cell_type": "code",
152 "cell_type": "code",
153 "collapsed": false,
153 "collapsed": false,
154 "input": [
154 "input": [
155 "# Python 3 compat\n",
156 "try:\n",
157 " raw_input\n",
158 "except NameError:\n",
159 " raw_input = input"
160 ],
161 "language": "python",
162 "metadata": {},
163 "outputs": [],
164 "prompt_number": 1
165 },
166 {
167 "cell_type": "code",
168 "collapsed": false,
169 "input": [
155 "name = raw_input(\"What is your name? \")\n",
170 "name = raw_input(\"What is your name? \")\n",
156 "name"
171 "name"
157 ],
172 ],
158 "language": "python",
173 "language": "python",
159 "metadata": {},
174 "metadata": {},
160 "outputs": [
175 "outputs": [
161 {
176 {
162 "name": "stdout",
177 "name": "stdout",
163 "output_type": "stream",
178 "output_type": "stream",
164 "stream": "stdout",
179 "stream": "stdout",
165 "text": [
180 "text": [
166 "What is your name? Sir Robin\n"
181 "What is your name? Sir Robin\n"
167 ]
182 ]
168 },
183 },
169 {
184 {
170 "metadata": {},
185 "metadata": {},
171 "output_type": "pyout",
186 "output_type": "pyout",
172 "prompt_number": 1,
187 "prompt_number": 2,
173 "text": [
188 "text": [
174 "u'Sir Robin'"
189 "'Sir Robin'"
175 ]
190 ]
176 }
191 }
177 ],
192 ],
178 "prompt_number": 1
193 "prompt_number": 2
194 },
195 {
196 "cell_type": "markdown",
197 "metadata": {},
198 "source": [
199 "**Python 2-only**: the eval input works as well (`input` is just `eval(raw_input(prompt))`)"
200 ]
201 },
202 {
203 "cell_type": "code",
204 "collapsed": false,
205 "input": [
206 "fingers = input(\"How many fingers? \")\n",
207 "fingers, type(fingers)"
208 ],
209 "language": "python",
210 "metadata": {},
211 "outputs": [
212 {
213 "name": "stdout",
214 "output_type": "stream",
215 "stream": "stdout",
216 "text": [
217 "How many fingers? 4\n"
218 ]
219 },
220 {
221 "metadata": {},
222 "output_type": "pyout",
223 "prompt_number": 3,
224 "text": [
225 "(4, int)"
226 ]
227 }
228 ],
229 "prompt_number": 3
179 },
230 },
180 {
231 {
181 "cell_type": "code",
232 "cell_type": "code",
182 "collapsed": false,
233 "collapsed": false,
183 "input": [
234 "input": [
184 "def div(x, y):\n",
235 "def div(x, y):\n",
185 " return x/y\n",
236 " return x/y\n",
186 "\n",
237 "\n",
187 "div(1,0)"
238 "div(1,0)"
188 ],
239 ],
189 "language": "python",
240 "language": "python",
190 "metadata": {},
241 "metadata": {},
191 "outputs": [
242 "outputs": [
192 {
243 {
193 "ename": "ZeroDivisionError",
244 "ename": "ZeroDivisionError",
194 "evalue": "integer division or modulo by zero",
245 "evalue": "integer division or modulo by zero",
195 "output_type": "pyerr",
246 "output_type": "pyerr",
196 "traceback": [
247 "traceback": [
197 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
248 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
198 "\u001b[1;32m<ipython-input-2-a5097cc0c0c5>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
249 "\u001b[1;32m<ipython-input-4-a5097cc0c0c5>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
199 "\u001b[1;32m<ipython-input-2-a5097cc0c0c5>\u001b[0m in \u001b[0;36mdiv\u001b[1;34m(x, y)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
250 "\u001b[1;32m<ipython-input-4-a5097cc0c0c5>\u001b[0m in \u001b[0;36mdiv\u001b[1;34m(x, y)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
200 "\u001b[1;31mZeroDivisionError\u001b[0m: integer division or modulo by zero"
251 "\u001b[1;31mZeroDivisionError\u001b[0m: integer division or modulo by zero"
201 ]
252 ]
202 }
253 }
203 ],
254 ],
204 "prompt_number": 2
255 "prompt_number": 4
205 },
256 },
206 {
257 {
207 "cell_type": "code",
258 "cell_type": "code",
208 "collapsed": false,
259 "collapsed": false,
209 "input": [
260 "input": [
210 "%debug"
261 "%debug"
211 ],
262 ],
212 "language": "python",
263 "language": "python",
213 "metadata": {},
264 "metadata": {},
214 "outputs": [
265 "outputs": [
215 {
266 {
216 "output_type": "stream",
267 "output_type": "stream",
217 "stream": "stdout",
268 "stream": "stdout",
218 "text": [
269 "text": [
219 "> \u001b[1;32m<ipython-input-2-a5097cc0c0c5>\u001b[0m(2)\u001b[0;36mdiv\u001b[1;34m()\u001b[0m\n",
270 "> \u001b[1;32m<ipython-input-4-a5097cc0c0c5>\u001b[0m(2)\u001b[0;36mdiv\u001b[1;34m()\u001b[0m\n",
220 "\u001b[1;32m 1 \u001b[1;33m\u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
271 "\u001b[1;32m 1 \u001b[1;33m\u001b[1;32mdef\u001b[0m \u001b[0mdiv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
221 "\u001b[0m\u001b[1;32m----> 2 \u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
272 "\u001b[0m\u001b[1;32m----> 2 \u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
222 "\u001b[0m\u001b[1;32m 3 \u001b[1;33m\u001b[1;33m\u001b[0m\u001b[0m\n",
273 "\u001b[0m\u001b[1;32m 3 \u001b[1;33m\u001b[1;33m\u001b[0m\u001b[0m\n",
223 "\u001b[0m\n"
274 "\u001b[0m\n"
224 ]
275 ]
225 },
276 },
226 {
277 {
227 "name": "stdout",
278 "name": "stdout",
228 "output_type": "stream",
279 "output_type": "stream",
229 "stream": "stdout",
280 "stream": "stdout",
230 "text": [
281 "text": [
231 "ipdb> x\n"
282 "ipdb> x\n"
232 ]
283 ]
233 },
284 },
234 {
285 {
235 "output_type": "stream",
286 "output_type": "stream",
236 "stream": "stdout",
287 "stream": "stdout",
237 "text": [
288 "text": [
238 "1\n"
289 "1\n"
239 ]
290 ]
240 },
291 },
241 {
292 {
242 "name": "stdout",
293 "name": "stdout",
243 "output_type": "stream",
294 "output_type": "stream",
244 "stream": "stdout",
295 "stream": "stdout",
245 "text": [
296 "text": [
246 "ipdb> y\n"
297 "ipdb> y\n"
247 ]
298 ]
248 },
299 },
249 {
300 {
250 "output_type": "stream",
301 "output_type": "stream",
251 "stream": "stdout",
302 "stream": "stdout",
252 "text": [
303 "text": [
253 "0\n"
304 "0\n"
254 ]
305 ]
255 },
306 },
256 {
307 {
257 "name": "stdout",
308 "name": "stdout",
258 "output_type": "stream",
309 "output_type": "stream",
259 "stream": "stdout",
310 "stream": "stdout",
260 "text": [
311 "text": [
261 "ipdb> exit\n"
312 "ipdb> exit\n"
262 ]
313 ]
263 }
314 }
264 ],
315 ],
265 "prompt_number": 3
316 "prompt_number": 5
266 }
317 }
267 ],
318 ],
268 "metadata": {}
319 "metadata": {}
269 }
320 }
270 ]
321 ]
271 } No newline at end of file
322 }
General Comments 0
You need to be logged in to leave comments. Login now